探索Redis設計與實現13:Redis集羣機制及一個Redis架構演進實例

本文轉自互聯網

本系列文章將整理到我在GitHub上的《Java面試指南》倉庫,更多精彩內容請到我的倉庫裏查看

https://github.com/h2pl/Java-Tutorial

喜歡的話麻煩點下Star哈

文章首發於我的個人博客:

www.how2playlife.com

本文是微信公衆號【Java技術江湖】的《探索Redis設計與實現》其中一篇,本文部分內容來源於網絡,爲了把本文主題講得清晰透徹,也整合了很多我認爲不錯的技術博客內容,引用其中了一些比較好的博客文章,如有侵權,請聯繫作者。

該系列博文會告訴你如何從入門到進階,Redis基本的使用方法,Redis的基本數據結構,以及一些進階的使用方法,同時也需要進一步瞭解Redis的底層數據結構,再接着,還會帶來Redis主從複製、集羣、分佈式鎖等方面的相關內容,以及作爲緩存的一些使用方法和注意事項,以便讓你更完整地瞭解整個Redis相關的技術體系,形成自己的知識框架。

如果對本系列文章有什麼建議,或者是有什麼疑問的話,也可以關注公衆號【Java技術江湖】聯繫作者,歡迎你參與本系列博文的創作和修訂。

轉自http://blog.720ui.com/2016/redis_action_04_cluster/#Replication%EF%BC%88%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%EF%BC%89

下面介紹Redis的集羣方案。

Replication(主從複製)

Redis的replication機制允許slave從master那裏通過網絡傳輸拷貝到完整的數據備份,從而達到主從機制。爲了實現主從複製,我們準備三個redis服務,依次命名爲master,slave1,slave2。

配置主服務器

爲了測試效果,我們先修改主服務器的配置文件redis.conf的端口信息


1.  port 6300

配置從服務器

replication相關的配置比較簡單,只需要把下面一行加到slave的配置文件中。你只需要把ip地址和端口號改一下。


1.  slaveof 192.168.1.1  6379

我們先修改從服務器1的配置文件redis.conf的端口信息和從服務器配置。


1.  port 6301
2.  slaveof 127.0.0.1  6300

我們再修改從服務器2的配置文件redis.conf的端口信息和從服務器配置。


1.  port 6302
2.  slaveof 127.0.0.1  6300

值得注意的是,從redis2.6版本開始,slave支持只讀模式,而且是默認的。可以通過配置項slave-read-only來進行配置。
此外,如果master通過requirepass配置項設置了密碼,slave每次同步操作都需要驗證密碼,可以通過在slave的配置文件中添加以下配置項


1.  masterauth 

測試

分別啓動主服務器,從服務器,我們來驗證下主從複製。我們在主服務器寫入一條消息,然後再其他從服務器查看是否成功複製了。

Sentinel(哨兵)

主從機制,上面的方案中主服務器可能存在單點故障,萬一主服務器宕機,這是個麻煩事情,所以Redis提供了Redis-Sentinel,以此來實現主從切換的功能,類似與zookeeper。

Redis-Sentinel是Redis官方推薦的高可用性(HA)解決方案,當用Redis做master-slave的高可用方案時,假如master宕機了,Redis本身(包括它的很多客戶端)都沒有實現自動進行主備切換,而Redis-Sentinel本身也是一個獨立運行的進程,它能監控多個master-slave集羣,發現master宕機後能進行自動切換。

它的主要功能有以下幾點

  • 監控(Monitoring):不斷地檢查redis的主服務器和從服務器是否運作正常。
  • 提醒(Notification):如果發現某個redis服務器運行出現狀況,可以通過 API 向管理員或者其他應用程序發送通知。
  • 自動故障遷移(Automatic failover):能夠進行自動切換。當一個主服務器不能正常工作時,會將失效主服務器的其中一個從服務器升級爲新的主服務器,並讓失效主服務器的其他從服務器改爲複製新的主服務器; 當客戶端試圖連接失效的主服務器時, 集羣也會向客戶端返回新主服務器的地址, 使得集羣可以使用新主服務器代替失效服務器。

Redis Sentinel 兼容 Redis 2.4.16 或以上版本, 推薦使用 Redis 2.8.0 或以上的版本。

配置Sentinel

必須指定一個sentinel的配置文件sentinel.conf,如果不指定將無法啓動sentinel。首先,我們先創建一個配置文件sentinel.conf


1.  port 26379
2.  sentinel monitor mymaster 127.0.0.1  6300  2

官方典型的配置如下


1.  sentinel monitor mymaster 127.0.0.1  6379  2
2.  sentinel down-after-milliseconds mymaster 60000
3.  sentinel failover-timeout mymaster 180000
4.  sentinel parallel-syncs mymaster 1
5.   
6.  sentinel monitor resque 192.168.1.3  6380  4
7.  sentinel down-after-milliseconds resque 10000
8.  sentinel failover-timeout resque 180000
9.  sentinel parallel-syncs resque 5

