DEVELOPMENT NOTE / Modu Square
Kafka 기반 실시간 인기글
문제
매일 0시 스케줄러로 인기 점수를 계산하면 두 문제가 생김.
- 게시글·댓글·좋아요·조회수를 모두 다시 읽어야 해 데이터가 늘수록 DB 조회량과 계산 시간 증가
- 자정 이후의 반응은 다음 실행까지 반영되지 않아 최대 24시간 지연
기술 선택 이유
-
도메인 서비스의 인기글 API 직접 호출 — 제외
- 인기글 서비스의 장애나 지연이 게시글·댓글·좋아요·조회수의 쓰기 요청까지 전파
-
스케줄러로 전체 데이터 재계산 — 제외
- 전체 데이터를 반복 조회해야 하고 집계 주기 사이의 변화를 바로 반영하기 어려움
-
Kafka로 변경 사항 전달 — 채택
- 각 서비스는 변경 이벤트만 발행. 인기글 서비스가 독립적으로 집계
- 장애 중 쌓인 이벤트를 복구 뒤 다시 처리 가능
Redis 기반 실시간 집계
인기 점수 계산
private static final long LIKE_WEIGHT = 3;
private static final long COMMENT_WEIGHT = 2;
private static final long VIEW_WEIGHT = 1;
public long calculate(Long articleId) {
return likeCountRepository.read(articleId) * LIKE_WEIGHT
+ commentCountRepository.read(articleId) * COMMENT_WEIGHT
+ viewCountRepository.read(articleId) * VIEW_WEIGHT;
}
- 서비스 API를 다시 호출하지 않도록 Redis에 게시글별 최신 댓글·좋아요·조회수 저장
- 좋아요 3점, 댓글 2점, 조회수 1점으로 인기 점수 계산
인기글 Top 10 저장
public void add(Long articleId, LocalDateTime time, Long score, Duration ttl) {
redisTemplate.executePipelined((RedisCallback<?>) action -> {
StringRedisConnection conn = (StringRedisConnection) action;
String key = generateKey(time);
conn.zAdd(key, score, String.valueOf(articleId));
conn.zRemRange(key, 0, -11);
conn.expire(key, ttl.toSeconds());
return null;
});
}
- 게시글 생성일별 Sorted Set에서 점수순으로 상위 10건 유지
- 점수 저장·하위 순위 제거·TTL 설정을 Redis Pipeline 한 번으로 처리