http://www.tuicool.com/articles/naeEJbvjava
時間 2014-02-21 15:15:17 IT社區推薦資訊git
原文 http://itindex.net/detail/48192-redis-sentinel-redisgithub
Redis Sentinel是一個分佈式系統,能夠部署多個Sentinel實例來監控同一組Redis實例,它們經過Gossip協議來肯定一個主實例宕機,經過Agreement協議來執行故障恢復和配置變動,通常在生產環境中部署多個實例來提升系統可用性,只要有一個Sentinel實例運行正常,就能保證被監控的Redis實例運行正常(相似Zookeeper,經過多個Zookeeper來提升系統可用性);
本文不涉及Sentinel的實現細節和工做原理,讀者能夠閱讀其餘文章瞭解;redis
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&Jedis看上去是個完美的解決方案,這句話只說對了一半,在無分片的狀況是這樣,但咱們的應用使用了數據分片-sharing,數據被平均分佈到4個不一樣的實例上,每一個實例以主從結構部署,Jedis沒有提供基於Sentinel的ShardedJedisPool,也就是說在4個分片中,若是其中一個分片發生主從切換,應用所使用的ShardedJedisPool沒法得到通知,全部對那個分片的操做將會失敗。
本文提供一個基於Sentinel的ShardedJedisPool,能及時感知全部分片主從切換行爲,進行鏈接池重建,源碼見 ShardedJedisSentinelPool.javashell
相似以前的Jedis Pool的構造方法,須要參數poolConfig提供諸如maxIdle,maxTotal之類的配置,masters是一個List,用來保存全部分片Master在Sentinel中配置的名字(注意master的順序不能改變,由於Shard算法是依據分片位置進行計算,若是順序錯誤將致使數據存儲混亂),sentinels是一個Set,其中存放全部Sentinel的地址(格式:IP:PORT,如127.0.0.1:26379),順序無關;分佈式
在構造函數中,經過方法
取得當前全部分片的master地址(IP&PORT),對每一個分片,經過順次鏈接Sentinel實例,獲取該分片的master地址,若是沒法得到,即全部Sentinel都沒法鏈接,將休眠1秒後繼續重試,直到取得全部分片的master地址,代碼塊以下:
經過
初始化鏈接池,到此鏈接池中的全部鏈接都指向分片的master;函數
在方法
最後,會爲每一個Sentinel啓動一個Thread來監控Sentinel作出的更改:
該線程的run方法經過Jedis Pub/Sub API(實現JedisPubSub接口,並經過jedis.subscribe進行訂閱)向Sentinel實例訂閱「+switch-master」頻道,當Sentinel進行主從切換時,該線程會獲得新Master地址的通知,經過master name判斷哪一個分片進行了切換,將新master地址替換原來位置的地址,並調用initPool(List masters)進行Jedis鏈接池重建;後續全部經過該鏈接池取得的鏈接都指向新Master地址,對應用程序透明;ui
本文經過現實中遇到的問題,即在Redis數據分片的狀況下,在使用Sentinel作HA時,如何作到主從的切換對應用程序透明,經過Jedis的Pub/Sub功能,能同時監控多個分片的主從切換狀況,並經過監聽到的新地址從新構造鏈接池,後續從鏈接池中取得的全部鏈接都指向新地址。該方案的關鍵是:使用sentinel作HA,Jedis版本必須2.2.2及以上,全部訪問Redis實例的鏈接都必須從鏈接池中獲取;spa
該項目的GitHub主頁: https://github.com/warmbreeze/sharded-jedis-sentinel-pool
本文附件下載:
jedis_sentinel_patch-1.0.jar (15 KB)
該項目的GitHub主頁: https://github.com/warmbreeze/sharded-jedis-sentinel-pool