Redis 和 Redis Cluster 概念筆記

fcamel
fcamel的程式開發心得
8 min readJun 27, 2020

官網寫得簡潔又清楚,多數文件看官網即可。安裝 Redis 也很簡單,server 和 redis-cli 一包裝好,不需要用線上的 playground。推薦先看 FAQ,對 Redis 有個概念。

Redis 可以單機跑,也可以跑 cluster mode。本文若沒有特別提及,均是指兩者共同行為。

需求分析

Designing Data-Intensive Applications 提到分散式系統的需求來分析:

  • Reliable: Redis Cluster 提供 sharding 和 replicas。Redis 使用 RDB 和 AOF 備份。前者是壓縮後的 snapshot。後者是 append-only logs,盡可能備份最新資料。
  • Scalable: 對 keys 用 CRC16 產生 16384 個 hash slots,Redis Cluster 將 hash slots 和 replicas 分配給不同的 primary nodes,可以動態調整分配,服務不會受影響。
  • Maintainable: Redis Enterprise CloudAWS ElastiCache for Redis 以 serverless 的方式提供服務,不需人力維護系統。兩者記費方式不同。Redis Enterprise Cloud 是用 ops/s 或 memory size 計價;ElastiCache 用 EC2 instances 型別和數量計價。

Redis Cluster (open source 版本) 解決了前兩個需求,有指令可以調整 hash slots、replicas 和 shards 的分配。Redis Enterprise Cloud 和 AWS ElastiCache for Redis 則是幫你監控和執行必要的指令。整體來說,Redis 是很完備的分散式系統。

Redis cluster tutorial 從使用者角度說明簡要的資訊;Redis Cluster Specification 將設計細節描述得很清楚,包含搬 shard 期間發生什麼事 ,如何作 failover 等。看完後覺得「理論上」應該沒有需要擔心的事。這篇也提供許多有用的資訊。

基本概念

  • Redis 是 persistent storage,全部資料存在記憶體內,所以資料大小上限受限於記憶體。資料會週期性備份到硬碟上 (RDB) 或是將所有更新寫入 append-only logs (AOF)。因此可以提供最快的操作。
  • 預設資料不會 expire。可以用 expire 指定 expire 時間。預設是記憶滿了就不能寫入資料,設定 LRU 的模式可以決定是只刪有設 expire 的 keys 或是都刪。例如 volatile-ttl 會照 TTL 優先刪掉 TTL 最小的 key 且只會刪有設 expire 的 keys。
  • 使用 multi-data mode,提供多種常用資料結構如 sorted set、hash、geospatial、publish/subscribe events。可裝 plugin 使用其它資料結構。《Redis Data Structures for Non-Redis Users》有為入門者的介紹,講得簡單易懂。
  • 主程式在單一 thread 執行,不用擔心 race conditions。但要留意執行太慢的操作會卡住整個系統。官方文件有寫明所有操作的 time complexity,很好評估操作效率。
  • 因為記憶體操作超快,減少呼叫 Redis 的次數是效率關鍵。有提供 incr 這類操作減少 read → write。要作更多操作時,可用 lua script。
  • 提供 Lua script 作 atomic 操作。執行 Lua script 前會檢查,不適合執行的 script 會直接失敗。像是呼叫 nondeterministic 函式之後寫入資料,或是cluster mode 用到放到不同 slots 的 keys。這裡有介紹 Lua script 除錯的小技巧。要小心不要執行太費時的 lua script 卡住其它請求。

和 Memcached 比較

  • Memcached 用 multi-thread 處理請求,Redis 只有 main thread。
  • Memcached 只支援簡單的資料型別。

如果只需要簡單的資料型別,memcached 較能善用 CPU。例如 AWS EC2 的 CPU 和 memory 是同步成長的,為了用更多 memory 而租高級的型別,會浪費一堆沒在用的 CPU。

