首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 更多程式設計知識

Python 遍歷 Redis 大量鍵值的最佳實踐:SCAN + Pipeline 避免阻塞

     編輯:更多程式設計知識

在 Redis 中使用 KEYS pattern 會阻塞單執行緒的伺服器,導致所有請求停滯。生產環境必須改用 SCAN 游標式迭代,並搭配 Pipeline 批次讀取,大幅降低網路往返延遲。本文提供完整可用的 Python 範本。

核心概念

  • SCAN:增量迭代,每次回傳少量鍵與下一個游標,不阻塞。
  • Pipeline:將多條指令打包一次發送,減少 RTT(Round-Trip Time)。
  • COUNT 參數:提示每次迭代掃描的鍵數量(預設 10),非精確值。

完整程式碼範本


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)

關鍵細節解析

  1. decode_responses=True:自動將 bytes 解碼為 str,避免手動 .decode()。
  2. pipe.reset():清空 pipeline 緩衝區,準備下一批。
  3. count=1000:每次 SCAN 掃描約 1000 個槽位,平衡回傳數量與伺服器 CPU。
  4. 錯誤處理:生產碼應加上 try/except redis.RedisError 並實作重試邏輯。

進階優化方向

  • 非阻塞異步:搭配 redis.asyncio (Python 3.7+) 實現高併發讀取。
  • Lua 腳本:將「掃描+讀取+刪除」封裝為原子 Lua 腳本,減少網路交互。
  • 分散式掃描:叢集模式下使用 SCAN 需遍歷所有分片,可考慮 redis-py-cluster 的 scan_iter。
  • 資料序列化:若值為 JSON/MsgPack,管線執行後再批次反序列化,避免逐個 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 指令癱瘓整個服務」的災難。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved