Redis 활용 사례: 캐싱, 큐, 속도 제한

Backend2026-10-13TryQuickToolBox

Redis를 스택에 추가했지만 단순한 키-값 저장소로만 사용하고 있나요? Redis는 캐싱, 큐잉, 속도 제한을 우아하게 해결할 수 있는 강력한 데이터 구조와 명령어를 제공합니다. 이 가이드에서는 이러한 패턴을 효과적으로 구현하는 방법을 보여줍니다.

이러한 사용 사례에 Redis를 사용하는 이유

Redis는 속도와 다양성으로 유명한 인메모리 데이터 저장소입니다. 문자열, 해시, 리스트, 세트, 정렬된 세트 등을 지원합니다. 원자적 연산과 내장 만료 기능 덕분에 캐싱, 큐, 속도 제한에 이상적입니다. 또한 모든 언어와 쉽게 통합할 수 있습니다.

Redis를 사용한 캐싱

캐싱은 가장 일반적인 Redis 사용 사례입니다. 자주 액세스하는 데이터를 Redis에 저장하여 데이터베이스 부하를 줄이고 응답 속도를 높입니다.

기본 캐시-어사이드 패턴

캐시-어사이드 패턴에서는 애플리케이션이 먼저 Redis를 확인합니다. 데이터가 없으면(캐시 미스) 데이터베이스에서 가져온 후 다음을 위해 Redis에 저장합니다.

import redis
import json

r = redis.Redis(host='localhost', port=6379, db=0)

def get_user(user_id):
    cache_key = f'user:{user_id}'
    cached = r.get(cache_key)
    if cached:
        return json.loads(cached)
    user = fetch_user_from_db(user_id)  # your DB call
    r.setex(cache_key, 3600, json.dumps(user))  # cache for 1 hour
    return user

모범 사례:

고급 캐싱 패턴

트래픽이 많은 애플리케이션의 경우 다음 패턴을 고려하세요:

Redis를 사용한 큐

Redis 리스트와 스트림은 간단한 메시지 큐를 구축하는 데 완벽합니다. 기본 작업 큐에는 리스트를, 더 복잡한 이벤트 처리에는 스트림을 사용하세요.

리스트를 사용한 간단한 작업 큐

LPUSH로 작업을 추가하고 BRPOP으로 처리합니다. BRPOP은 작업이 사용 가능할 때까지 블록되어 워커에 효율적입니다.

# Producer
r.lpush('jobs', json.dumps({'task': 'send_email', 'to': 'user@example.com'}))

# Consumer (worker)
while True:
    _, job_data = r.brpop('jobs', timeout=30)
    job = json.loads(job_data)
    process_job(job)

모범 사례:

이벤트 소싱을 위한 Redis 스트림

Redis 스트림(Redis 5.0에서 도입)은 소비자 그룹, 승인, 재생 기능을 갖춘 더 강력한 큐를 제공합니다. XADD로 이벤트를 추가하고 XREADGROUP으로 소비하세요.

# Add event
r.xadd('events', {'type': 'order_placed', 'order_id': '123'})

# Consumer group
r.xgroup_create('events', 'order_processors', id='0', mkstream=True)
while True:
    events = r.xreadgroup('order_processors', 'worker1', {'events': '>'}, count=10, block=5000)
    for event in events:
        process_event(event)
        r.xack('events', 'order_processors', event.id)

Redis를 사용한 속도 제한

속도 제한은 API를 남용으로부터 보호하고 공정한 사용을 보장합니다. Redis의 원자적 연산은 요청을 계산하는 데 이상적입니다.

고정 윈도우 속도 제한

각 사용자에 대해 카운터를 증가시키고 만료를 설정합니다. 카운트가 제한을 초과하면 요청을 차단합니다.

def is_allowed(user_id, limit=100, window=60):
    key = f'rate_limit:{user_id}'
    current = r.incr(key)
    if current == 1:
        r.expire(key, window)
    return current