스케쥴러를 사용한 푸시 알림과 배치 처리 기능 구현
·
Project
이전 포스팅에서는 스프링에서 스케줄링을 사용하는 방법과 개선이 필요한 부분들을 살펴봤습니다. 먼저 마일스톤에는 어떤 기능들을 스케줄링으로 제공하는지 살펴본 뒤 앞에서 학습한 내용을 적용해나간 과정을 공유해보려 합니다.푸시 알림 스케쥴러 개발마일스톤에는 사용자가 선택한 요일과 시간에 리마인드 알림을 FCM 푸시를 통해 보내줍니다.  리마인드 알림 기능은 다음과 같은 규칙을 가지고 있습니다.요일은 복수 선택이 가능하다.시간 설정은 30분 단위로 가능하다. (ex. 7:00 -> 7:30 -> 8:00)사용자는 알림을 받을지 여부를 직접 선택 가능하다.구현 시 고려사항알림의 기준이 되는 목표 테이블과 요일을 저장하는 테이블  조회에 사용되는 컬럼alarm_enabled : 알람을 보낼지 여부를 결정합니다.al..
분산락을 통한 동시성 문제 해결 예시
·
Project
기존에 진행중이던 프로젝트의 댓글 좋아요 기능을 DB 쓰기락 기반 JPA 비관적락으로 동시성을 제어했습니다. 락 매커니즘 비교 대상에서 분산락은 오버엔지니어링의 관점에서 제거했지만, 만약 도입한다면 어떤 식으로 코드를 적용할 수 있을지 경험을 공유하고자 합니다.AOP를 사용한 분산락 구현그렇다면 분산락을 코드에 어떻게 적용했는지 살펴보겠습니다. 저는 분산락 적용을 위해 AOP를 사용했습니다.@Aspect@Component@Order(Ordered.LOWEST_PRECEDENCE - 1)@RequiredArgsConstructorpublic class DistributedLockAspect { private final RedissonClient redissonClient; @Around("@an..
스케쥴러를 사용한 푸시 알림과 배치 처리 기능 구현 (이론편)
·
Project
Spring은 어노테이션을 사용해서 손쉽게 스케쥴링을 사용하도록 도와줍니다. 하지만 @Scheduler 어노테이션만 붙여서는 실제 운영 시에 문제가 발생할 수 있습니다.오늘은 어떤 문제들이 발생할 수 있는지 알아보고 이를 해결하는 방법들을 학습해보고자 합니다.ThreadPoolTaskScheduler 도입첫번째로 발생 가능한 문제 상황을 설명하기 위해 별도의 간단한 스케쥴링 예제를 가져왔습니다.@Componentpublic class SchedulerService { @Scheduled(fixedDelay = 1000) public void test1() throws InterruptedException { log.info("Scheduling 1 start : " + Thread.current..
DB 쓰기락 적용을 통한 동시성 문제 해결
·
Project
오늘은 프로젝트에 DB 쓰기락을 적용해서 동시성 문제를 해결한 경험을 공유하겠습니다.문제 상황현재 서비스에서는 댓글에 좋아요를 누를 수 있는 기능을 제공합니다. 이때 여러명의 사용자가 동시에 좋아요 버튼을 누르면 동시성 문제로 인해 갱신 손실이 발생할 수 있습니다. 문제 해결 방법 선정현재 서비스가 단일 서버로 운영된다고 생각해보겠습니다. 그렇다면 가장 간단한 해결 방법은 Java 모니터락 기반 Synchronized 키워드나, Java Lock API를 사용하는 것입니다.하지만 현재 멜리 서비스는 인스턴스 2개를 로드밸런서에 연결해서 부하를 분산하고 있기 때문에 두 서버간의 동기화가 필요합니다.그렇다면 다음으로 생각해볼 수 있는 해결 방법에는 뭐가 있을까요? 저는 JPA 기반의 비관적락&낙관적락 그리고..
캐시를 사용한 조회 성능 개선기
·
Project
서비스의 사용자가 늘어나면 트래픽의 총량이 늘어나고 DB에 저장되는 데이터의 양도 늘어납니다. 개발자 입장에서는 서비스가 잘 운영된다는 지표이므로 기쁜 일이지만, 그동안 발견하지 못했던 성능 문제들이 하나씩 발견되기도 합니다. 조회 성능을 향상시키는 방법에는 여러가지가 있습니다. 비효율적인 쿼리 개선, JPA 사용시 N+1문제 해결 그리고 인덱스 적용을 통해서도 조회 성능을 비약적으로 향상시킬 수 있습니다. 하지만 성능 문제가 발생하는 API의 특성에 따라서는 캐시라는 수단을 사용할 수도 있습니다. 이번 글에서는 서비스의 성능 문제를 해결하기 위해 캐시를 도입하고 부하 테스트를 통해 성능 개선의 정량적 지표를 도출한 과정을 공유하고자 합니다.성능 개선이 필요한 부분현재 개선 중인 프로젝트는 사용자가 장소..
동시성 이슈를 해결하기 위한 JPA 낙관적 락 사용
·
Project
서비스의 사용자가 증가하면 예상치 못한 여러 문제들이 발생할 수 있습니다. 오늘은 그중 분산 서버에서 특정 기능에 동시 접근했을때 발생할 수 있는 동시성 이슈를 알아보고 이를 해결하는 과정을 공유하고자 합니다.문제 상황Melly 서비스는 소규모 그룹 간의 추억 공유를 중시하기 때문에 그룹의 최대 인원 수를 10명으로 제한해놨습니다. 만약 현재 그룹의 인원수가 10명일때 신규 참여 요청이 들어오면 아래의 예외를 반환합니다.{ "status": 409, "code": "GROUP-005", "message": "그룹의 인원은 최대 10명 입니다.", "errors": [], "reason": null}일반적인 상황에서는 인원수를 검증하는 로직이 잘 동작할 것입니다. 하지만 분산 서..
분산 캐시 서버 Fault Tolerance 개선기
·
Project
Melly 서비스는 Redis 기반의 분산 캐시를 적용해 조회 성능을 최적화했습니다. 하지만 기존의 캐시 로직은 Standalone의 캐시 서버가 죽지 않는다는 이상적인 가정 하에서 잘 동작하는 시스템이었습니다. 이번 글에서는 Circuit Breaker와 Spring Actuator health check 설정을 통해 분산 서버 환경에서 가용성 있는 캐시 서버를 나름대로 구축해본 기록을 공유하고자 합니다.초기 문제 상황스프링은 @Cacheable 어노테이션을 사용해서 간편하게 캐시 기능을 사용할 수 있습니다. @Cacheable는 먼저 캐시를 조회한 뒤 데이터가 없다면 DB를 조회하는 Cache Aside 전략을 사용합니다. 하지만 만약 분산 캐시 서버가 장애로 인해 죽는다면 어떻게 동작할까요?  간단..