기타

Redis의 Sorted Set이 조회 횟수를 저장하는 원리 (검색 순위)

99duuk 2025. 1. 12. 15:29

Redis의 Sorted Set은 각 요소에 점수(score)라는 부가 정보를 포함해, 점수를 기준으로 정렬된 상태로 저장하는 데이터 구조이다.

조회 횟수를 저장하거나 관리할 때 이 점수를 활용할 수 있다.


Sorted Set의 기본 구조

  • Key: Sorted Set의 이름.
  • Member: 저장된 요소 (예: 특정 페이지 ID, 사용자 ID).
  • Score: 숫자 값으로, 정렬 및 계산에 사용됨.

Redis의 Sorted Set은 내부적으로 skip list라는 자료 구조를 사용하여 효율적으로 데이터를 삽입, 삭제, 조회, 정렬한다.


조회 횟수 저장 원리

  1. 조회 횟수를 점수로 사용
    • 조회된 항목(예: 페이지 ID 또는 특정 데이터의 키)을 Member로 추가한다.
    • 조회 횟수를 Score로 사용한다.
    • 예: 페이지 page1이 5번 조회되었다면, Sorted Set에 score=5, member=page1으로 저장.
  2. 조회 시 점수 증가
    Redis의 ZINCRBY 명령어를 사용하여 조회 시마다 해당 요소의 점수를 증가시킨다.
    • my_sorted_set: Sorted Set의 키
    • 1: 증가시킬 점수
    • page1: 조회된 항목(Member)
  3. ZINCRBY my_sorted_set 1 page1
  4. 점수 기준으로 정렬
    Sorted Set은 점수를 기준으로 항상 정렬된 상태를 유지한다. 가장 조회 횟수가 많은 항목은 높은 점수를 가지며, 이를 조회할 수 있다.

예제

1. 조회 횟수 저장

ZADD my_sorted_set 0 page1
ZADD my_sorted_set 0 page2
ZADD my_sorted_set 0 page3
  • page1, page2, page3를 score=0으로 추가.

2. 조회 발생 시 점수 증가

ZINCRBY my_sorted_set 1 page1
ZINCRBY my_sorted_set 2 page2
  • page1의 조회 횟수를 1 증가.
  • page2의 조회 횟수를 2 증가.

3. 조회 횟수 높은 순으로 조회

ZREVRANGE my_sorted_set 0 -1 WITHSCORES
  • 점수가 높은 순으로 모든 멤버를 반환.
  • 출력 예시:
    1) "page2"
    2) "2"
    3) "page1"
    4) "1"
    5) "page3"
    6) "0"
    

 

[ZINCRBY 명령어란?]

더보기

ZINCRBY 명령어란?

 

ZINCRBY는 Redis의 Sorted Set에서 사용되는 명령어로,

특정 멤버의 점수(score)를 증가시키는 데 사용됨.

 

이 명령은 점수를 추가적으로 더하거나 감소시키고,

결과적으로 멤버를 Sorted Set 안에서 점수에 따라 재정렬함.

 

------------------------------------------------------------------------------------------

 

ZINCRBY key increment member

 

  • key: Sorted Set의 이름.
  • increment: 점수에 더할 값 (양수 또는 음수).
  • member: 점수를 증가시킬 멤버.

 

------------------------------------------------------------------------------------------

특징

  1. 존재하지 않는 멤버 처리
    • 지정한 멤버가 존재하지 않을 경우, 멤버를 추가하고 초기 점수는 0에서 시작하여 increment를 더함.
  2. 실시간 정렬 유지
    • 점수를 업데이트한 뒤, Sorted Set은 즉시 점수에 따라 정렬된 상태를 유지.
  3. 양수와 음수 모두 지원
    • increment 값에 음수를 지정하면 점수가 감소.

 

 


장점

  1. 정렬 유지
    항상 점수에 따라 정렬된 상태를 유지하므로, 순위나 조회 횟수 상위 데이터를 효율적으로 관리할 수 있다.
  2. 빠른 조회 및 수정
    ZINCRBY나 ZREVRANGE와 같은 명령어로 데이터를 빠르게 업데이트 및 조회할 수 있다.
  3. 추가적인 메타데이터 관리
    Member에 조회와 관련된 추가 정보를 포함시킬 수도 있다 (예: 페이지 이름, 사용자 ID).

응용

  • 실시간 인기 콘텐츠 관리
    조회 수를 기준으로 실시간 인기 콘텐츠를 제공하는 데 사용.
  • 사용자 활동 추적
    특정 사용자나 항목의 활동 빈도를 저장 및 분석.
  • 순위(Ranking) 관리
    게임 리더보드 등에서 점수를 기준으로 순위를 관리하는 데 활용.

 

 

 

지난 여름 프로젝트 했을 때 검색순위를 만들어봤었다.

 

그 때는 mysql과 elasticsearch를 logstash로 동기화시켜두고 

조회가 될 때마다 해당 doc의 count컬럼 값을 1씩 증가시키는 방식으로 만들었다.

단순히 테이블의 컬럼에 count++해놓고 그걸 동기화하는 방식이었다......

 

사실상 집계할 때만 es의 일별, 주별 같은 집계 조건을 사용했던 건데..