配置文件只需要配置master的信息就好啦,不用配置slave的信息,因爲slave能夠被自動檢測到(master節點會有關於slave的消息)。

需要注意的是,配置文件在sentinel運行期間是會被動態修改的,例如當發生主備切換時候,配置文件中的master會被修改爲另外一個slave。這樣,之後sentinel如果重啓時,就可以根據這個配置來恢復其之前所監控的redis集羣的狀態。

接下來我們將一行一行地解釋上面的配置項:


1.  sentinel monitor mymaster 127.0.0.1  6379  2

這行配置指示 Sentinel 去監視一個名爲 mymaster 的主服務器, 這個主服務器的 IP 地址爲 127.0.0.1 , 端口號爲 6300, 而將這個主服務器判斷爲失效至少需要 2 個 Sentinel 同意,只要同意 Sentinel 的數量不達標,自動故障遷移就不會執行。

不過要注意, 無論你設置要多少個 Sentinel 同意才能判斷一個服務器失效, 一個 Sentinel 都需要獲得系統中多數(majority) Sentinel 的支持, 才能發起一次自動故障遷移, 並預留一個給定的配置紀元 (configuration Epoch ,一個配置紀元就是一個新主服務器配置的版本號)。換句話說, 在只有少數(minority) Sentinel 進程正常運作的情況下, Sentinel 是不能執行自動故障遷移的。sentinel集羣中各個sentinel也有互相通信,通過gossip協議。

除了第一行配置,我們發現剩下的配置都有一個統一的格式:


1.  sentinel     

接下來我們根據上面格式中的option_name一個一個來解釋這些配置項:

  • down-after-milliseconds 選項指定了 Sentinel 認爲服務器已經斷線所需的毫秒數。
  • parallel-syncs 選項指定了在執行故障轉移時, 最多可以有多少個從服務器同時對新的主服務器進行同步, 這個數字越小, 完成故障轉移所需的時間就越長。

啓動 Sentinel

對於 redis-sentinel 程序, 你可以用以下命令來啓動 Sentinel 系統


1.  redis-sentinel sentinel.conf

對於 redis-server 程序, 你可以用以下命令來啓動一個運行在 Sentinel 模式下的 Redis 服務器


1.  redis-server sentinel.conf --sentinel

以上兩種方式,都必須指定一個sentinel的配置文件sentinel.conf, 如果不指定將無法啓動sentinel。sentinel默認監聽26379端口,所以運行前必須確定該端口沒有被別的進程佔用。

測試

此時,我們開啓兩個Sentinel,關閉主服務器,我們來驗證下Sentinel。發現,服務器發生切換了。

當6300端口的這個服務重啓的時候,他會變成6301端口服務的slave。

Twemproxy

Twemproxy是由Twitter開源的Redis代理, Redis客戶端把請求發送到Twemproxy,Twemproxy根據路由規則發送到正確的Redis實例,最後Twemproxy把結果彙集返回給客戶端。

Twemproxy通過引入一個代理層,將多個Redis實例進行統一管理,使Redis客戶端只需要在Twemproxy上進行操作,而不需要關心後面有多少個Redis實例,從而實現了Redis集羣。

Twemproxy本身也是單點,需要用Keepalived做高可用方案。

這麼些年來,Twenproxy作爲應用範圍最廣、穩定性最高、最久經考驗的分佈式中間件,在業界廣泛使用。

但是,Twemproxy存在諸多不方便之處,最主要的是,Twemproxy無法平滑地增加Redis實例,業務量突增,需增加Redis服務器;業務量萎縮,需要減少Redis服務器。但對Twemproxy而言,基本上都很難操作。其次,沒有友好的監控管理後臺界面,不利於運維監控。

Codis

Codis解決了Twemproxy的這兩大痛點,由豌豆莢於2014年11月開源,基於Go和C開發、現已廣泛用於豌豆莢的各種Redis業務場景。

