redis 學習筆記(4)-HA高可用方案Sentinel配置

轉自:http://www.cnblogs.com/yjmyzz/p/redis-sentinel-sample.html

上一節中介紹了master-slave模式,在最小配置:master、slave各一個節點的情況下,不管是master還是slave down掉一個,“完整的”讀/寫功能都將受影響,這在生產環境中顯然不能接受。幸好redis提供了sentinel(哨兵)機制,通過sentinel模式啓動redis後,自動監控master/slave的運行狀態,基本原理是:心跳機制+投票裁決

每個sentinel會向其它sentinal、master、slave定時發送消息,以確認對方是否“活”着,如果發現對方在指定時間(可配置)內未迴應,則暫時認爲對方已掛(所謂的“主觀認爲宕機” Subjective Down,簡稱SDOWN)。

若“哨兵羣”中的多數sentinel,都報告某一master沒響應,系統才認爲該master"徹底死亡"(即:客觀上的真正down機,Objective Down,簡稱ODOWN),通過一定的vote算法,從剩下的slave節點中,選一臺提升爲master,然後自動修改相關配置。

 

 

最小化的sentinel配置文件爲:

複製代碼
1 port 7031
2 
3 dir /opt/app/redis/redis-2.8.17/tmp
4 
5 sentinel monitor mymaster 10.6.144.155 7030 1
6 sentinel down-after-milliseconds mymaster 5000
7 sentinel parallel-syncs mymaster 1
8 sentinel failover-timeout mymaster 15000
複製代碼

第1行,指定sentinel使用的端口,不能與redis-server運行實例的端口衝突

第3行,指定工作目錄

第5行,顯示監控master節點10.6.144.155,master節點使用端口7030,最後一個數字表示投票需要的"最少法定人數",比如有10個sentinal哨兵都在監控某一個master節點,如果需要至少6個哨兵發現master掛掉後,才認爲master真正down掉,那麼這裏就配置爲6,最小配置1臺master,1臺slave,在二個機器上都啓動sentinal的情況下,哨兵數只有2個,如果一臺機器物理掛掉,只剩一個sentinal能發現該問題,所以這裏配置成1,至於mymaster只是一個名字,可以隨便起,但要保證5-8行都使用同一個名字

第6行,表示如果5s內mymaster沒響應,就認爲SDOWN

第8行,表示如果15秒後,mysater仍沒活過來,則啓動failover,從剩下的slave中選一個升級爲master

第7行,表示如果master重新選出來後,其它slave節點能同時並行從新master同步緩存的臺數有多少個,顯然該值越大,所有slave節點完成同步切換的整體速度越快,但如果此時正好有人在訪問這些slave,可能造成讀取失敗,影響面會更廣。最保定的設置爲1,只同一時間,只能有一臺幹這件事,這樣其它slave還能繼續服務,但是所有slave全部完成緩存更新同步的進程將變慢。

另:一個sentinal可同時監控多個master,只要把5-8行重複多段,加以修改即可。

 

具體使用步驟:(約定7030是redis-server端口,7031是redis-sentinel端口,且master、slave上的redis-server均已正常啓動)

1、先在redis根目錄下創建conf子目錄,新建配置文件sentinel.conf,內容參考前面的內容(master和slave上都做相同的配置)

2、./redis-sentinel ../conf/sentinel.conf 即可(master和slave上都啓用sentinel,即最終有二個哨兵)

3、./redis-cli -p 7031 sentinel masters 可通過該命令查看當前的master節點情況

4、在master上,./redis-cli -p 7030 shutdown ,手動把master停掉,觀察sentinel的輸出

[17569] 21 Nov 11:06:56.277 # +odown master mymaster 10.6.144.155 7030 #quorum 1/1
[17569] 21 Nov 11:06:56.277 # Next failover delay: I will not start a failover before Fri Nov 21 11:07:26 2014
[17569] 21 Nov 11:06:57.389 # +config-update-from sentinel 10.6.144.156:7031 10.6.144.156 7031 @ mymaster 10.6.144.155 7030
[17569] 21 Nov 11:06:57.389 # +switch-master mymaster 10.6.144.155 7030 10.6.144.156 7030
[17569] 21 Nov 11:06:57.389 * +slave slave 10.6.53.131:7030 10.6.53.131 7030 @ mymaster 10.6.144.156 7030

