카테고리 없음

[SERVER] - shared solution project : 최근 검색어 Redis - sorted set (refactoring)

Kim David 2024. 9. 11. 20:20

 

shared solution project 중 최근 검색어 구현시 Redis를 사용하면 좀 더 많은 이점이 있다고 생각하였습니다.

 

우선 redis는 메모리 기반 데이터 저장소로, 디스크 기반 데이터베이스에 비하여 훨씬 빠른 읽기와 쓰기 성능을 제공해주며, 검색어 처럼 자주 업데이트되고 빠르게 조회되어야하는 데이터를 저장하기에 적합하다고 생각하였습니다.

 

우선 최근 검색어 자체가 순서가 있는 목록이기에 단순한 key-value 저장소가 아닌 리스트, 셋, 해시 등 다양한 데이터 구조를 지원하기에 효율적으로 관리할 수 있다고 생각했습니다.

 

또한 TTL( 유효기간 ) 을 설정할 수 있어서 일정 시간이 지난 후에 데이터가 자동으로 삭제 될 수 있어서 오래된 검색어를 자동으로 제거하는데 유용하며, 메모리 사용을 최적화 수 있기에 좋다고 생각하였습니다.

 

 

기존 Queue방식

Queue는 fifo 구조를 따릅니다. ( 가장 먼저 들어온 데이터가 가장 먼저 나가는 방식. )

- 큐의 크기를 고정 할 수 있으며, 이를 초과하면 오랜 항목을 제거합니다. ( 주로 leftPush() rightPop() 을 통해 오래된 항목을 제거하는 방식으로 관리합니다. )

- 동일한 데이터가 여러번 들어올 수 있으며, 중복된 데이터도 그대로 저장됩니다. (동일한 검색어를 여러번 검색하면 계속 저장됩니다. )

 

 

새로운 Sorted Set 방식

sorted set방식은 set 처럼 중복을 허용하지 않으면서 각 요소가 score(점수)를 가지게 되는데 이 점수에 따라 자동으로 정렬되는 자료 구조입니다.

- 저장된 데이터가 점수에 따라 자동으로 저장됩니다. ( 점수는 보통 시간이나 우선순위로 부여합니다. )

- 동일한 값을 여러번 저장하려고하면, 중복을 허용하지 않고 기존 데이터를 업데이트합니다. ( 예시를 들자면 동일한 검색어를 다시 입력하게 되면 검색어가 중복 저장되는 것이 아닌 점수만 업데이트 됩니다. )

- 점수순으로 데이터를 빠르게 가져오거나 삭제할 수 있어서 효율적인 데이터 관리가 가능합니다.

 

 

기존 Queue 방식의 문제점

Redis의 Queue 방식을 사용하여 최근 검색어 기능을 구현하였습니다.

하지만 큐 방식으로 구현하면서 몇 가지 중요한 문제점들이 드러났습니다.

 

첫번째로는, 큐는 삽입된 순서대로만 데이터를 관리하기 때문에, 검색어를 시간 순서에 따라 정렬하는 기능이 부족했습니다. 이를 해결하기 위해 각 검색어에 생성 시간을 부여하고( 엔티티를 만들어 운영하였습니다. ), 별도의 엔티티와 정렬 로직을 추가해야 했습니다.

이로 인해 시스템이 불필요하게 복잡해졌습니다.

 

두번째로는, 큐 구조의 탐색 기능 부족도 문제였습니다. 큐는 데이터 삽입과 삭제에는 효율적이지만, 특정 검색어를 빠르게 찾거나 중간 데이터를 조회하는 데 있어 효율성이 떨어졌습니다. 결과적으로 검색어 관리의 유연성이 크게 제한되었습니다.

 

마지막으로는, 중복 검색어 문제가 발생했습니다. 동일한 검색어가 반복해서 입력되면 큐에 여러 번 쌓이게 되어, 중복된 검색어가 그대로 저장되는 현상이 발생했습니다. 이를 해결하기 위해 별도의 중복 체크 로직을 추가해야 했는데, 이는 불필요한 복잡성을 초래하고 성능에도 영향을 미친다고 생각했습니다.

 

이러한 문제들을 해결하기 위해, Redis의 Sorted Set 구조로 전환하는 것이 더 적합하다고 판단했습니다. Sorted Set은 검색어를 자동으로 시간 순서에 따라 정렬하고, 중복 검색어를 방지하면서도 효율적으로 데이터를 관리할 수 있기 때문에, 큐 방식보다 나은 방법이라고 생각했습니다.

 

 

code Refactoring

 

getPostSearch 메서드는 사용자가 검색어를 입력하면 해당 검색어를 저장해주고 관련 게시글을 찾아주는 메서드입니다.

redis의 저장할 키를 설정하기 위해 currentsearch + 해당 유저의 아이디로 형식을 정해주었고, sorted set은 자동으로 시간 순서에 따라 정렬되기에 현재 시간을 점수로 사용하여서 검색어를 저장해 주었습니다. ( 점수가 높을수록 나중에 검색한 항목이 되는 것입니다. )

(redisTemplate에서 제공해주는 opsZset 메서드는 redis의 sorted set 작업을 처리해주는 인터페이스를 제공해줍니다.)

 

removeRange 함수를 통하여 저장한 후 갯수가 10개가 초과하면 가장 오래된 항목을 삭제해주는 로직을 추가해주어서 최근 검색어가 10개로 제한 될 수 있게 해주었습니다.

 

 

다음으로 getRecentSearchLogs 메서드에서는 최근 검색어가 조회되는 메서드입니다.

유저의 아이디를 기반으로 redis에 저장된 검색어 리스트 키를 생성하여 최신검색어 10개를 가져오도록 하였습니다.

reverseRangeWithScores메서드를 사용하여 점수가 높은 순서대로 ( 최신순으로 검색어를 가져오기 ) 데이터를 가져오도록 하였습니다.

 

마지막으로는 Object형태로 저장된 데이터를 문자열 리스트로 변환하여 리스트로 반환해주었습니다.

 

리팩토링 후 swagger를 통하여 확인시 중복 이슈들은 모두 사라졌습니다.

redis의 sortedSet은 자동 정렬을 제공하기에, 개발시 추가적인 정렬 작업이 없어도 됐습니다.