Codis 3.x 由以下組件組成:

  • Codis Server:基於 redis-2.8.21 分支開發。增加了額外的數據結構,以支持 slot 有關的操作以及數據遷移指令。具體的修改可以參考文檔 redis 的修改。
  • Codis Proxy:客戶端連接的 Redis 代理服務, 實現了 Redis 協議。 除部分命令不支持以外(不支持的命令列表),表現的和原生的 Redis 沒有區別(就像 Twemproxy)。對於同一個業務集羣而言,可以同時部署多個 codis-proxy 實例;不同 codis-proxy 之間由 codis-dashboard 保證狀態同步。
  • Codis Dashboard:集羣管理工具,支持 codis-proxy、codis-server 的添加、刪除,以及據遷移等操作。在集羣狀態發生改變時,codis-dashboard 維護集羣下所有 codis-proxy 的狀態的一致性。對於同一個業務集羣而言,同一個時刻 codis-dashboard 只能有 0個或者1個;所有對集羣的修改都必須通過 codis-dashboard 完成。
  • Codis Admin:集羣管理的命令行工具。可用於控制 codis-proxy、codis-dashboard 狀態以及訪問外部存儲。
  • Codis FE:集羣管理界面。多個集羣實例共享可以共享同一個前端展示頁面;通過配置文件管理後端 codis-dashboard 列表,配置文件可自動更新。
  • Codis HA:爲集羣提供高可用。依賴 codis-dashboard 實例,自動抓取集羣各個組件的狀態;會根據當前集羣狀態自動生成主從切換策略,並在需要時通過 codis-dashboard 完成主從切換。
  • Storage:爲集羣狀態提供外部存儲。提供 Namespace 概念,不同集羣的會按照不同 product name 進行組織;目前僅提供了 Zookeeper 和 Etcd 兩種實現,但是提供了抽象的 interface 可自行擴展。

Codis引入了Group的概念,每個Group包括1個Redis Master及一個或多個Redis Slave,這是和Twemproxy的區別之一,實現了Redis集羣的高可用。當1個Redis Master掛掉時,Codis不會自動把一個Slave提升爲Master,這涉及數據的一致性問題,Redis本身的數據同步是採用主從異步複製,當數據在Maste寫入成功時,Slave是否已讀入這個數據是沒法保證的,需要管理員在管理界面上手動把Slave提升爲Master。

Codis使用,可以參考官方文檔https://github.com/CodisLabs/codis/blob/release3.0/doc/tutorial_zh.md

Redis 3.0集羣

Redis 3.0集羣採用了P2P的模式,完全去中心化。支持多節點數據集自動分片,提供一定程度的分區可用性,部分節點掛掉或者無法連接其他節點後,服務可以正常運行。Redis 3.0集羣採用Hash Slot方案,而不是一致性哈希。Redis把所有的Key分成了16384個slot,每個Redis實例負責其中一部分slot。集羣中的所有信息(節點、端口、slot等),都通過節點之間定期的數據交換而更新。

Redis客戶端在任意一個Redis實例發出請求,如果所需數據不在該實例中,通過重定向命令引導客戶端訪問所需的實例。

Redis 3.0集羣,目前支持的cluster特性

  • 節點自動發現
  • slave->master 選舉,集羣容錯
  • Hot resharding:在線分片
  • 集羣管理:cluster xxx
  • 基於配置(nodes-port.conf)的集羣管理
  • ASK 轉向/MOVED 轉向機制

如上圖所示,所有的redis節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬。節點的fail是通過集羣中超過半數的節點檢測失效時才生效。客戶端與redis節點直連,不需要中間proxy層。客戶端不需要連接集羣所有節點,連接集羣中任何一個可用節點即可。redis-cluster把所有的物理節點映射到[0-16383]slot上cluster負責維護node<->slot<->value。


選舉過程是集羣中所有master參與,如果半數以上master節點與master節點通信超時,認爲當前master節點掛掉。

當集羣不可用時,所有對集羣的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)錯誤。如果集羣任意master掛掉,且當前master沒有slave,集羣進入fail狀態,也可以理解成進羣的slot映射[0-16383]不完成時進入fail狀態。如果進羣超過半數以上master掛掉,無論是否有slave集羣進入fail狀態。

環境搭建

現在,我們進行集羣環境搭建。集羣環境至少需要3個主服務器節點。本次測試,使用另外3個節點作爲從服務器的節點,即3個主服務器,3個從服務器。

修改配置文件,其它的保持默認即可。


1.  # 根據實際情況修改
2.  port 7000  
3.  # 允許redis支持集羣模式
4.  cluster-enabled yes 
5.  # 節點配置文件,由redis自動維護
6.  cluster-config-file nodes.conf 
7.  # 節點超時毫秒
8.  cluster-node-timeout 5000  
9.  # 開啓AOF同步模式
10.  appendonly yes

創建集羣

目前這些實例雖然都開啓了cluster模式,但是彼此還不認識對方,接下來可以通過Redis集羣的命令行工具redis-trib.rb來完成集羣創建。
首先,下載 https://raw.githubusercontent.com/antirez/redis/unstable/src/redis-trib.rb

然後,搭建Redis 的 Ruby 支持環境。這裏,不進行擴展,參考相關文檔。

現在,接下來運行以下命令。這個命令在這裏用於創建一個新的集羣, 選項–replicas 1 表示我們希望爲集羣中的每個主節點創建一個從節點。


1.  redis-trib.rb create --replicas 1  127.0.0.1:7001  127.0.0.1:7002  127.0.0.1:7003  127.0.0.1:7004  127.0.0.1:7005  127.0.0.1:7006

5.3、測試

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章