redis全面解析(七)

redis全面解析(七)

主從複製與集群分片

主從複製

Redis支持一主多從的主從複製架構。一個Master實例負責處理所有的寫請求,Master將寫操作同步至所有Slave。

藉助Redis的主從複製,可以實現讀寫分離和高可用:

  • 實時性要求不是特別高的讀請求,可以在Slave上完成,提升效率。特別是一些週期性執行的統計任務,這些任務可能需要執行一些長耗時的Redis命令,可以專門規劃出1個或幾個Slave用於服務這些統計任務
  • 藉助Redis Sentinel可以實現高可用,當Master crash後,Redis Sentinel能夠自動將一個Slave晉升為Master,繼續提供服務

啟用主從複製非常簡單,只需要配置多個Redis實例,在作為Slave的Redis實例中配置:

slaveof 192.168.1.1 6379 #指定Master的IP和端口

當Slave啟動後,會從Master進行一次冷啟動數據同步,由Master觸發BGSAVE生成RDB文件推送給Slave進行導入,導入完成後Master再將增量數據通過Redis Protocol同步給Slave。之後主從之間的數據便一直以Redis Protocol進行同步

使用Sentinel做自動failover

Redis的主從複製功能本身只是做數據同步,並不提供監控和自動failover能力,要通過主從複製功能來實現Redis的高可用,還需要引入一個組件:Redis Sentinel

Redis Sentinel是Redis官方開發的監控組件,可以監控Redis實例的狀態,通過Master節點自動發現Slave節點,並在監測到Master節點失效時選舉出一個新的Master,並向所有Redis實例推送新的主從配置。

Redis Sentinel需要至少部署3個實例才能形成選舉關係。

關鍵配置:

sentinel monitor mymaster 127.0.0.1 6379 2 #Master實例的IP、端口,以及選舉需要的贊成票數

sentinel down-after-milliseconds mymaster 60000 #多長時間沒有響應視為Master失效

sentinel failover-timeout mymaster 180000 #兩次failover嘗試間的間隔時長

sentinel parallel-syncs mymaster 1 #如果有多個Slave,可以通過此配置指定同時從新Master進行數據同步的Slave數,避免所有Slave同時進行數據同步導致查詢服務也不可用

另外需要注意的是,Redis Sentinel實現的自動failover不是在同一個IP和端口上完成的,也就是說自動failover產生的新Master提供服務的IP和端口與之前的Master是不一樣的,所以要實現HA,還要求客戶端必須支持Sentinel,能夠與Sentinel交互獲得新Master的信息才行。

集群分片

為何要做集群分片:

  • Redis中存儲的數據量大,一臺主機的物理內存已經無法容納
  • Redis的寫請求併發量大,一個Redis實例以無法承載

當上述兩個問題出現時,就必須要對Redis進行分片了。

Redis的分片方案有很多種,例如很多Redis的客戶端都自行實現了分片功能,也有向Twemproxy這樣的以代理方式實現的Redis分片方案。然而首選的方案還應該是Redis官方在3.0版本中推出的Redis Cluster分片方案。

本文不會對Redis Cluster的具體安裝和部署細節進行介紹,重點介紹Redis Cluster帶來的好處與弊端。

Redis Cluster的能力

  • 能夠自動將數據分散在多個節點上
  • 當訪問的key不在當前分片上時,能夠自動將請求轉發至正確的分片
  • 當集群中部分節點失效時仍能提供服務

其中第三點是基於主從複製來實現的,Redis Cluster的每個數據分片都採用了主從複製的結構,原理和前文所述的主從複製完全一致,唯一的區別是省去了Redis Sentinel這一額外的組件,由Redis Cluster負責進行一個分片內部的節點監控和自動failover。

Redis Cluster分片原理

Redis Cluster中共有16384個hash slot,Redis會計算每個key的CRC16,將結果與16384取模,來決定該key存儲在哪一個hash slot中,同時需要指定Redis Cluster中每個數據分片負責的Slot數。Slot的分配在任何時間點都可以進行重新分配。

