AOP로 동시성 처리 코드 분리하기
·
Spring
이 글에서는 Spring AOP를 활용해 분산 락 처리 코드를 비즈니스 로직에서 완전히 분리하는 방법을 소개한다. 동시성을 제어를 위해 Lock 인터페이스를 사용할 때, try-finally 블록과 락 관리 코드가 비즈니스 로직을 압도하는 문제를 겪게 된다. Spring의 @Transactional이 트랜잭션 관리를 단순화한 것처럼, DistributedLock Aspect를 만들어 이 문제를 해결할 것이다. 또한, Spring Cache의 검증된 패턴을 참고하여 SpEL 평가기를 만들어 @DistributedLock의 사용성을 확장해볼 것이다. Lock 인터페이스Java/Spring에서 Lock 인터페이스를 직접 사용하면 필연적으로 try-finally 블록을 작성해야 한다.에러가 발생했을 때 락을 해..
좋아요 기능으로 알아보는 비관적 락
·
Spring
이 글에서는 좋아요 기능을 구현하면서 발생하는 동시성 문제를 DB 락으로 해결하는 과정을 다룬다. 비관적 락의 동작 원리와 함께, 넥스트 키 락(Next-Key Lock)으로 인한 성능 저하 문제까지 살펴본다. 좋아요 기능 요구사항 정리다중 서버 환경에서 서버 간 동시성 제어 필요기능 명세1) 좋아요 추가사용자는 리뷰에 좋아요를 누를 수 있다한 사용자는 하나의 리뷰에 한 번만 좋아요 가능 (중복 방지)동시다발적인 요청도 안전하게 처리해야 한다2) 좋아요 취소물리적 삭제가 아닌 논리적 삭제(Soft Delete) 방식 사용취소 후 다시 좋아요를 누를 수 있다3) 좋아요 조회좋아요를 누르지 않은 상태: 비활성화 표시좋아요를 누른 상태: 활성화 표시좋아요를 취소한 상태: 비활성화 표시 엔티티 설계리뷰에 좋아요..
외부 API가 서비스를 마비시킬 뻔한 이야기: 가상스레드 도입기
·
Spring
이 글은 Network I/O로 인한 스레드 블로킹 문제를 진단하고, JDK 21의 가상 스레드(Virtual Thread)를 활용해 근본적인 해결책을 찾아가는 과정을 담고 있다. 단순히 문제를 해결하는 것을 넘어, 가상 스레드 도입 과정에서 마주친 Thread Pinning과 Overwhelming 같은 예상치 못한 도전들과 그 해결책까지 상세히 다룬다. 스레드 풀이 왜 고갈되었을까?월요일 오전 10시, 커피를 마시며 한 주를 시작하려는 순간 슬랙에서 지연시간 알림이 오기 시작한다.급하게 모니터링 대시보드를 확인해본다.잔여 스레드 수: 0왜 스레드 풀이 고갈되었을까?마케팅 팀과 협업해 만든 서버 사이드 이벤트 추적(Meta Conversion API 연동)의 영향이었다.데이터를 수집하기 위해 사용자의..
UPDATE 한 줄로 끝내는 동시성 문제
·
Spring
선착순 이벤트 시스템을 설계한다고 가정해보자. 요구사항은 아래와 같다.요구사항:매일 제한된 수량의 무료 체험 제공선착순 N명 정확히 선정1명만 1개만 주문 가능동시 요청 처리 필수일별 재고 수량 기록 필요단일 데이터베이스 시스템, 여러 개의 서버 컨테이너가장 중요한 것은 동시성 제어이다.100개의 재고가 있을 때 동시에 1,000명이 요청하면 어떻게 정확히 100명에게만 제공할 수 있을까? 이때 일반적으로 제시되는 해결책들은 아래와 같다.비관적 락(SELECT FOR UPDATE)낙관적 락(JPA @Version)데이터베이스 네임드 락Redis 분산 락하지만 단일 데이터베이스 환경에서 분산 락은 오버엔지니어링일 수 있고, 낙관적 락은 재시도 로직이 복잡하며, 비관적 락은 대기 시간이 길어질 수 있다.이 ..
실무에서 @Transactional을 제거했더니 성능이 2배 향상된 이유
·
Spring
Spring에서 @Transactional(readOnly = true)는 DirtyChecking 모드를 Manual 모드로 바꿔줘 성능 최적화를 위해 사용된다고 알려져 있지만, 오히려 불필요한 JDBC 호출로 인해 성능이 저하될 수 있다. 이 글은 Elastic APM을 통해 확인한 실제 호출 로그를 바탕으로 readOnly 트랜잭션이 성능에 어떤 영향을 주는지 분석하고, 실무적으로 더 나은 대안을 제시한다. 아는 사람만 아는 @Transactional의 비밀다음 API는 @Transactional(readOnly = true)로 선언된 Service 메소드를 호출한다. Elastic APM을 통해 추적한 결과, 해당 API는 단 2개의 SELECT 쿼리만 실행함에도 불구하고, 여러 번 JDBC 호출..
당신의 메모리는 안녕하십니까?
·
Spring
당신의 애플리케이션은 안전한가요?"혹시 서비스 운영 중 아무런 이상이 없어 보이던 시스템이 갑자기 느려지고, 응답 시간이 증가하며, 결국 장애로 이어진 경험이 있지는 않나요? 우리가 흔히 간과하는 작은 코드 한 줄이 애플리케이션 성능 저하와 서버 장애를 초래할 수 있다는 사실, 알고 계셨나요?" 이런 문제는 대부분 메모리 관리의 작은 실수에서 시작된다. 애플리케이션이 실행되는 동안 메모리는 끊임없이 할당되고 해제된다. 특히 Java의 JVM 메모리 관리 방식을 제대로 이해하지 못하면, 시스템 성능 저하와 장애를 초래하는 메모리 누수(memory leak)가 발생하여 시스템 성능이 점점 저하될 수 있다.위 그래프는 JVM 메모리 사용량을 보여준다. 특정 시점에 메모리 사용량이 급격히 증가하고 있다. 많은 ..