
고성능 댓글 시스템이 필요할 때, 우리는 흔히 Redis 캐싱, Kafka 비동기 처리, 그리고 DB 인덱싱 같은 기술을 떠올립니다.
하지만 이것들을 어떻게 설계 수준에서 결합하느냐에 따라 아키텍처의 성능과 안정성은 완전히 달라집니다.
이번 포스팅에서는 아프리카Tv 의 실전 댓글 시스템 아키텍처를 분석하고, 오픈소스 기술 스택으로 구현하는 방법까지 정리 합니다.
단순히 따라만 하는 것이 아니라, 왜 그렇게 설계했는지도 같이 봅니다.
대규모 트래픽 환경에서 댓글 시스템은 아래 두 가지 문제에 직면하였습니다.
인기순, 최신순 댓글 정렬은 결국 DB에 부담을 줍니다.
인기 게시글 하나에 댓글 수천 개가 달리면, 매 요청마다 정렬/필터링하는 쿼리는 DB를 죽입니다.
모든 댓글이 하나의 MySQL에 몰려 있으면, 그 DB 하나가 죽는 순간 서비스도 같이 멈춥니다.
✅ 원본 데이터는 TiDB/MySQL에 저장
✅ 인기/최신 댓글 인덱스는 Redis Sorted Set
✅ 변경 사항은 Kafka로 전달, Redis 실시간 반영
✅ Redis 장애 시에도 최대한 대응 가능한 헷지 다운그레이드 전략
// Redis 인덱스 갱신 예시 (인기순 정렬)
redisTemplate.opsForZSet().add("post:123:popular", commentId, likeCount);
Set<String> ids = redisTemplate.opsForZSet()
.reverseRange("post:123:popular", 0, 9);
// 이후 댓글 본문은 별도 조회 or 캐싱된 Map에서 병합
# application.yml 일부
spring:
kafka:
consumer:
bootstrap-servers: localhost:9092
group-id: comment-sync
@KafkaListener(topics = "comment-events", groupId = "comment-sync")
public void onCommentChanged(String message) {
CommentEvent event = objectMapper.readValue(message, CommentEvent.class);
// Redis 인덱스 갱신
if (event.getType().equals("LIKE_UPDATED")) {
redisTemplate.opsForZSet().add(
"post:" + event.getPostId() + ":popular",
event.getCommentId(),
event.getLikeCount()
);
}
}
ALTER TABLE comment ADD COLUMN version INT DEFAULT 0;
@Modifying
@Query("UPDATE Comment c SET c.likeCount = :likeCount, c.version = c.version + 1 " +
"WHERE c.id = :id AND c.version = :version")
int updateLikeCount(@Param("id") Long id,
@Param("likeCount") int likeCount,
@Param("version") int version);
// Redis와 DB의 좋아요 수가 불일치할 경우 정정
void reconcileData() {
for (String postId : allPostIds()) {
Set<ZSetOperations.TypedTuple<String>> topComments =
redisTemplate.opsForZSet().reverseRangeWithScores("post:" + postId + ":popular", 0, 100);
for (var tuple : topComments) {
Long commentId = Long.valueOf(tuple.getValue());
Integer likeInRedis = tuple.getScore().intValue();
Integer likeInDB = commentRepository.findLikeCountById(commentId);
if (!Objects.equals(likeInRedis, likeInDB)) {
redisTemplate.opsForZSet().add("post:" + postId + ":popular", String.valueOf(commentId), likeInDB);
}
}
}
}
| 구성요소 | 기술 |
|---|---|
| 기본 스토리지 | TiDB / MySQL |
| 캐싱 및 인덱스 | Redis (Sorted Set) |
| 데이터 동기화 | TiCDC / Debezium + Kafka |
| API 서버 | Spring Boot |
| 정합성 조정 | XXL-Job / Quartz |
| 인프라 | Docker / Kubernetes 추천 |
이 아키텍처의 핵심은 단순히 기술을 나열한 것이 아니라고 생각합니다.
각 계층의 역할을 분리하고, 장애를 고려해 설계하며,
데이터 일관성을 실제 운영 환경에서 유지하는 방식을 다루는 것이라는것을 배웠습니다.
댓글 시스템 하나에도 수많은 트래픽과 장애 가능성이 숨어 있습니다.
단순히 빠르기만 한 것이 아니라, “어떤 상황에서도 멈추지 않는” 구조를 목표로 해야 합니다.