客戶端在對key進行讀寫操作時,可以連接Cluster中的任意一個分片,如果操作的key不在此分片負責的Slot範圍內,Redis Cluster會自動將請求重定向到正確的分片上。

hash tags

在基礎的分片原則上,Redis還支持hash tags功能,以hash tags要求的格式明明的key,將會確保進入同一個Slot中。例如:{uiv}user:1000和{uiv}user:1001擁有同樣的hash tag {uiv},會保存在同一個Slot中。

使用Redis Cluster時,pipelining、事務和LUA Script功能涉及的key必須在同一個數據分片上,否則將會返回錯誤。如要在Redis Cluster中使用上述功能,就必須通過hash tags來確保一個pipeline或一個事務中操作的所有key都位於同一個Slot中。

有一些客戶端(如Redisson)實現了集群化的pipelining操作,可以自動將一個pipeline裡的命令按key所在的分片進行分組,分別發到不同的分片上執行。但是Redis不支持跨分片的事務,事務和LUA Script還是必須遵循所有key在一個分片上的規則要求。

主從複製 vs 集群分片

在設計軟件架構時,要如何在主從複製和集群分片兩種部署方案中取捨呢?

從各個方面看,Redis Cluster都是優於主從複製的方案

  • Redis Cluster能夠解決單節點上數據量過大的問題
  • Redis Cluster能夠解決單節點訪問壓力過大的問題
  • Redis Cluster包含了主從複製的能力

那是不是代表Redis Cluster永遠是優於主從複製的選擇呢?

並不是。

軟件架構永遠不是越複雜越好,複雜的架構在帶來顯著好處的同時,一定也會帶來相應的弊端。採用Redis Cluster的弊端包括:

  • 維護難度增加。在使用Redis Cluster時,需要維護的Redis實例數倍增,需要監控的主機數量也相應增加,數據備份/持久化的複雜度也會增加。同時在進行分片的增減操作時,還需要進行reshard操作,遠比主從模式下增加一個Slave的複雜度要高。
  • 客戶端資源消耗增加。當客戶端使用連接池時,需要為每一個數據分片維護一個連接池,客戶端同時需要保持的連接數成倍增多,加大了客戶端本身和操作系統資源的消耗。
  • 性能優化難度增加。你可能需要在多個分片上查看Slow Log和Swap日誌才能定位性能問題。
  • 事務和LUA Script的使用成本增加。在Redis Cluster中使用事務和LUA Script特性有嚴格的限制條件,事務和Script中操作的key必須位於同一個分片上,這就使得在開發時必須對相應場景下涉及的key進行額外的規劃和規範要求。如果應用的場景中大量涉及事務和Script的使用,如何在保證這兩個功能的正常運作前提下把數據平均分到多個數據分片中就會成為難點。

所以說,在主從複製和集群分片兩個方案中做出選擇時,應該從應用軟件的功能特性、數據和訪問量級、未來發展規劃等方面綜合考慮,只在

確實有必要引入數據分片時再使用Redis Cluster。

下面是一些建議:

  1. 需要在Redis中存儲的數據有多大?未來2年內可能發展為多大?這些數據是否都需要長期保存?是否可以使用LRU算法進行非熱點數據的淘汰?綜合考慮前面幾個因素,評估出Redis需要使用的物理內存。
  2. 用於部署Redis的主機物理內存有多大?有多少可以分配給Redis使用?對比(1)中的內存需求評估,是否足夠用?
  3. Redis面臨的併發寫壓力會有多大?在不使用pipelining時,Redis的寫性能可以超過10萬次/秒(更多的benchmark可以參考 https://redis.io/topics/benchmarks )
  4. 在使用Redis時,是否會使用到pipelining和事務功能?使用的場景多不多?

綜合上面幾點考慮,如果單臺主機的可用物理內存完全足以支撐對Redis的容量需求,且Redis面臨的併發寫壓力距離Benchmark值還尚有距離,建議採用主從複製的架構,可以省去很多不必要的麻煩。同時,如果應用中大量使用pipelining和事務,也建議儘可能選擇主從複製架構,可以減少設計和開發時的複雜度。


分享到:


相關文章: