Redis는 단순 키-값 저장소를 넘어 String, Hash, List, Set, Sorted Set, Bitmap, HyperLogLog, Stream, JSON 등 다양한 자료구조를 제공한다. 각 자료구조를 올바르게 활용하면 복잡한 기능을 효율적으로 구현할 수 있다.
자료구조별 사용 사례
| 자료구조 | 사용 사례 | 시간 복잡도 |
|---|
| String | 캐시, 카운터, 세션 | O(1) |
| Hash | 사용자 프로필, 설정 | O(1) 필드별 |
| List | 큐, 타임라인 | O(1) 양끝, O(N) 중간 |
| Set | 고유 방문자, 태그 | O(1) 추가/삭제 |
| Sorted Set | 랭킹, 스케줄 | O(log N) |
| HyperLogLog | 근사 카운팅 | O(1), 12KB 고정 |
| Stream | 이벤트 로그, 메시지 큐 | O(1) 추가 |
| Bitmap | 일일 활성 사용자 | O(1) 비트 연산 |
자료구조 심화 예시
python
import redis
r = redis.Redis(decode_responses=True)
# Sorted Set - 실시간 랭킹
r.zadd('game:leaderboard', {'player1': 1500, 'player2': 2300})
r.zincrby('game:leaderboard', 100, 'player1') # 점수 추가
top10 = r.zrevrange('game:leaderboard', 0, 9, withscores=True)
# Stream - 이벤트 스트리밍
stream_id = r.xadd('events:purchase', {
'user_id': '1001',
'amount': '99.99',
'product': 'laptop'
})
# 소비자 그룹
r.xgroup_create('events:purchase', 'analytics', '$', mkstream=True)
messages = r.xreadgroup('analytics', 'worker1', {'events:purchase': '>'}, count=10)
# HyperLogLog - 대규모 UV 계산 (메모리 절약)
r.pfadd('uv:2024-01-15', 'user1', 'user2', 'user3')
r.pfadd('uv:2024-01-15', 'user1') # 중복 무시
uv_count = r.pfcount('uv:2024-01-15') # ≈3 (±0.81% 오차)
# Bitmap - 일일 출석 체크
r.setbit('attendance:2024-01-15', 1001, 1) # 사용자 1001 출석
r.setbit('attendance:2024-01-15', 1002, 1)
count = r.bitcount('attendance:2024-01-15') # 출석 인원수
# 두 날 모두 출석한 사용자 (AND 연산)
r.bitop('AND', 'both_days', 'attendance:2024-01-14', 'attendance:2024-01-15')
Lua 스크립트 (원자적 연산)
lua
-- 재고 감소 원자적 처리
local key = KEYS[1]
local amount = tonumber(ARGV[1])
local stock = tonumber(redis.call('GET', key))
if stock == nil then return -1 end
if stock < amount then return 0 end
redis.call('DECRBY', key, amount)
return stock - amount
python
script = r.register_script(lua_script)
result = script(keys=['product:stock:A001'], args=[5])
관련 문서