用Redis構建緩存集羣的最佳實踐有哪些?

Redis Cluster 如何解決數據量大、高可用和高併發問題?算法

Redis 從 3.0 版本開始,提供了官方的集羣支持,也就是 Redis Cluser。Redis Cluster 相比於單個節點的 Redis,能保存更多的數據,支持更多的併發,而且能夠作到高可用,在單個節點故障的狀況下,繼續提供服務緩存

爲了可以保存更多的數據,和 MySQL 分庫分表的方式相似,Redis Cluster 也是經過分片的方式,把數據分佈到集羣的多個節點上。架構

Redis Cluster 是如何來分片的呢?它引入了一個「槽(Slot)」的概念,這個槽就是哈希表中的哈希槽,槽是 Redis 分片的基本單位,每一個槽裏面包含一些 Key。每一個集羣的槽數是固定的 16384(16 * 1024)個,每一個 Key 落在哪一個槽中也是固定的,計算方法是:併發

HASH_SLOT = CRC16(key) mod 16384


這個算法很簡單,先計算 Key 的 CRC 值,而後把這個 CRC 以後的 Key 值直接除以 16384,餘數就是 Key 所在的槽。這個算法就是咱們上節課講過的哈希分片算法。ide

這些槽又是如何存放到具體的 Redis 節點上的呢?這個映射關係保存在集羣的每一個 Redis 節點上,集羣初始化的時候,Redis 會自動平均分配這 16384 個槽,也能夠經過命令來調整。這個分槽的方法,也是咱們上節課講到過的分片算法:查表法高併發

客戶端能夠鏈接集羣的任意一個節點來訪問集羣的數據,當客戶端請求一個 Key 的時候,被請求的那個 Redis 實例先經過上面的公式,計算出這個 Key 在哪一個槽中,而後再查詢槽和節點的映射關係,找到數據所在的真正節點,若是這個節點正好是本身,那就直接執行命令返回結果。若是數據不在當前這個節點上,那就給客戶端返回一個重定向的命令,告訴客戶端,應該去連哪一個節點上請求這個 Key 的數據。而後客戶端會再鏈接正確的節點來訪問。性能

解決分片問題以後,Redis Cluster 就能夠經過水平擴容來增長集羣的存儲容量,可是,每次往集羣增長節點的時候,須要從集羣的那些老節點中,搬運一些槽到新節點,你能夠手動指定哪些槽遷移到新節點上spa

分片能夠解決 Redis 保存海量數據的問題,而且客觀上提高了 Redis 的併發能力和查詢性能。可是並不能解決高可用的問題,每一個節點都保存了整個集羣數據的一個子集,任何一個節點宕機,都會致使這個宕機節點上的那部分數據沒法訪問設計

那 Redis Cluster 是怎麼解決高可用問題的?代理

增長從節點,作主從複製。Redis Cluster 支持給每一個分片增長一個或多個從節點,每一個從節點在鏈接到主節點上以後,會先給主節點發送一個 SYNC 命令,請求一次全量複製,也就是把主節點上所有的數據都複製到從節點上。全量複製完成以後,進入同步階段,主節點會把剛剛全量複製期間收到的命令,以及後續收到的命令持續地轉發給從節點。

最後咱們看一下,Redis Cluster 是如何應對高併發的

通常來講,Redis Cluster 進行了分片以後,每一個分片都會承接一部分併發的請求,加上 Redis 自己單節點的性能就很是高,因此大部分狀況下不須要再像 MySQL 那樣作讀寫分離來解決高併發的問題。默認狀況下,集羣的讀寫請求都是由主節點負責的,從節點只是起一個熱備的做用。固然了,Redis Cluster 也支持讀寫分離,在從節點上讀取數據。

以上就是 Redis Cluster 的基本原理,你能夠對照下圖來加深理解

圖片

Redis Cluster 總體的架構徹底就是照抄 MySQL 構建集羣的那一套東西(固然,這些設計和方法也不是 MySQL 發明的),抄做業抄的就差把名字一塊兒也抄上了

圖片

爲何 Redis Cluster 不適合超大規模集羣?

Redis Cluster 的優勢是易於使用。分片、主從複製、彈性擴容這些功能均可以作到自動化,經過簡單的部署就能夠得到一個大容量、高可靠、高可用的 Redis 集羣,而且對於應用來講,近乎因而透明的

因此,Redis Cluster 是很是適合構建中小規模 Redis 集羣,這裏的中小規模指的是,大概幾個到幾十個節點這樣規模的 Redis 集羣

可是 Redis Cluster 不太適合構建超大規模集羣,主要緣由是,它採用了去中心化的設計。剛剛咱們講了,Redis 的每一個節點上,都保存了全部槽和節點的映射關係表,客戶端能夠訪問任意一個節點,再經過重定向命令,找到數據所在的那個節點。那你有沒有想過一個問題,這個映射關係表,它是如何更新的呢?好比說,集羣加入了新節點,或者某個主節點宕機了,新的主節點被選舉出來,這些狀況下,都須要更新集羣每個節點上的映射關係表。

圖片

如何用 Redis 構建超大規模集羣?

  • Redis Cluster 不太適合用於大規模集羣,因此不少大廠,都選擇本身去搭建 Redis 集羣。這裏面,每一家的解決方案都有本身的特點,但其實整體的架構都是大同小異的。

  • 一種是基於代理的方式,在客戶端和 Redis 節點之間,還須要增長一層代理服務。這個代理服務有三個做用。

  • 第一個做用是,負責在客戶端和 Redis 節點之間轉發請求和響應。客戶端只和代理服務打交道,代理收到客戶端的請求以後,再轉發到對應的 Redis 節點上,節點返回的響應再經由代理轉發返回給客戶端。

  • 第二個做用是,負責監控集羣中全部 Redis 節點狀態,若是發現有問題節點,及時進行主從切換。第三個做用就是維護集羣的元數據,這個元數據主要就是集羣全部節點的主從信息,以及槽和節點關係映射表

圖片

用 HAProxy+Keepalived 來代理 MySQL 請求的架構是相似的,只是多了一個自動路由分片的功能而已

固然,客戶端不用每次都去查詢元數據,由於這個元數據是不怎麼變化的,客戶端能夠本身緩存元數據,這樣訪問性能基本上和單機版的 Redis 是同樣的。若是某個分片的主節點宕機了,新的主節點被選舉出來以後,更新元數據裏面的信息。對集羣的擴容操做也比較簡單,除了遷移數據的工做必需要作之外,更新一下元數據就能夠了

圖片

雖說,這個元數據服務仍然是一個單點,可是它的數據量不大,訪問量也不大,相對就比較容易實現。咱們能夠用 ZooKeeper、etcd 甚至 MySQL 都能知足要求。這個方案應該是最適合超大規模 Redis 集羣的方案了,在性能、彈性、高可用幾方面表現都很是好,缺點是整個架構比較複雜,客戶端不能通用,須要開發定製化的 Redis 客戶端,只有規模足夠大的企業才負擔得起

小結

從小到大三種構建 Redis 集羣的方式

  • 小規模的集羣建議使用官方的 Redis Cluster,在節點數量很少的狀況下,各方面表現都不錯。

  • 再大一些規模的集羣,能夠考慮使用 twemproxy 或者 Codis 這類的基於代理的集羣架構,雖然是開源方案,可是已經被不少公司在生產環境中驗證過。

  • 相比於代理方案,使用定製客戶端的方案性能更好,不少大廠採用的都是相似的架構

相關文章
相關標籤/搜索