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

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

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

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

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

 

 

最小化的sentinel配置文件爲:緩存

port 7031

dir /opt/app/redis/redis-2.8.17/tmp

sentinel monitor mymaster 10.6.144.155 7030 1
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 15000

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

第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中選一個升級爲masterspa

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

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

 

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

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

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

三、./redis-cli -p 7031 sentinel masters 可經過該命令查看當前的master節點狀況(注,這裏必定要帶sentinel的端口)

四、在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。

最後,若是想中止sentinel,可輸入命令./redis-cli -p 7031 shutdown

 

客戶端的使用:

1、Jedis

@Test
    public void testJedis() throws InterruptedException {

        Set<String> sentinels = new HashSet<String>();
        sentinels.add("10.6.144.155:7031");
        sentinels.add("10.6.144.156:7031");        

        JedisSentinelPool sentinelPool = new JedisSentinelPool("mymaster",
                sentinels);

        Jedis jedis = sentinelPool.getResource();

        System.out.println("current Host:"
                + sentinelPool.getCurrentHostMaster());

        String key = "a";

        String cacheData = jedis.get(key);

        if (cacheData == null) {
            jedis.del(key);
        }

        jedis.set(key, "aaa");// 寫入

        System.out.println(jedis.get(key));// 讀取

        System.out.println("current Host:"
                + sentinelPool.getCurrentHostMaster());// down掉master,觀察slave是否被提高爲master

        jedis.set(key, "bbb");// 測試新master的寫入

        System.out.println(jedis.get(key));// 觀察讀取是否正常

        sentinelPool.close();
        jedis.close();

    }

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

 

2、Redisson

@Test
    public void testRedisson() throws InterruptedException, ExecutionException,
            TimeoutException {

        Config config = new Config();

        config.useSentinelConnection().setMasterName("mymaster")
                .addSentinelAddress("10.6.144.155:7031", "10.6.144.156:7031");
        config.useSentinelConnection().setRetryInterval(1000);
        config.useSentinelConnection().setRetryAttempts(1);

        Redisson redisson = Redisson.create(config);

        String key = "test";

        RBucket<String> myObj = redisson.getBucket(key);
        if (myObj != null) {
            myObj.delete();
        }

        myObj.set("aaa");// 寫入

        System.out.println(myObj.get());// 讀取

        myObj.set("bbb");// down掉master,觀察是否能寫入新master

        System.out.println(myObj.get());

        redisson.shutdown();

    }

一樣作相似的測試,二次寫,二次讀,若是第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

相關文章
相關標籤/搜索