標籤:
本文主要介紹一種通過Jedis&Sentinel實現Redis叢集高可用方案,該方案需要使用Jedis2.2.2及以上版本(強制),Redis2.8及以上版本(可選,Sentinel最早出現在Redis2.4中,Redis2.8中Sentinel更加穩定),Redis叢集是以分區(Sharding)加主從的方式搭建,滿足可擴充性的要求;
Redis Sentinel介紹
Redis Sentinel是Redis官方提供的叢集管理工具,主要有三大功能:
監控,能持續監控Redis的主從執行個體是否正常工作;
通知,當被監控的Redis執行個體出問題時,能通過API通知系統管理員或其他程式;
自動故障恢複,如果主執行個體無法正常工作,Sentinel將啟動故障恢複機制把一個從執行個體提升為主執行個體,其他的從執行個體將會被重新設定到新的主執行個體,且應用程式會得到一個更換新地址的通知。
Redis Sentinel是一個分布式系統,可以部署多個Sentinel執行個體來監控同一組Redis執行個體,它們通過Gossip協議來確定一個主執行個體宕機,通過Agreement協議來執行故障恢複和配置變更,一般在生產環境中部署多個執行個體來提高系統可用性,只要有一個Sentinel執行個體運行正常,就能保證被監控的Redis執行個體運行正常(類似Zookeeper,通過多個Zookeeper來提高系統可用性);
本文不涉及Sentinel的實現細節和工作原理,讀者可以閱讀其他文章瞭解;
Redis HA方案
HA的關鍵在於避免單點故障及故障恢複,在Redis Cluster未發布之前,Redis一般以主/從方式部署(這裡討論的應用從執行個體主要用於備份,主執行個體提供讀寫,有不少應用是讀寫分離的,讀寫操作需要取不同的Redis執行個體,該方案也可用於此種應用,原理都是相通的,區別在於資料操作層如何封裝),該方式要實現HA主要有如下幾種方案:
1,keepalived:通過keepalived的虛擬IP,提供主從的統一訪問,在主出現問題時,通過keepalived運行指令碼將從提升為主,待主恢複後先同步後自動變為主,該方案的好處是主從切換後,應用程式不需要知道(因為訪問的虛擬IP不變),壞處是引入keepalived增加部署複雜性;
2,zookeeper:通過zookeeper來監控主從執行個體,維護最新有效IP,應用通過zookeeper取得IP,對Redis進行訪問;
3,sentinel:通過Sentinel監控主從執行個體,自動進行故障恢複,該方案有個缺陷:因為主從執行個體地址(IP&PORT)是不同的,當故障發生進行主從切換後,應用程式無法知道新地址,故在Jedis2.2.2中新增了對Sentinel的支援,應用通過redis.clients.jedis.JedisSentinelPool.getResource()取得的Jedis執行個體會及時更新到新的主執行個體地址。
筆者所在的公司先使用了方案1一段時間後,發現keepalived在有些情況下會導致資料丟失,keepalived通過shell指令碼進行主從切換,配置複雜,而且keepalived成為新的單點,後來選用了方案3,使用Redis官方解決方案;(方案2需要編寫大量的監控代碼,沒有方案3簡便,網上有人使用方式情節2讀者可自行查看)
選用Sentinel出現的問題
Sentinel&Jedis看上去是個完美的解決方案,這句話只說對了一半,在無分區的情況是這樣,但我們的應用使用了資料分區-sharing,資料被平均分布到4個不同的執行個體上,每個執行個體以主從結構部署,Jedis沒有提供基於Sentinel的ShardedJedisPool,也就是說在4個分區中,如果其中一個分區發生主從切換,應用所使用的ShardedJedisPool無法獲得通知,所有對那個分區的操作將會失敗。
本文提供一個基於Sentinel的ShardedJedisPool,能及時感知所有分區主從切換行為,進行串連池重建,源碼見ShardedJedisSentinelPool.Java
ShardedJedisSentinelPool實現分析建構函式
類似之前的Jedis Pool的構造方法,需要參數poolC
取得當前所有分區的master地址(IP&PORT),對每個分區,通過順次串連Sentinel執行個體,擷取該分區的master地址,如果無法獲得,即所有Sentinel都無法串連,將休眠1秒後繼續重試,直到取得所有分區的master地址,代碼塊如下:
通過
初始化串連池,到此串連池中的所有串連都指向分區的master;
監控每個Sentinel
在方法
最後,會為每個Sentinel啟動一個Thread來監控Sentinel做出的更改:
該線程的run方法通過Jedis Pub/Sub API(實現JedisPubSub介面,並通過jedis.subscribe進行訂閱)向Sentinel執行個體訂閱“+switch-master”頻道,當Sentinel進行主從切換時,該線程會得到新Master地址的通知,通過master name判斷哪個分區進行了切換,將新master地址替換原來位置的地址,並調用initPool(List masters)進行Jedis串連池重建;後續所有通過該串連池取得的串連都指向新Master地址,對應用程式透明;
應用樣本
總結
本文通過現實中遇到的問題,即在Redis資料分區的情況下,在使用Sentinel做HA時,如何做到主從的切換對應用程式透明,通過Jedis的Pub/Sub功能,能同時監控多個分區的主從切換情況,並通過監聽到的新地址重新構造串連池,後續從串連池中取得的所有串連都指向新地址。該方案的關鍵是:使用sentinel做HA,Jedis版本必須2.2.2及以上,所有訪問Redis執行個體的串連都必須從串連池中擷取;
該項目的GitHub首頁: https://github.com/warmbreeze/sharded-jedis-sentinel-pool
http://www.07net01.com/linux/jiyuRedis_SentineldeRedisjiqun_zhucong_amp_amp_Sharding_gaokeyongfangan_720296_1393002463.html
基於Redis Sentinel的Redis叢集(主從Sharding)高可用方案(轉)