在 Redis 中使用 KEYS pattern 會阻塞單執行緒的伺服器,導致所有請求停滯。生產環境必須改用 SCAN 游標式迭代,並搭配 Pipeline 批次讀取,大幅降低網路往返延遲。本文提供完整可用的 Python 範本。
import redis
def scan_and_fetch(redis_url="redis://localhost:6379/0", pattern="PREFIX_*", batch_size=1000):
"""
迭代符合 pattern 的鍵,並以 pipeline 批次讀取值。
:param redis_url: Redis 連線字串
:param pattern: 鍵模式(支援 * ? [range])
:param batch_size: 每次 pipeline 累積多少鍵才執行一次
"""
r = redis.Redis.from_url(redis_url, decode_responses=True)
pipe = r.pipeline()
key_buffer = []
total_fetched = 0
# scan_iter 內部自動處理游標循環
for key in r.scan_iter(match=pattern, count=1000):
key_buffer.append(key)
pipe.get(key)
if len(key_buffer) >= batch_size:
# 執行 pipeline,取回所有值
values = pipe.execute()
for k, v in zip(key_buffer, values):
print(f"{k}: {v}") # 實際應用中可寫入檔案、推送隊列等
total_fetched += 1
# 重置
key_buffer.clear()
pipe.reset()
# 處理剩餘
if key_buffer:
values = pipe.execute()
for k, v in zip(key_buffer, values):
print(f"{k}: {v}")
total_fetched += 1
print(f"完成,共處理 {total_fetched} 個鍵")
if __name__ == "__main__":
scan_and_fetch(pattern="USER:SESSION:*", batch_size=5000)
.decode()。try/except redis.RedisError 並實作重試邏輯。redis.asyncio (Python 3.7+) 實現高併發讀取。SCAN 需遍歷所有分片,可考慮 redis-py-cluster 的 scan_iter。json.loads 開銷。原文另附 os.walk 遍歷資料夾並刪除大檔範例,這屬於不同領域,不再贅述。若需處理本地檔案,pathlib.Path.rglob (Python 3.5+) 寫法更現代:
from pathlib import Path
for file in Path("/data").rglob("*.log"):
if file.stat().st_size > 50 * 1024 * 1024:
print(f"大檔案: {file} ({file.stat().st_size/1024/1024:.1f} MB)")
# file.unlink() # 謹慎刪除
掌握 SCAN + Pipeline 模式,是操作大型 Redis 資料集的基本功,能有效避免「一條 KEYS 指令癱瘓整個服務」的災難。