자유 게시판 프로젝트를 진행함에 있어서 실시간 인기글을 구현해야 했다. 인기글 선정은 게시글의 좋아요와, 조회수, 그리고 댓글의 수를 따져가며 인기글인지 아닌지를 선정하게 되는데 여기에 있어서 Redis를 사용했다.
결정적인 이유는 자동 정렬 기능으로 인해 조회해 올 시 속도가 빠르다는 것이다. 인기글 조회는 사용자가 많이 접근하는 기능이기도 할 것이고, 그만큼 빠른 속도가 중요하기 때문에 채택하게 되었다.
인기글 선정을 RDBMS로 선정하고 저장해서 가져오게 될 경우 쿼리를 통해 조회해야 한다. 이 경우 인덱스를 활용하여 정렬과 조회 속도를 개선할 수 있겠지만, 새로운 인기글이 선정될 때마다 정렬 작업이 매번 이루어지게 되고 트래픽이 많아질 수록 DB 부하가 증가할 것이기 때문에 NoSQL DB인 Redis를 택했다.
게다가 TTL을 지원하기 때문에, 기간별로 인기글을 저장했다가 지울수도 있고, 여러가지 기능의 확장성으로 보았을 때 적합하다고 생각해서 Redis를 통해서 기능을 구현하기로 했다.
Redis SortedSet
해당 자료구조는 각 원소에 대해서 점수가 부여되고, 점수에 따라 자동으로 정렬되는 데이터 집합이다.
아래와 같은 특징을 가지기 때문에 인기글 선정에 대한 작업에 있어서 적합하다.
- 중복을 허용하지 않는다 : 중복이 발생할 경우 기존 점수만 덮어씌워진다.
- 점수 기반 자동 정렬 : 점수가 낮은 순서, 내림 차순으로 정렬되며 조회 시 정렬된 상태로 반환한다.
- 빠른 조회 성능 : 점수를 기반으로 조회할 때의 시간복잡도는 O(logN)이다.
- 범위 검색 지원 : 점수 또는 순위의 범위를 지정하여 데이터를 효율적으로 검색할 수 있는 함수를 제공한다.
데이터 삽입 (ZADD)
public void addOrUpdatePost(String key, String postId, double score) {
redisTemplate.opsForZSet().add(key, postId, score);
System.out.println("✅ " + postId + " 추가됨 (점수: " + score + ")");
}
postId를 원소로 지정하고 score를 통해 해당 key값으로 내부적으로 내림차순으로 정렬을 수행한다.
점수 증가 (ZINCRBY)
게시물의 점수를 증가시키는 방법이다.
public void incrementPostScore(String key, String postId, double increment) {
redisTemplate.opsForZSet().incrementScore(key, postId, increment);
System.out.println("🔼 " + postId + "의 점수가 " + increment + "만큼 증가했습니다.");
}
점수 변경 후에도 자동으로 정렬된다.
인기글 조회 (ZREVRANGE)
public Set<String> **getTopNPosts**(String key, long start, long end) {
return redisTemplate.opsForZSet().reverseRange(key, start, end);
}
start 0, end 9의 값을 넣게되면 상위 10개의 인기글을 꺼내오게 된다.
ZREVRANGE 명령어는 점수가 높은 순서로 반환한다.
해당 함수들과 더불어 더 많은 기능을 제공한다.
나는 해당 프로젝트에서 실시간 인기글 반영 기능을 구현해야 했기 때문에, SpringScheduler로 매 30분 마다 update 해주는 식으로 인기글을 반영하였다.
'프로젝트 이슈 및 몰랐던점 정리 > CommunityAPI' 카테고리의 다른 글
[트러블 슈팅] ⚠️ 게시글 검색 및 페이지네이션 슬로우 쿼리 (0) | 2025.04.01 |
---|---|
[학습 포인트] 💡Redis를 활용한 toggle(좋아요)기능 구현하기 (0) | 2025.03.30 |
[학습 포인트] 💡Mockito Matchers와 실제 값을 이용한 테스트의 차이 (0) | 2025.03.30 |
[학습 포인트]💡 MockMvc 컨트롤러 단위 테스트 시 인증정보 부재 (0) | 2025.03.30 |
[학습 포인트] 💡Redis 단위 테스트 작성하기 feat.ValueOperations, Operations (0) | 2025.03.30 |