Redis 使用案例:快取、佇列與速率限制
您已經建立了一個在開發環境中運作良好的網頁應用程式,但隨著流量增長,您注意到回應時間變慢和資料庫超載。罪魁禍首通常是重複的昂貴操作:從資料庫取得相同的資料、同步處理任務,或允許濫用性的請求速率。Redis 是一個記憶體內資料儲存庫,為這些問題提供了優雅的解決方案。在本文中,我們將探討三個實用的 Redis 使用案例:快取、佇列和速率限制。您將透過程式碼範例學習如何實作每個模式,並了解何時應用它們。
為什麼選擇 Redis?
Redis 是一個開源、記憶體內的鍵值儲存庫,以其速度和多功能性而聞名。它支援字串、列表、集合和雜湊等資料結構,使其適合簡單快取之外的各種任務。由於它將資料保存在記憶體中,Redis 提供亞毫秒級的延遲,這對於高效能場景來說是理想的。它還提供持久化選項,因此您不會在重新啟動時遺失資料。讓我們深入探討這三個使用案例。
1. 使用 Redis 進行快取
快取是最常見的 Redis 使用案例。這個想法很簡單:將昂貴操作(如資料庫查詢或 API 呼叫)的結果儲存在 Redis 中,並在後續請求中直接提供它們。這減少了主要資料庫的負載並加快了回應時間。
如何實作快取
- 檢查快取:在存取資料庫之前,使用唯一鍵(例如
user:123)查詢 Redis 以取得資料。 - 如果找到(快取命中):立即回傳快取的資料。
- 如果未找到(快取未命中):從資料庫取得資料,將其儲存在 Redis 中並設定過期時間(TTL),然後回傳。
以下是使用 redis-py 的 Python 範例:
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)
r.setex(cache_key, 3600, json.dumps(user)) # 快取 1 小時
return user
最佳實務:選擇有意義的鍵,設定適當的 TTL 以避免過時資料,並考慮快取失效策略。對於讀取密集型工作負載,快取可以將資料庫負載減少幾個數量級。
2. 使用 Redis 的佇列
佇列將耗時的任務與請求-回應週期分離。例如,發送電子郵件、處理圖片或產生報告可以非同步完成。Redis 列表或串流非常適合實作簡單佇列。
實作基本佇列
使用 LPUSH 將任務新增到列表的左側,並使用 BRPOP 從右側阻塞並彈出。這會建立一個 FIFO 佇列。
# 生產者:新增任務
r.lpush('email_queue', json.dumps({'to': 'user@example.com', 'subject': 'Welcome'}))
# 消費者:處理任務
while True:
_, job = r.brpop('email_queue', timeout=30)
if job:
process_email(json.loads(job))
對於更進階的需求,Redis Streams 提供消費者群組、確認和可重播性,使其適合穩健的訊息處理。
3. 使用 Redis 的速率限制
速率限制保護您的 API 免受濫用並確保公平使用。Redis 的原子操作使得實作自動過期的計數器變得容易。
固定視窗速率限制
在固定視窗方法中,您允許每個時間視窗 N 個請求(例如,每個 IP 每小時 100 個請求)。使用 INCR 和 EXPIRE:
def is_allowed(ip, limit=100, window=3600):
key = f'rate:{ip}'
current = r.incr(key)
if current == 1:
r.expire(key, window)
return current