Redis의 Sorted Set은 각 요소에 점수(score)라는 부가 정보를 포함해, 점수를 기준으로 정렬된 상태로 저장하는 데이터 구조이다.
조회 횟수를 저장하거나 관리할 때 이 점수를 활용할 수 있다.
Sorted Set의 기본 구조
- Key: Sorted Set의 이름.
- Member: 저장된 요소 (예: 특정 페이지 ID, 사용자 ID).
- Score: 숫자 값으로, 정렬 및 계산에 사용됨.
Redis의 Sorted Set은 내부적으로 skip list라는 자료 구조를 사용하여 효율적으로 데이터를 삽입, 삭제, 조회, 정렬한다.
조회 횟수 저장 원리
- 조회 횟수를 점수로 사용
- 조회된 항목(예: 페이지 ID 또는 특정 데이터의 키)을 Member로 추가한다.
- 조회 횟수를 Score로 사용한다.
- 예: 페이지 page1이 5번 조회되었다면, Sorted Set에 score=5, member=page1으로 저장.
- 조회 시 점수 증가
Redis의 ZINCRBY 명령어를 사용하여 조회 시마다 해당 요소의 점수를 증가시킨다.- my_sorted_set: Sorted Set의 키
- 1: 증가시킬 점수
- page1: 조회된 항목(Member)
- ZINCRBY my_sorted_set 1 page1
- 점수 기준으로 정렬
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: 점수를 증가시킬 멤버.
------------------------------------------------------------------------------------------
특징
- 존재하지 않는 멤버 처리
- 지정한 멤버가 존재하지 않을 경우, 멤버를 추가하고 초기 점수는 0에서 시작하여 increment를 더함.
- 실시간 정렬 유지
- 점수를 업데이트한 뒤, Sorted Set은 즉시 점수에 따라 정렬된 상태를 유지.
- 양수와 음수 모두 지원
- increment 값에 음수를 지정하면 점수가 감소.
장점
- 정렬 유지
항상 점수에 따라 정렬된 상태를 유지하므로, 순위나 조회 횟수 상위 데이터를 효율적으로 관리할 수 있다. - 빠른 조회 및 수정
ZINCRBY나 ZREVRANGE와 같은 명령어로 데이터를 빠르게 업데이트 및 조회할 수 있다. - 추가적인 메타데이터 관리
Member에 조회와 관련된 추가 정보를 포함시킬 수도 있다 (예: 페이지 이름, 사용자 ID).
응용
- 실시간 인기 콘텐츠 관리
조회 수를 기준으로 실시간 인기 콘텐츠를 제공하는 데 사용. - 사용자 활동 추적
특정 사용자나 항목의 활동 빈도를 저장 및 분석. - 순위(Ranking) 관리
게임 리더보드 등에서 점수를 기준으로 순위를 관리하는 데 활용.
지난 여름 프로젝트 했을 때 검색순위를 만들어봤었다.
그 때는 mysql과 elasticsearch를 logstash로 동기화시켜두고
조회가 될 때마다 해당 doc의 count컬럼 값을 1씩 증가시키는 방식으로 만들었다.
단순히 테이블의 컬럼에 count++해놓고 그걸 동기화하는 방식이었다......
사실상 집계할 때만 es의 일별, 주별 같은 집계 조건을 사용했던 건데..
아무리 초마다 동기화를 붙혀두고 해도 묘하게 반영이 늦고 뒤쳐지는 느낌이 들었는데...
그때도 레디스를 좀 더 붙혀서 검색 수 집계는 레디스로 하고, 집계된 값을 es에 동기화하는 방식이었으면 좀 더 실시간으로 따박따박 붙었지 않을까...하는 생각이 든다...
추천 구조: Redis + Elasticsearch
- Redis에서 검색 순위 집계 (실시간 집계 담당)
- ZINCRBY 또는 INCR 명령어를 사용해 검색어, 문서 ID, 콘텐츠 ID 등의 조회 횟수를 실시간으로 관리.
- Redis는 메모리 기반이므로 빠른 읽기/쓰기 속도를 제공합니다.
- 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" }
]
}
장점
- 실시간성과 성능
- Redis가 빠르게 데이터를 갱신하고, ES는 검색과 분석에 최적화된 역할을 수행.
- 확장성
- Redis는 메모리 기반이지만 작은 집계 데이터를 유지하므로 효율적.
- ES는 대규모 데이터를 처리할 수 있으므로 검색 처리량을 늘릴 수 있음.
- 데이터 일관성
- Redis에 저장된 실시간 데이터를 주기적으로 Elasticsearch로 동기화하므로, 최신 데이터를 검색 결과에 반영 가능.
- 복합 정렬 가능
- Elasticsearch는 search_count 외에도 텍스트 검색 점수, 날짜, 사용자 선호도 등을 조합하여 정렬 가능.
주의 사항 및 최적화 팁
- 동기화 주기 설정
- Redis와 Elasticsearch 간 동기화 주기는 시스템 부하와 실시간성 요구 사항에 따라 조절.
- 예: 실시간성이 중요하면 1분마다, 부하가 중요하면 10분마다.
- Redis 데이터 만료 설정
- Redis의 메모리 사용량 관리를 위해 일정 기간 이후 조회 데이터를 자동 삭제하도록 TTL(Time-To-Live)을 설정.
- Elasticsearch의 업데이트 병합 정책 활용
- ES에서 동기화할 때 script를 사용해 델타 값을 더하거나, 동기화된 데이터를 그대로 덮어쓰는 방식도 가능.
- 대규모 동기화 처리
- 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 |