티스토리 뷰
문제 상황 & 접근
- DB 정렬 및 페이징 쿼리 기반으로 랭킹을 조회하는데 있어 성능이 좋지 못했다.
- 가장 많이 호출되는 핵심 API 이자 호출 빈도 수가 가장 높은 중요한 기능이다.
- 커서 페이징 방식으로 바꾸는 방법을 우선 고려했지만, 정렬 기준은 랭킹에 사용되는 포인트 값이었고 이 값을 통해 페이징을 수행해야 했다. 포인트 값은 계속해서 변화하기 때문에 적합하지 않을 것이라 판단했다.
- 페이지 마다 랭킹들을 보여주면 되었기에 다음과 같은 경우가 있었다.
- [오프셋 기반 페이징 시 발생 가능한 상황] 이전 페이지에 있던 회원이 이후 페이지에 보여진다면 에러 상황이 아니다. 포인트가 바뀌어 랭킹이 바뀐 상황일 뿐이다.
- [커서 기반 페이징 시 발생 가능한 상황] 실제 그룹의 전체 회원의 수와 다른 수의 회원이 랭킹에 보여지면 에러 상황이다.
- 커서 기반 페이징은 현재 시스템에 적합한 방법이 아니었다.
- 오프셋 기반 페이징은 데이터가 많아질 수록, 마지막 페이지로 이동할 수록 느려질 수 밖에 없다.
- 따라서, Redis를 통해 랭킹 시스템을 구축하고자 결정했다.
- es로도 랭킹 시스템을 구현할 수 있으나, 이미 아키텍처에 존재하는 Redis가 원하는 기능을 모두 제공하였다.
- 문자열 검색이나 다른 es를 활용할 기능도 보이지 않았기에 랭킹 만으로 도입하기에는 관리 포인트를 늘리기만 한다고 판단했다.
- 문자열 검색이나 다른 es를 활용할 기능도 보이지 않았기에 랭킹 만으로 도입하기에는 관리 포인트를 늘리기만 한다고 판단했다.
적용
기존 쿼리
- Pageable 를 통해 데이터베이스의 데이터를 정렬하여 오프셋 기반 페이징을 수행한다.
- where 절의 조건은 랭킹에 포함할 멤버인지 확인하는 정도의 조건이다.
- DB에서 순위를 매겨야 하기에 정렬은 불가피 했고, 서비스 요구사항에 의해 페이징도 필요했다.
(요구사항이 아니더라도 많은 데이터가 있는 경우 페이징이 없다면 전체조회는 위험하다.)
- Redis의 자료구조 중 하나인 Sorted Set은 member를 score 기반으로 정렬하여 저장한다.
- 순위를 매겨 조회해야하는 경우 효과적이다.
- 페이징과 같이 부분만 조회하는 기능도 제공하며, 그룹별 순위를 매겨 조회하는 기능 또한 가능하여 효과적으로 서비스 요구사항을 만족시키며 구현할 수 있을 것이라 기대했다.
Redis의 Sorted Set 활용
- redisTemplate의 ZSet에 조회를 수행한다.
다른 정보 함께 저장하는 방법에 대한 고민
- 랭킹 조회시 다른 정보들이 함께 조회되어야 했다.
- ZSet 에는 여러 정보를 함께 저장하기엔 한정적이었다. 별도의 자료구조에 나머지 정보를 저장하는게 좋을 것이라 판단했다.
- String 자료구조에 Json 형태로 변환하여 저장하였고, 조회할때 key 값을 통해 읽어오도록 구현하였다.
- String 자료구조는 get으로 조회시 O(1) 의 시간복잡도로 처리 가능하기에 조회 성능을 기대하고 사용했다.
- String 자료구조가 아닌 다른 방법은?
- Hash 자료구조로 항목별로 key-value 형태를 통해 저장하는 방법을 생각해볼 수 있다.
- Json 변환과정을 거치지 않아도 된다는 장점이 있으며 일부 개별 항목에만 접근할때 효과적이다.
- 하지만, json을 dto로 변환한 이후 바로 응답 body에 사용하고 개별 항목 접근은 없었기 때문에 굳이 Hash에 요소 하나하나 저장하지 않아도 된다고 판단하여 String에 저장하기로 했다.
결론
- DB에 5만 건의 row를 삽입한 이후 부하테스트를 통해 평균 Latency를 확인하였다.
- 기존 랭킹시스템에 비해 4.58배 개선되었다.
(Before) DB Paging Query [120.44ms]
(After) Redis Sorted Set [26.26ms 4.58배 개선]
분석
- 정렬되어 저장되는 자료구조를 사용하여 DB를 통해 매번 정렬하면서 부분만 조회하는 방법보다 더 나은 성능을 보였다.
- Redis Sorted Set으로 이전하여 성능을 높일 수 있었다.
'프로젝트 탐구 > GitRank' 카테고리의 다른 글
Github API의 느린 응답 이슈 개선을 위한 스케줄링을 통한 DB 업데이트 (0) | 2024.03.25 |
---|---|
DB 중복 insert 동시성 이슈 개선을 위한 Lock 전략 수립 (0) | 2024.03.25 |