아무리 초마다 동기화를 붙혀두고 해도 묘하게 반영이 늦고 뒤쳐지는 느낌이 들었는데...

 

 

그때도 레디스를 좀 더 붙혀서 검색 수 집계는 레디스로 하고, 집계된 값을 es에 동기화하는 방식이었으면 좀 더 실시간으로 따박따박 붙었지 않을까...하는 생각이 든다... 

 

 

추천 구조: Redis + Elasticsearch

  1. Redis에서 검색 순위 집계 (실시간 집계 담당)
    • ZINCRBY 또는 INCR 명령어를 사용해 검색어, 문서 ID, 콘텐츠 ID 등의 조회 횟수를 실시간으로 관리.
    • Redis는 메모리 기반이므로 빠른 읽기/쓰기 속도를 제공합니다.
  2. Elasticsearch로 동기화 (검색 및 정렬 담당)
    • Redis에서 일정 주기(예: 1분, 10분, 1시간)로 집계된 데이터를 Elasticsearch에 동기화.
    • Elasticsearch는 검색, 필터링, 정렬 등 복잡한 작업을 담당하며, 사용자에게 데이터를 제공합니다.

왜 Redis와 Elasticsearch를 결합해야 할까?

1. Redis는 실시간 데이터 업데이트에 최적화

  • ZINCRBY나 INCR로 조회 수를 빠르게 업데이트 가능.
  • ES는 잦은 업데이트가 성능에 부하를 줄 수 있지만, Redis는 빈번한 조회/갱신 작업에 적합.

2. Elasticsearch는 검색과 분석에 강력

  • 복잡한 검색 쿼리, 필터링, 텍스트 검색, 정렬 등을 제공.
  • 검색 엔진으로 설계된 ES는 조회 순위 데이터를 활용해 검색 결과에 가중치를 부여하거나 복합적인 정렬 기준을 처리하는 데 적합.

3. 부하 분산 및 역할 분담

  • Redis는 빠른 업데이트조회수 집계만 처리.
  • Elasticsearch는 검색 결과 반환랭킹 계산에 집중.
  • 각 시스템의 강점을 극대화하여 성능과 확장성을 모두 확보.

구현 플로우

1. 사용자가 검색할 때

  • Redis에 조회수 증가:
    ZINCRBY search_rankings 1 "document_id"

search_rankings: Sorted Set 이름.

document_id: 검색된 문서 ID 또는 콘텐츠 ID.

 

 

2. 일정 주기마다 Redis → Elasticsearch로 동기화

  • Redis에서 조회 데이터를 가져오기:
ZRANGE search_rankings 0 -1 WITHSCORES

결과: [ "document_id_1", "10", "document_id_2", "7", ... ]

 

  • Elasticsearch로 동기화:
POST /index_name/_update/document_id_1
{
  "script": {
    "source": "ctx._source.search_count += params.increment",
    "params": {
      "increment": 10
    }
  }
}

 

3. Elasticsearch에서 검색 결과 반환

  • 검색 결과를 search_count 필드 기준으로 정렬:
GET /index_name/_search
{
  "query": {
    "match": { "content": "search_keyword" }
  },
  "sort": [
    { "search_count": "desc" }
  ]
}
더보기

장점

  1. 실시간성과 성능
    • Redis가 빠르게 데이터를 갱신하고, ES는 검색과 분석에 최적화된 역할을 수행.
  2. 확장성
    • Redis는 메모리 기반이지만 작은 집계 데이터를 유지하므로 효율적.
    • ES는 대규모 데이터를 처리할 수 있으므로 검색 처리량을 늘릴 수 있음.
  3. 데이터 일관성
    • Redis에 저장된 실시간 데이터를 주기적으로 Elasticsearch로 동기화하므로, 최신 데이터를 검색 결과에 반영 가능.
  4. 복합 정렬 가능
    • Elasticsearch는 search_count 외에도 텍스트 검색 점수, 날짜, 사용자 선호도 등을 조합하여 정렬 가능.

주의 사항 및 최적화 팁

  1. 동기화 주기 설정
    • Redis와 Elasticsearch 간 동기화 주기는 시스템 부하와 실시간성 요구 사항에 따라 조절.
    • 예: 실시간성이 중요하면 1분마다, 부하가 중요하면 10분마다.
  2. Redis 데이터 만료 설정
    • Redis의 메모리 사용량 관리를 위해 일정 기간 이후 조회 데이터를 자동 삭제하도록 TTL(Time-To-Live)을 설정.
  3. Elasticsearch의 업데이트 병합 정책 활용
    • ES에서 동기화할 때 script를 사용해 델타 값을 더하거나, 동기화된 데이터를 그대로 덮어쓰는 방식도 가능.
  4. 대규모 동기화 처리
    • Redis에서 데이터를 가져온 뒤, Elasticsearch Bulk API를 사용해 여러 문서를 한 번에 동기화하여 성능을 최적화.

'기타' 카테고리의 다른 글

Deque  (1) 2025.01.16
단상 2  (0) 2025.01.07
파이썬 import kafka (six) ModuleNotFoundError 에러  (0) 2025.01.06
쿠키 옵션  (2) 2024.12.26
Materialized Path - 계층적 데이터 표현...  (0) 2024.12.10