標籤:
自Redis增加Sentinel叢集工具以來,本博主就從未嘗試過使用該工具。最近在調研目前主流的Redis叢集部署方案,所以詳細地看了一遍官方對於Sentinel的介紹並在自己的台式機上完成了三Redis執行個體+三Sentinel執行個體的部署,這裡做一下簡單的總結。 首先,下載安裝Redis。目前隨Redis 2.8發布的Sentinel版本被antirez稱為Sentinel 2,是在Sentinel 1的基礎上重寫的。因為Sentinel 1已經廢棄而且BUG太多,所以antirez強烈建議將Redis和Sentinel均升級到2.8版本,本博主安裝的版本為最新的2.8.17。 其次,配置並啟動Redis執行個體。分別在6379、6380和6381三個本地連接埠上啟動三個Redis執行個體,其中6379為Master,其餘兩個為Slave。關於Redis的主從配置這裡就不再贅述了,但其中需要指出的是兩個Slave在配置參數slave-priority上的區別:6380執行個體該配置參數為50,6381執行個體該配置參數為100,這樣當Master掛掉的時候Sentinel會優先選擇slave-priority值較小的作為新的Master。 最後,配置並啟動Sentinel執行個體。分別在26379、26380和26381三個本地連接埠上啟動三個Sentinel執行個體,這三個Sentinel執行個體用來監控上面已經啟動的三個Redis執行個體。以下是26379上Sentinel執行個體的設定檔內容,參考官方文檔僅配置幾個主要的參數,其他兩個執行個體的設定檔只是連接埠號碼和資料目錄不同。port 26379dir /home/liangzhichao/data/redis/sentinels/26379sentinel monitor mymaster 127.0.0.1 6379 2sentinel down-after-milliseconds mymaster 30000sentinel parallel-syncs master 1sentinel failover-timeout mymaster 180000 在啟動Sentinel執行個體時,因為想將日誌資訊列印到檔案,但是沒有找到在設定檔中設定記錄檔的方法,所以直接採用以下方式啟動:./redis-sentinel /home/liangzhichao/data/redis/confs/sentinel.26379.conf >> /home/liangzhichao/data/redis/logs/26379.log 2>&1 &。 完成Sentinel執行個體的啟動後,我們不妨先看看Sentinel的日誌,看看它啟動之後究竟做了哪些工作,以下為26379執行個體的日誌內容,從日誌內容可以看到Sentinel啟動之後至少做了四件事:1)為自己產生一個runid來唯一地標識本執行個體;2)開始監控運行在6379連接埠上的Master Redis執行個體;3)擷取Master Redis執行個體的所有Slave Redis執行個體資訊,以便在Master Redis執行個體掛掉之後可以從所有Salve Redis執行個體中選擇出一個新的Master;4)向監控相同Master Redis執行個體的Sentinel執行個體發布自己的存在,以便讓所有Sentinel執行個體認識並記住彼此。[8229] 18 Nov 11:18:46.677 # You requested maxclients of 10000 requiring at least 10032 max file descriptors.[8229] 18 Nov 11:18:46.677 # Redis can‘t set maximum open files to 10032 because of OS error: Operation not permitted.[8229] 18 Nov 11:18:46.677 # Current maximum open files is 1024. maxclients has been reduced to 992 to compensate for low ulimit. If you need higher maxclients increase ‘ulimit -n‘.[8229] 18 Nov 11:18:46.679 # Sentinel runid is 2262ed911e9414208af4b1c48ad2b449fd4e0b89[8229] 18 Nov 11:18:46.679 # +monitor master mymaster 127.0.0.1 6379 quorum 2[8229] 18 Nov 11:18:46.679 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379[8229] 18 Nov 11:18:46.679 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379[8229] 18 Nov 11:19:27.260 * +sentinel sentinel 127.0.0.1:26380 127.0.0.1 26380 @ mymaster 127.0.0.1 6379[8229] 18 Nov 11:19:36.069 * +sentinel sentinel 127.0.0.1:26381 127.0.0.1 26381 @ mymaster 127.0.0.1 6379 這裡需要注意的是,在我們觀察到以上日誌內容的同時,各個Sentinel執行個體也都更新了自己的設定檔,以記錄目前最新的配置資訊,此時每個Sentinel執行個體的設定檔內容與啟動之前就大不相同了。以下列舉了26379執行個體的設定檔的主要內容,從中可知所有Slave Redis執行個體的資訊、其他Sentinel執行個體的資訊都已經添加完成。另外,當前設定檔的版本號碼為0。sentinel monitor mymaster 127.0.0.1 6379 2sentinel known-slave mymaster 127.0.0.1 6380sentinel known-slave mymaster 127.0.0.1 6381sentinel known-sentinel mymaster 127.0.0.1 26381 22b65a4796e6ece6b76284558a071cc83df71098sentinel known-sentinel mymaster 127.0.0.1 26380 59616326f3c539ff3301098e1bf708350e6dd45dsentinel current-epoch 0 至此,一主兩從的Redis叢集和三執行個體的Sentinel叢集就全部啟動完成並開始正常工作了。接下來我們不妨通過Jedis用戶端來驗證一下Sentinel叢集的正確性,以下為測試代碼,功能很簡單:首先建立到Sentinel叢集的串連,然後通過Sentinel叢集擷取當前Master Redis執行個體的資訊,最後向Master Redis執行個體寫入一條資料並查詢該資料以確保資料寫入成功。
package redis.clients.mytest;import java.util.HashSet;import java.util.Set;import redis.clients.jedis.HostAndPort;import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisSentinelPool;public class MyJedisSentinelTest { public static void main(String[] args) { Set sentinels = new HashSet(); sentinels.add(new HostAndPort("localhost", 26379).toString()); sentinels.add(new HostAndPort("localhost", 26380).toString()); sentinels.add(new HostAndPort("localhost", 26381).toString()); JedisSentinelPool sentinelPool = new JedisSentinelPool("mymaster", sentinels); System.out.println("Current master: " + sentinelPool.getCurrentHostMaster().toString()); Jedis master = sentinelPool.getResource(); master.set("username","liangzhichao"); sentinelPool.returnResource(master); Jedis master2 = sentinelPool.getResource(); String value = master2.get("username"); System.out.println("username: " + value); master2.close(); sentinelPool.destroy(); }}
執行以上代碼,我們會得到如下結果資訊,由此可知通過Sentinel叢集成功擷取到了Master Redis執行個體的資訊,到Master Redis執行個體的讀寫請求可以正常處理。
2014-11-20 16:39:00 redis.clients.jedis.JedisSentinelPool initSentinels
資訊: Trying to find master from available Sentinels...
2014-11-20 16:39:00 redis.clients.jedis.JedisSentinelPool initSentinels
資訊: Redis master running at 127.0.0.1:6379, starting Sentinel listeners...
2014-11-20 16:39:00 redis.clients.jedis.JedisSentinelPool initPool
資訊: Created JedisPool to master at 127.0.0.1:6379
Current master: 127.0.0.1:6379
username: liangzhichao 目前為止,Sentinel叢集都是正常工作的,接下來我們再來看一看Sentinel叢集是如何處理Master Redis執行個體掛掉的。我們通過kill掉運行在6379連接埠上的Redis執行個體進程來觸發這一情況,同時觀察Sentinel叢集各個執行個體的日誌資訊,以下為各個執行個體處理Master Redis執行個體掛掉的日誌資訊。
26379執行個體:[8229] 19 Nov 14:41:32.033 # +sdown master mymaster 127.0.0.1 6379[8229] 19 Nov 14:41:32.116 # +odown master mymaster 127.0.0.1 6379 #quorum 2/2[8229] 19 Nov 14:41:32.116 # +new-epoch 1[8229] 19 Nov 14:41:32.116 # +try-failover master mymaster 127.0.0.1 6379[8229] 19 Nov 14:41:32.286 # +vote-for-leader 2262ed911e9414208af4b1c48ad2b449fd4e0b89 1[8229] 19 Nov 14:41:32.286 # 127.0.0.1:26381 voted for 22b65a4796e6ece6b76284558a071cc83df71098 1[8229] 19 Nov 14:41:32.387 # 127.0.0.1:26380 voted for 22b65a4796e6ece6b76284558a071cc83df71098 1[8229] 19 Nov 14:41:33.326 # +config-update-from sentinel 127.0.0.1:26381 127.0.0.1 26381 @ mymaster 127.0.0.1 6379[8229] 19 Nov 14:41:33.326 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380[8229] 19 Nov 14:41:33.326 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6380[8229] 19 Nov 14:41:33.430 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380[8229] 19 Nov 14:42:03.507 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
26380執行個體:[8243] 19 Nov 14:41:32.023 # +sdown master mymaster 127.0.0.1 6379[8243] 19 Nov 14:41:32.336 # +new-epoch 1[8243] 19 Nov 14:41:32.386 # +vote-for-leader 22b65a4796e6ece6b76284558a071cc83df71098 1[8243] 19 Nov 14:41:33.151 # +odown master mymaster 127.0.0.1 6379 #quorum 3/2[8243] 19 Nov 14:41:33.151 # Next failover delay: I will not start a failover before Wed Nov 19 14:47:32 2014[8243] 19 Nov 14:41:33.327 # +config-update-from sentinel 127.0.0.1:26381 127.0.0.1 26381 @ mymaster 127.0.0.1 6379[8243] 19 Nov 14:41:33.328 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380[8243] 19 Nov 14:41:33.328 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6380[8243] 19 Nov 14:41:33.558 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380[8243] 19 Nov 14:42:03.616 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
26381執行個體:[8247] 19 Nov 14:41:32.042 # +sdown master mymaster 127.0.0.1 6379[8247] 19 Nov 14:41:32.094 # +odown master mymaster 127.0.0.1 6379 #quorum 3/2[8247] 19 Nov 14:41:32.094 # +new-epoch 1[8247] 19 Nov 14:41:32.094 # +try-failover master mymaster 127.0.0.1 6379[8247] 19 Nov 14:41:32.194 # +vote-for-leader 22b65a4796e6ece6b76284558a071cc83df71098 1[8247] 19 Nov 14:41:32.286 # 127.0.0.1:26379 voted for 2262ed911e9414208af4b1c48ad2b449fd4e0b89 1[8247] 19 Nov 14:41:32.387 # 127.0.0.1:26380 voted for 22b65a4796e6ece6b76284558a071cc83df71098 1[8247] 19 Nov 14:41:32.396 # +elected-leader master mymaster 127.0.0.1 6379[8247] 19 Nov 14:41:32.396 # +failover-state-select-slave master mymaster 127.0.0.1 6379[8247] 19 Nov 14:41:32.459 # +selected-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379[8247] 19 Nov 14:41:32.459 * +failover-state-send-slaveof-noone slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379[8247] 19 Nov 14:41:32.522 * +failover-state-wait-promotion slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379[8247] 19 Nov 14:41:33.307 # +promoted-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379[8247] 19 Nov 14:41:33.307 # +failover-state-reconf-slaves master mymaster 127.0.0.1 6379[8247] 19 Nov 14:41:33.326 * +slave-reconf-sent slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379[8247] 19 Nov 14:41:33.851 # -odown master mymaster 127.0.0.1 6379[8247] 19 Nov 14:41:34.356 * +slave-reconf-inprog slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379[8247] 19 Nov 14:41:34.356 * +slave-reconf-done slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379[8247] 19 Nov 14:41:34.426 # +failover-end master mymaster 127.0.0.1 6379[8247] 19 Nov 14:41:34.426 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380[8247] 19 Nov 14:41:34.427 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6380[8247] 19 Nov 14:41:34.479 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380[8247] 19 Nov 14:42:04.531 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380 由以上日誌內容我們大致可以看到Sentinel叢集處理Master Redis執行個體掛掉的基本流程:1)每個Sentinel執行個體通過監控發現6379連接埠的Master Redis執行個體不工作,於是將該執行個體的狀態設定為sdown;2)通過Sentinel彼此之間通訊確認大多數Sentinel執行個體均認為Master Redis掛掉,於是將該執行個體的狀態設定為odown;3)準備觸發Master Redis執行個體的failover,要選舉一個Sentinel執行個體進行首次failover操作;4)選舉出來的Sentinel執行個體從Slave Redis執行個體中選擇一個出來成為新的Master Redis執行個體;5)完成Master Redis執行個體的切換之後,在各個Sentinel執行個體間同步最新的配置資訊;6)讓落選的Slave Redis執行個體切換到新的Master Redis執行個體,開始同步資料。 具體到我們的環境就是運行在連接埠26381上的Sentinel執行個體獲得了執行此次failover的許可權,於是它選擇運行在連接埠6380上的Slave Redis執行個體成為新的Master Redis執行個體(因為6380執行個體的slave-priority比6381執行個體的值小),切換完成後落選的6381執行個體開始轉而備份6380執行個體的資料。此時我們再看一看Sentinel執行個體的設定檔,以確認配置資訊確實進行了更新。以下同樣為26379執行個體的設定檔的主要內容,對比之前的設定檔內容我們可以知道Master Redis執行個體確實發生了切換,當前的配置資訊版本已經變為1。sentinel monitor mymaster 127.0.0.1 6380 2sentinel known-slave mymaster 127.0.0.1 6381sentinel known-slave mymaster 127.0.0.1 6379sentinel known-sentinel mymaster 127.0.0.1 26381 22b65a4796e6ece6b76284558a071cc83df71098sentinel known-sentinel mymaster 127.0.0.1 26380 59616326f3c539ff3301098e1bf708350e6dd45dsentinel current-epoch 1 我們再執行一次上面的Jedis測試程式,得到以下結果,從Sentinel叢集擷取到的確實已經是新的Master Redis執行個體了!2014-11-20 16:39:00 redis.clients.jedis.JedisSentinelPool initSentinels
資訊: Trying to find master from available Sentinels...
2014-11-20 16:39:00 redis.clients.jedis.JedisSentinelPool initSentinels
資訊: Redis master running at 127.0.0.1:6380, starting Sentinel listeners...
2014-11-20 16:39:00 redis.clients.jedis.JedisSentinelPool initPool
資訊: Created JedisPool to master at 127.0.0.1:6380
Current master: 127.0.0.1:6380
username: liangzhichao
Redis Sentinel初體驗