效能分析和除錯

  • redis-cli 提供很多有用的工具,例如 redis-cli monitor可以看打入 Redis 的指令,方便 debug。推薦好好地讀完 redis-cli 的文件
  • slowlog 會取出最近較慢的操作。預設會記錄 ≥ 10ms 的指令。
  • redis-benchmark 用來測效能。
  • 這篇介紹六個免費分析記憶體使用量的工具。我試了 Redis-audit,滿好用的,可以自動對 keys 分群。若有手動加入已知的分群規則,可以大幅縮短分析時間。若 keys 用 binary 而非 Unicode 表示,需要 patch code 在遇到 parsing error 的地方加上 key.scrub(‘’)

Redis Cluster

  • 提供 hash tags 的語法將相關的 keys 放到同一個 shard。例如 key “hello{world}” 會用 “world” 計算 hash slot。因此,”hello{world}” 和 “googlebye{world}” 會放在同一個 node。
  • 讓 client 記住 hash slots 和 Redis nodes 的對應,因此 client 使用單台 Redis 和 Redis Cluster 的 response time 是一樣的。
  • 沒有支援 strong consistency。對於重要的資料,可用 WAIT 強迫 N 個 replicas 同步資料後才返回。
  • 預設 replicas 會將 client 導向 primary node。可以用 readonly 向 replicas 讀資料。
  • 多數 nodes 在 2 * NODE_TIMEOUT 的時間內發覺 node A ≥ NODE_TIMEOUT 沒有回應,會對 A 作 failover。
  • 搬 shard 的期間,Redis node 會回覆 client 暫時性處理該 hash slot 的 node addree。搬完後會回覆 client 已永久性搬到的 node address。client 可用 CLUSTER SLOTS 取得最新的全部對應。

使用 sharding 可同時分散讀和寫,加上 Redis 反應很快,從效能的角度來看,可能沒有用 replicas 的必要。但從 high availability 的角度來看,用 replicas 可縮短 failover 時間,因為 Redis server 載入 RDB 需要一段時間,資料量有 100GB 時,可能會到十分鐘以上。

其它雜記

  • Redis Enterprise Cloud 提供 Redis on Flash,將 keys 和 hot values 存在 RAM,warm values 存在 Flash。可滿足 working set 不大但 dataset 很大且多數 values 不大的需求。Redis on Flash 會用額外的 threads 存取放在 flash 的資料。
  • 因為全部資料都在記憶體,需要備份時,fork child process,然後讓 child process 將全部資料寫入硬碟即可。沒有想過 isolation snapshot 這麼容易實作。
  • Episode 20: Redis Labs — Database for the Instant Experience with Ofer Bengal:這則 podcast 介紹 Redis Labs 的商業策略。command、datatype 這類功能 open source,但是 deployment、operation 要用他們的商用版。一般用戶可以安心用免費版,規模夠大時就有錢買商用版解決 scalability 的痛點。
  • Box 於 2018 說明他們如何使用 redis cluster:主要管 session data (30 days login) 和 recent files。使用 sharding + 2 replicas。replicas 只用提升 HA,讀寫都用 primary 避免 read consistency 問題。使用 AOF: appendonly + fsync per 30s。在 slave 額外使用 RDB (snapshot) 作 backup per hour。
  • 使用 key-value store 時,最好幫 keys 加上 namespace,像是 A:hello 表示是類型 A 用的 key hello。之後比較方便分析那種類型的 keys 占比較多資源,要砍 keys 也比較不用擔心砍錯。
  • 用 unlink 取代 del,避免在刪大量資料時占住 main thread。
  • Redis 砍掉 expired keys 的方法是存取到時才砍,並且定期取樣檢查。定期取樣檢查是滿有意思的設計,可以穩定地使用 CPU 資源處理過期資料。
  • Redis Best Practice: 有許多中肯實用的建議。

結語

Redis 實在太好上手了,官方文件也清楚,反而不太知道要寫什麼…。初用 Redis 最困擾我的問題是資料是否可存在記憶外?是否永久儲存?和 memcached 有什麼差別?這些都寫在前面了。

--

--