본문 바로가기

Java/트러블 슈팅15

nGrinder를 사용한 성능 테스트: 비관적 락 vs 분산 락 nGrinder를 사용한 성능 테스트: 비관적 락 vs 분산 락 분산 환경에서는 비관적 락과 분산 락의 성능이 비교해보려고 한다. 비관적 락과 분산 락 비즈니스 로직 성능 테스트를 위해 두 비즈니스 로직을 똑같게 만들기 위해서 상품을 조회한 후 재고를 차감할 후 있는지 확인한 후 가능하다면 재고를 차감시킬 수 있도록 구현했다. 비관적 락과 분산 락 로직 차이 SELECT * FROM product WHERE id = #{id} SELECT * FROM product WHERE id = #{id} FOR UPDATE 가장 먼저, 상품을 조회했을 때 비관적 락은 SELECT ... FOR UPDATE를 통해서 조회한 레코드에 대해 배타락을 획득하는 반면, 분산 락은 애플리케이션 단에서 락을 획득하고 반납하기.. 2024. 1. 21.
MySQL Replication 적용하기 MySQL Replication 데이터베이스를 사용하고 운영할 때 가장 중요한 두 가지 요소는 확장성(Scalability)과 가용성(Availability)이다. 이 두 가지 요소를 위해 가장 일반적으로 사용되는 기술인 MySQL 복제는 소스 서버의 데이터를 하나 이상의 레플리카 서버로 복제하여 읽기 작업을 분산시켜 성능을 향상시키는 것을 말한다. 원본 데이터를 가진 서버를 소스(Source) 서버, 복제된 데이터를 가지는 서버를 레플리카(Replica) 서버라고 부른다. 소스 서버에서 데이터 및 스키마에 대한 변경이 최초로 발생하며, 레플리카 서버에서는 이러한 변경 내역을 소스 서버로부터 전달받아 자신이 가지고 있는 데이터에 반영함으로써 소스 서버에 저장된 데이터와 동기화시킨다. 복제 장점 복제를 통.. 2024. 1. 15.
분산 락 사용 시 상위 트랜잭션이 있으면 안되는 이유 분산 락 사용 시 상위 트랜잭션이 있으면 안되는 이유 주문 기능 중 재고 차감을 데이터 정합성을 위해 비관적 락으로 먼저 구현하고, 다음으로 Redisson을 사용하여 분산 락으로 구현하려고 했지만 주문 트랜잭션에서 상위 트랜잭션이 있는 경우에는 적용하지 못해 그 이유에 대해 작성해보고자 한다. Redisson을 사용한 분산 락 Redisson은 pub/sub 기반으로 Lock 구현을 제공한다. 채널을 하나 만들고 Lock을 점유중인 스레드가 Lock을 획득하려고 하는 스레드들에게 해제를 알려주고 안내를 받은 스레드가 Lock 획득 시도하는 방식으로 스핀락을 통해 계속해서 락을 획득할 수 있는지 요청해야 하는 Lettuce의 경우보다 부하를 덜 줄 수 있다. boolean tryLock(long wait.. 2024. 1. 7.
페이징 성능 개선: offset vs no offset vs covering index 페이징 성능 개선: offset vs no offset vs covering index 웹 서비스에서 페이징은 아주 흔하게 사용되는 기능이다. 일반적으로 페이징은 구현한다면 LIMIT ... OFFSET ...; 와 같은 패턴으로 OFFSET을 사용하는데 이는 점차 데이터가 많아짐에 따라 수십초 ~ 수분까지 조회가 느려질 수도 있다. 따라서 No offset과 Covering index를 통해서 페이징 기능을 개선하는 방법에 대해서 살펴보자. product 테이블에 대략 1,572만 건 상품 데이터가 있다. OFFSET LIMIT 쿼리는 결과에서 지정된 순서에 위치한 레코드만 가져오고자 할 때 사용된다. 위 쿼리는 다음과 같은 순서로 실행된다. ORDER BY id DESC: 일반적으로 최신에서 과거순으.. 2023. 12. 25.
synchronized vs Pessimistic Lock vs Distributed Lock synchronized vs Pessimistic Lock vs Distributed Lock DB의 무결성을 보장하기 위해서는 다양한 방법이 있다. 물론 synchronized는 적합한 방법은 아니지만 왜 적합하지 않은지에 대해 살펴보고, 그 뒤 비관적 락(Pessimistic Lock)과 분산락(Distributed Lock)을 통해 성능 비교를 해보자. 재고 차감 로직을 통한 DB 부정합 문제 살펴보기 위 ProductService는 주문 관련 비즈니스 로직 중 하나로 "상품 조회 -> 상품의 재고 차감 가능 여부 확인 -> 재고 차감"의 순서로 이루어지는 로직이다. 해당 비즈니스 로직을 통해서 어떻게 DB 부정합 문제가 발생하게 되는지 테스트 코드를 작성해보자. 위 테스트 코드는 한 번에 100개.. 2023. 12. 21.
Nginx와 WAS의 로깅 식별자(request_id) 공유하기 Nginx와 WAS의 로깅 식별자(request_id) 공유하기 현재 프로젝트의 서비스 환경은 위 그림과 같다. WAS만 사용하는 것이 아니라 Nginx와 같은 Web Server를 앞단에 두고 사용하고 있다. 따라서 Nginx 로그와 WAS 로그를 함께 봐야하는 경우가 많은데, 이때 Nginx와 WAS가 동일한 request_id를 공유하면 로그 파악이 매우 용이해진다. Nginx 설정 Nginx에서는 제공하는 변수 중 하나로 $request_id가 있다. 이 변수는 각 HTTP 요청에 대해 고유한 식별자를 생성하여 주로 로깅이나 디버깅 목적으로 사용된다. 이 변수는 ngx_http_core_module 모듈에서 제공되며 32개의 16진수 문자열로 각 HTTP 요청이 도착하면 자동으로 할당된다. Log.. 2023. 12. 17.
Blue/Green 방식으로 서비스 중단없이 배포하기 Blue/Green 방식으로 서비스 중단없이 배포하기 어플리케이션을 배포하는데 있어 Rolling 배포, Blue/Green 배포, 그리고 Canary 배포와 같은 다양한 배포 전략들이 있다. 각 전략의 특징과 장담점을 살펴보고 프로젝트에 어떤 전략을 선택할지 고민해보려고 한다. Rolling 배포 롤링 배포는 각 서버를 한 개씩 새로운 버전으로 (점진적) 배포하는 방법을 말한다. 즉, 위 그림처럼 기존 버전에서 새 버전으로 서비스를 전환하는 과정을 순차적으로 진행한다. 서비스 중인 인스턴스 하나를 로드밸런서에 라우팅하지 않도록 한 뒤 새 버전을 적용하여 다시 라우팅하는 방식으로 구성된 자원을 그대로 유지한 채로 무중단 배포가 가능하므로 관리가 편하다는 장점이 있지만 배포가 진행되는 동안 구버전과 신버전.. 2023. 12. 17.
Jenkins으로 CI/CD 구축하기 Jenkins으로 CI/CD 구축하기 다른 분들과 협업 프로젝트를 진행하면서 요구사항은 계속 바뀔 수 있기 마련이다. 하지만 폭포수 모델처럼 분석, 설계 영역에 상당한 시간이 할당되고, 해당 작업이 끝난 후에는 개발 시 어떤 추가나 수정도 허용되지 않으면서 전체 개발이 끝난 후에 통합이 진행된다면 그 결과로 수 많은 통합 이슈가 가장 마지막 단계에서 발생하는 문제가 발생할 수 있다. 따라서 현재 진행하는 이커머스 프로젝트는 충분히 잦은 요구사항이 발생할 수 있는 서비스이기 때문에 애자일처럼 빠르고 유연하며 조금씩 발전되는 소프트웨어 개발을 통해 목표를 계속 수정해나가는 방법론을 선택했다. 따라서 하나 혹은 그 이상의 기능을 구현하고 테스트, 빌드, 배포하는 것이 자주 발생하기 때문에 이러한 반복적인 개발.. 2023. 12. 9.
세션은 어느 계층에서 처리해야 할까? 세션은 어느 계층에서 처리해야 할까? 세션을 통해 사용자 관련 로그인, 로그아웃 기능을 구현하고 있을 때 현재 어떤 문제가 있는지에 대해서 살펴보고, 리팩토링해보자! 리팩토링 전 코드 먼저 리팩토링을 하기 전에 로그인은 어떻게 동작하고 있는지에 대해서 살펴보자. @MemberLoginCheck @Target(ElementType.METHOD) @Retention(value = RetentionPolicy.RUNTIME) public @interface MemberLoginCheck { } 먼저, @MemberLoginCheck 어노테이션을 생성해줬다. Controller 레이어에서 @MemberLoginCheck 어노테이션이 붙어있는 메서드는 실행 전에 로그인 검증이 일어날 수 있도록 Aspect 클래스.. 2023. 11. 30.