Closed veluxer62 closed 3 years ago
graalvm
몽고 세션 정리
리드 쿼리가 증가하고 있다.
몽고디비의 업서트는 문제가 있다. -> 다큐먼트에 1개당 16M 크기 제한이 있다. -> 해결방안?
인덱스를 잘못 걸면 안건것 보다 쿼리 성능이 더 안좋아 질 수 있다.
인덱스 조건
and인경우 카디너리티가 높은 인덱스를 수행 후 나머지는 filter를 하는 방식 ex) {$and: [{a: xxx}, {b: xxx}, {c: xxx}]} createIndex(a) <- 중요 createIndex(b) createIndex(c)
or인 경우 걸려있는 모든 인덱스를 태운다. ex) {$and: [{a: xxx}, {b: xxx}, {c: xxx}]} createIndex(a) <- 중요 createIndex(b) <- 중요 createIndex(c) <- 중요
순정렬 인덱스와 역정렬 인덱스를 2개 만들 필요가 없음. 하나만 만들어도 동일한 성능을 보임
E-S-Rule
위와 같은 순서로 인덱스를 주면 성능적으로 좋다.
Atlias 에서 차트라는 기능이 있는데 데이터 시각화 및 데이터셋을 csv나 json으로 export 할 수 있다.
몽고 노드에는 세컨더리 분석용 노드가 있다.
Aggregation 제한조건
메모리 제약이 있다.
aggregate({$match}, {$addFields}, {$project}) 이런 식으로 하면 문제 없음
blocking sort
인덱스 생성 방법
write conflict 케이스
ChangeStream
Aggregation 시 주의
aggregate( {$match}, <- 첫번째 match절만 index를 탄다 {$addFields}, {$project}, {$match} )
4.4버전부터는 모든 스테이지에서 plan을 볼 수 있다. 하지만 현재는 안됨(소요시간, 다큐먼트리턴갯수)
쓸모없는 인덱스도 성능에 영향을 미친다.
메모리
getmore를 사용하는 케이스
커넥션이 증가하는경우
cpu가 계속해서 증가하는 케이스
anti corruption layer
부패방지 계층
kotlin에서 Entity 클래스 사용 시 getter를 따로 만들지 않고 인스턴스 변수를 사설로 사용할 수 있는 방법
@Entity
class MessageHistory(
@Id
val id: UUID = UUID.randomUUID(),
phoneNumber: String,
) {
@Column
final var phoneNumber: String = phoneNumber
private set
fun test() {
phoneNumber = "ddd"
}
}
Kotlin에서 @JsonCreator
를 사용하는 경우 아래와 같이 사용하면 된다
enum class MessageResultCode(private val code: String) {
KAKAO_SUCCESS("1000"),
KAKAO_UNKNOWN_NUMBER("4001"),
KAKAO_NOT_SUPPORTED_NUMBER("4002"),
KAKAO_ERROR("9999"),
LMS_SUCCESS("R000"),
LMS_UNKNOWN_NUMBER("R500"),
LMS_BLOCKED_NUMBER("R501"),
LMS_ERROR("R502");
companion object {
@JsonCreator
@JvmStatic
fun fromCode(code: String): MessageResultCode {
return values().first { it.code == code }
}
}
}
Kotlin JPA 사용시 Entity의 setter를 외부에서 사용하지 못하도록 하는 방법에 대한 고민
https://multifrontgarden.tistory.com/272
JPA가 내부적으로 Entity의 proxy를 생성하여 Entity를 상속하여 사용하는 것처럼 보임 그래서 private setter인 경우 오류가 발생함
protected setter를 사용하는 경우 final 키워드를 사용하지 않아도 됨
Entity는 기본적으로 mutable 변수를 써야하므로 val를 쓰는것은 추천하지 않음
고민 결과 최선의 코드
@Entity
class MessageHistory(
promotionId: UUID,
phoneNumber: String,
content: String,
) {
@Id
var id: UUID = UUID.randomUUID()
protected set
@Column(nullable = false)
var promotionId = promotionId
protected set
@Column(nullable = false)
var createdAt: ZonedDateTime = ZonedDateTime.now()
protected set
@Column
@Enumerated(STRING)
var provider: Provider? = null
protected set
@Column(nullable = false)
@Enumerated(STRING)
var status = REQUESTED
protected set
@Column(nullable = false)
var phoneNumber = phoneNumber
protected set
@Column(length = 4000)
var content = content
protected set
@Column
var sentAt: ZonedDateTime? = null
protected set
@Column
var responseAt: ZonedDateTime? = null
protected set
@Column
@Enumerated(STRING)
var resultCode: MessageResultCode? = null
protected set
fun changeStatusToSend(provider: Provider) {
if (status != REQUESTED) {
throw DomainException("이미 전송된 메시지 이력은 전송상태로 변경할 수 없습니다.")
}
this.provider = provider
this.status = SENT
this.sentAt = ZonedDateTime.now()
}
fun putResponseResult(code: MessageResultCode) {
if (status != SENT) {
throw DomainException("전송되지 않은 메시지는 전송결과를 저장할 수 없습니다.")
}
status = code.getHistoryStatus()
responseAt = ZonedDateTime.now()
resultCode = code
}
}
lazy loading을 쓰고자 한다면 gradle에 아래와 같은 설정을 넣어줘야 함
allOpen {
annotation("javax.persistence.Entity")
annotation("javax.persistence.MappedSuperclass")
annotation("javax.persistence.Embeddable")
}
noArg {
annotation("javax.persistence.Entity")
annotation("javax.persistence.MappedSuperclass")
annotation("javax.persistence.Embeddable")
}
jpa open-in-view
JMS Listener 에서 동시성 처리하려면 아래와 같이 하면됨
@JmsListener(destination = MESSAGE_SEND_REQUEST, concurrency = "3-10")
Kafka topic convention
https://devshawn.com/blog/apache-kafka-topic-naming-conventions/
대학 수학 지식 관련 PDF
Jackson
enum 소문자로 표시할때
enum class Provider {
KAKAO,
LMS;
@JsonValue
fun getKey() = this.name.toLowerCase()
}
JPA EntityGraph 이슈
interface DocumentRepository : JpaRepository<Document, Long> {
@EntityGraph(attributePaths = ["approvalLines"])
fun findByDrafter(drafter: String): List<Document>
fun findByApprovalLinesAssignment(assignment: String): List<Document>
@EntityGraph(attributePaths = ["approvalLines"])
fun findByDrafterOrApprovalLinesAssignment(drafter: String, assignment: String): List<Document>
}
인터페이스 구현체로 빈을 주입하는 경우 java dynamic proxy가 생긴다 클래스를 직접 주입하면 CGLIB이 동작한다.
CGLIB이 성능적으로 뛰어나다 그이유는 컴파일 단계에서 프록시 파일을 생성하기 때문이다.
만약 인터페이스 구현체도 CGLIB을 사용하도록 하려면
@EnableAspectJAutoProxy(proxyTargetClass = true)
을 사용하자
근데 설정없이 인터페이스로 주입해보니 CGLIB으로 프록시가 생성되네???
SCTP
https://developers.redhat.com/blog/2018/01/03/sctp-stream-schedulers/