본문 바로가기

반응형

Spring

(19)
공연 예매 시 Proxy를 사용해 DB 부하 줄이기 개요현재 공연 좌석을 예매할 시 락의 적용 없이 DB에 바로 저장시도 하도록 되어있습니다.공연 좌석 예매는 공연 날짜, 좌석에 따라 결정되며, 이 두가지 조건에 대해 Unique Constraint가 걸려있어 중복 예매를 방지하지만, 바로 Database에 많은 INSERT Query를 날리는 것은 많은 부하를 줄 수 있다고 판단했습니다.@Entity@Table( name = "carts", uniqueConstraints = [UniqueConstraint( name = "ux_seat_uid_date_uid", columnNames = ["seat_id", "performance_datetime_id"] )])class Cart( //...}따라서 Redis로..
공연 정보 조회 API 쿼리 분석하고 개선하기 개요티케팅 어플리케이션의 개발 및 배포가 완료되어서, 이제 성능 측정을 해보려 합니다.이번에 성능 개선을 할 API는 공연 정보 API 입니다.지금 아래와 같이 Performance가 검색 조차 되지 않는데, 쿼리 분석을 하고 정상적으로 검색이 되도록 수정해보고자 합니다.[LdrxyZMp]|||-> PerformanceReader.searchPerformanceSummaryDto [LdrxyZMp]||| PerformanceReader.searchPerformanceSummaryDto [Sldi1Gc3]||| PerformanceReader.searchPerformanceSummaryDto [NztCOAr_]||| PerformanceReader.searchPerformanceSummaryDto [wnv..
Spring + Grafana, Loki, Prometheus로 모니터링 시스템 구축하기 개요Spring + ELK Stack으로 로그 모니터링 시스템을 구축하려 했지만, ElasticSearch가 서버에 너무 무거워서 정상적으로 동작하지 않았습니다. 이에 대한 대안으로 ELK 대신 Loki와 Grafana로 로그 시각화 툴을 구축하고, 추가적으로 Prometheus를 도입해 메트릭또한 수집해 보고자 합니다.먼저 Grafana, Loki, Promtail을 필요로 하는데, 각 서비스의 역할은 다음과 같습니다.Grafana: 로그 시각화Loki: 로그 데이터 저장 및 인덱싱Prometheus : Spring, MySQL, Nginx등의 매트릭 수집Grafana와 Loki는 별도의 모니터링 서버에 구축하고, Promtail은 Application 서버에 구축하려 합니다.Grafana + Loki..
비동기 환경에서 Request를 유지하려면 어떻게 해야할까? 개요Spring Web MVC 환경에서 request 마다 유지되는 값이 존재할 때, 고민해야할 점이 하나 생겼습니다. 바로 비동기 환경에서 request 마다 유지되는 값을 전달해 줄 수 있을까? 만약 잘 동작하지 않는다면 어떻게 해야할까? 에 대한 고민입니다. 상황 설명상황은 아래와 같습니다. 아래와 같이 Logging을 찍는 AOP 코드가 있다고 가정해보겠습니다.@Component@Scope(scopeName = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)class RequestId( val id :String = createId()){ companion object{ fun createId() : String{ ..
Database Unique Constraint를 활용한 중복 예약 방지 로직 구현하기 개요공연 티케팅 예매 프로젝트 진행 중, 공연의 좌석에 대해 중복된 예약을 제한해야하는 요구사항이 존재했습니다. 이를 Database의 Unique Constraint를 사용하여 구현하였는데, 어떻게 구현하였는지 공유하고자 합니다.요구사항, Entity 설명먼저 요구사항은 아래와 같습니다.로그인된 사용자는 공연의 자리를 선택하여 장바구니에 추가할 수 있습니다. 이 때, 다른 사람이 이미 예약한 좌석은 예매할 수 없습니다.다음으로 엔티티를 보겠습니다. 엔티티는 아래와 같습니다.class Cart( @Column(unique = true, updatable = false) val uid: String, @ManyToOne @JoinColumn(name = "seat_id") val..
락을 활용한 동시성 처리 개요쇼핑몰 프로젝트 개발 중, Database 락을 활용하여 동시성 처리를 해결한 사례에 대해 소개하고자 합니다.재고 감소 로직 동시성 처리하기첫번째로 소개할 사례는 비관적 락을 활용하여 재고 감소에 대한 동시성 처리를 한 로직입니다. 코드는 다음과 같습니다.private int decreaseProductStock(List productDtoList) throws CannotFindEntityException, InvalidStockQuantityException { int totalPrice = 0; for(OrderDto.OrderProductRequestInfo productOrderInfo : productDtoList){ Product product = productRe..
N + 1 쿼리 개선하고 확장성 있는 코드 만들기 개요Flab 프로젝트를 진행하던 중, 공연 상세 조회 API에서 N+1문제가 발생함을 알아차렸습니다.관련한 요구사항을 간단히 설명하자면, 먼저 공연에는 "공연 날짜" 엔티티가 1:N으로 연관을 맺고 있습니다. 각 공연 날짜에서 예매한 좌석의 수를 확인하기 위해 각 공연날짜마다 예약의 갯수를 조회해야 하는 로직이 필요했습니다.이해를 돕기 위해 Performance 상세 조회를 하기 위해 필요한 엔티티들의 관계를 도식화하면 아래와 유사한 형식이 나옵니다.관련 코드이와 관련한 코드는 아래와 같습니다.fun searchDetail(uid : String) : PerformanceDetailResponse{ val performance = performanceRepository.findByUid(uid) ..
테스트 코드 개선하기 개요Flab 티케팅 프로젝트를 진행하며 받았던 테스트 코드에 대한 피드백과 개선사항을 정리하고자 합니다.티케팅 프로젝트에서 테스트시 사용하는 프레임워크와 라이브러리는 아래와 같습니다.KotlinKotest(+ kotest-extensions-spring)mockk개선 전 UnitTest저는 모든 TestCode를 BDD형식으로 작성하고 개발하고 있었습니다. 아래는 이에 대한 예시코드로, UserService의 회원가입 로직을 검증하는 테스트입니다.given("이메일 인증 코드 검증이 완료된 사용자의 경우") { val email = "email@email.com" every { emailVerifier.checkVerified(email) } returns Unit..

반응형