미니 프로젝트 - 스케줄러 알림 구현

Zyoon·2025년 8월 11일

미니프로젝트

목록 보기
34/35
post-thumbnail

📘스케줄러와 Redis 기반으로 한 특정 시간 알림 기능 - 저장 및 수정 기능


내용

  • 모임 관련 어플리케이션 개발 과정에서 모임 시작 시간에 맞춘 사전 알림 기능 필요
  • 모든 알림 로직은 메세지 허브를 중심으로 수집·처리하도록 구조 설계
  • 모임 시작 하루 전과 30분 전에 각각 알림을 발송하는 기능 구현 목표
  • 스케줄 관리에는 Spring Scheduler를, 상태 관리에는 Redis를 조합하여 사용
  • 하루 전 알림은 발송 여부를 Redis에 기록하여 중복 발송 방지
  • 30분 전 알림은 발송 이후 해당 데이터를 삭제하여 자원 관리 최적화

구현 계획

  • Scheduler가 일정 주기에 맞춰 예약된 알림 발송 요청을 실행
  • Provider가 발송 대상과 메시지 내용을 가공하여 Service로 전달
  • Service는 Redis를 활용해 비즈니스 로직 처리 및 Repository를 통한 데이터 저장·조회 수행
  • 발송 준비가 완료된 메시지는 Publisher를 통해 Notification 서비스로 전달

저장 방식

저장

  • 알림 예약 데이터는 ZSET과 HASH 조합으로 두 번 저장
  • uniqueKeyuserId + meetingId 조합을 사용하여 유니크성 보장
  • ZSET:
    • uniqueKeyscore(스케줄러 실행 시간, Instant 기반 Double 타입)를 저장
    • SortedMap과 유사하게 score 순으로 정렬되어 조회 효율이 높음
    • score 값은 스케줄러 기준 시간을 Instant로 설정한 뒤 Double 타입으로 변환하여 저장
  • HASH:
    • uniqueKey와 실제 알림 데이터 객체를 저장하며, 일반 Map 구조와 유사

    • 객체 생성을 위한 별도 config 생성

      //객체 전용 Template 별도 구현
      private final RedisTemplate<String, MeetingReminderMessage> redisReminderTemplate;
  • 둘 중 하나라도 저장 실패 시 롤백

저장 예시

ZSET

KeyMember (uniqueKey)Score (기준 시각, epoch milli)
reminder:meeting123:4561733970000000
reminder:meeting789:1111733971800000
reminder:meeting555:9991733973300000

HASH

KeyField (uniqueKey)Value (JSON 직렬화 예시)
reminder:meeting:data123:456{"userId":123,"meetingId":456,"title":"스터디"}
reminder:meeting:data789:111{"userId":789,"meetingId":111,"title":"회의"}
reminder:meeting:data555:999{"userId":555,"meetingId":999,"title":"점심"}

데이터 조회

공통 조회 방식

  • ZSET에서 rangeByScore 메서드를 사용해 특정 시간 범위에 해당하는 키 목록 조회
Set<V> rangeByScore(K key, double min, double max, long offset, long count);
  • 조회된 키 목록을 이용해 HASH에서 multiGet 메서드로 객체 리스트 조회
List<HV> multiGet(H key, Collection<HK> hashKeys);
  • 조회 결과인 List<Object>를 알림용 DTO 리스트로 변환하여 반환

알림 방식 - 하루 전 알림

  • 내일 하루치 알림 데이터를 조회해 오전 10시부터 오후 5시까지 순차 발송
  • 하루 약 10만 건 기준, 발송 주기별 네트워크 사용량은 동일하나 비용은 다르게 발생
  • 차이를 만드는 핵심 요인은 피크 처리량실패 시 재시도 부담
  • 이를 최소화하는 매분 발송 방식이 가장 안정적이며, 처리 비용 또한 가장 저렴
    • 한 번에 최대 250개 조회
방식하루매 시간매 분
네트워크 총량25.6MB/일 ($0.002)25.6MB/일 ($0.002)25.6MB/일 ($0.002)
컴퓨팅 피크1,666 rps ≈ 17 vCPU238 rps ≈ 3 vCPU4 rps ≈ 1 vCPU
실패/재시도 리스크높음중간낮음
예상 총비용$4.76/일$0.84/일$0.28/일

알림 방식 - 30분 전 알림

  • ZSET에서 score 기준 30분 이내 범위의 uniqueKey 목록 조회. 한 번에 최대 1000건
  • 조회 범위는 현재 시각 ~ 기준 시간이 30분 이내인 모든 데이터.
  • 이 방식으로 모임 시작 직전에 가입한 사용자도 즉시 30분 전 알림 생성 가능
  • 조회된 uniqueKey로 HASH에서 실제 알림 데이터를 가져와 발송 처리
  • 발송 완료 후 해당 uniqueKey를 ZSET과 HASH 양쪽에서 삭제하여 중복 발송 방지

데이터 처리

처리 방식 - 하루 전 알림

  • 하루 전 알림 전송 성공 시, 해당 알림을 SET에 저장해 발송 여부 마킹
  • Key 형식은 reminder:meeting:{date}, Member에는 uniqueKey+alarmType 저장
  • expire를 사용해 마킹 데이터는 2일 후 자동 삭제
  • 중복 발송 방지를 위해 발송 전 SET에 존재 여부 확인
  • 마킹 로직은 updateSentMessages 메서드에서 한 번에 처리

처리 방식 - 30분 전 알림

  • 발송 완료된 30분 전 알림의 uniqueKey 목록을 전달받아 처리
  • ZSET에서 해당 키들을 remove로 삭제해 예약 인덱스 제거
  • HASH에서도 동일 키를 delete로 삭제해 상세 데이터 제거
  • ZSET과 HASH 모두 삭제함으로써 중복 발송 방지 및 메모리 회수

처리 방식 - 좀비 데이터 삭제

  • 30분 전 알림은 발송 직후 삭제하지만, 누락된 잔여 데이터를 주기적으로 정리
  • ZSET에서 score 기준 2~8일 전 범위의 uniqueKey를 조회해 대상 선정
  • 조회된 키를 ZSET과 HASH에서 동시에 삭제하여 인덱스와 데이터 모두 제거
  • 하루 최대 maxCount 건만 처리해 Redis 부하를 최소화
  • 새벽 2~6시 저부하 시간대에 스케줄러를 실행해 서비스 영향 최소화
profile
기어 올라가는 개발

0개의 댓글