從紅線部分可以看出,master發生了遷移,等剛纔停掉的master再重啓後,可以觀察到它將被當作slave加入,類似以下輸出:

[36444] 21 Nov 11:11:14.540 * +convert-to-slave slave 10.6.144.155:7030 10.6.144.155 7030 @ mymaster 10.6.144.156 7030

注意事項:發生master遷移後,如果遇到運維需要,想重啓所有redis,必須最先重啓“新的”master節點,否則sentinel會一直找不到master。

 

客戶端的使用:

一、Jedis

複製代碼
 1     @Test
 2     public void testJedis() throws InterruptedException {
 3 
 4         Set<String> sentinels = new HashSet<String>();
 5         sentinels.add("10.6.144.155:7031");
 6         sentinels.add("10.6.144.156:7031");        
 7 
 8         JedisSentinelPool sentinelPool = new JedisSentinelPool("mymaster",
 9                 sentinels);
10 
11         Jedis jedis = sentinelPool.getResource();
12 
13         System.out.println("current Host:"
14                 + sentinelPool.getCurrentHostMaster());
15 
16         String key = "a";
17 
18         String cacheData = jedis.get(key);
19 
20         if (cacheData == null) {
21             jedis.del(key);
22         }
23 
24         jedis.set(key, "aaa");// 寫入
25 
26         System.out.println(jedis.get(key));// 讀取
27 
28         System.out.println("current Host:"
29                 + sentinelPool.getCurrentHostMaster());// down掉master,觀察slave是否被提升爲master
30 
31         jedis.set(key, "bbb");// 測試新master的寫入
32 
33         System.out.println(jedis.get(key));// 觀察讀取是否正常
34 
35         sentinelPool.close();
36         jedis.close();
37 
38     }
複製代碼

4-6行是關鍵,這裏指定了sentinel節點信息。但這段代碼在運行時發現一個問題:對於1主1從的最小化配置,如果連續發生兩次寫操作,第1次set成功後,如果斷點停在這裏,down掉master,這時剩下的slave會提升爲master,但是第2次set時,會拋異常,類似:連接已斷開。(注:通過Spring-Data-Redis整合Jedis與redis時,利用RedisTemplate調用不會有這個問題,建議正式項目中,通過Spring整合Redis來調用相關功能)

 

二、Redisson

複製代碼
 1     @Test
 2     public void testRedisson() throws InterruptedException, ExecutionException,
 3             TimeoutException {
 4 
 5         Config config = new Config();
 6 
 7         config.useSentinelConnection().setMasterName("mymaster")
 8                 .addSentinelAddress("10.6.144.155:7031", "10.6.144.156:7031");
 9         config.useSentinelConnection().setRetryInterval(1000);
10         config.useSentinelConnection().setRetryAttempts(1);
11 
12         Redisson redisson = Redisson.create(config);
13 
14         String key = "test";
15 
16         RBucket<String> myObj = redisson.getBucket(key);
17         if (myObj != null) {
18             myObj.delete();
19         }
20 
21         myObj.set("aaa");// 寫入
22 
23         System.out.println(myObj.get());// 讀取
24 
25         myObj.set("bbb");// down掉master,觀察是否能寫入新master
26 
27         System.out.println(myObj.get());
28 
29         redisson.shutdown();
30 
31     }
複製代碼

同樣做類似的測試,二次寫,二次讀,如果第1次寫後,人工down掉master,剩下的slave會提升成master,第二次寫ok,但此時redis節點中,只剩master,沒有slave了,從測試結果上看,第二次get還是嘗試去找slave節點,但是此時已經不存在了,所以一直在等候,導致後面的的處理被阻塞。

這不是redis的問題,而是Redisson客戶端設計不夠智能。

鑑於這種現狀,如果要使用Redisson,最好做成1主2從的部署結構:(sentinel.conf中的“法定人數”,建議調整成2)

 

這樣的好處是,1個master掛掉後,剩下的2臺slave中,會有1臺提升爲master,整體仍然保證有1個master和1個slave,讀寫均不受影響。

關於Sentinel的更多細節,可參考官網文檔:http://www.redis.io/topics/sentinel

作者:菩提樹下的楊過
出處:http://yjmyzz.cnblogs.com 
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。

發佈了42 篇原創文章 · 獲贊 3 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章