Redis 主從、哨兵Sentinel、Jedis

 

Redis 主從、哨兵Sentinel、Jedis

版權聲明:本文爲博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接和本聲明。
本文連接: http://www.javashuo.com/article/p-hcihbkbc-mh.html

上篇說到了Redis安裝、運行。今天來看一看Redis的主從複製、Sentinel;java


1、主從複製

1. 配置

Master上修改redis.confnginx

// 不想用密碼,因此把保護模式設置爲no protected-mode no // 其實master上不須要配置什麼,這裏只是取消了保護模式
  • 1
  • 2
  • 3

Slave1Slave2上修改redis.confredis

// 一樣關閉保護模式 protected-mode no // 設置本機是誰的slave slaveof master的ip 6379 // 當配置了slaveof後,下面這條控制本機只能讀 slave-read-only yes
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2. Jedis操做

// 簡單設置3個鏈接池 private static final JedisPool masterPool; private static final JedisPool slavePool1; private static final JedisPool slavePool2; static { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); // 最多能夠有10個鏈接 jedisPoolConfig.setMaxTotal(10); jedisPoolConfig.setMaxIdle(5); jedisPoolConfig.setMinIdle(5); masterPool = new JedisPool(jedisPoolConfig, "111.111.111.111"); slavePool1 = new JedisPool(jedisPoolConfig, "111.111.111.112"); slavePool2 = new JedisPool(jedisPoolConfig, "111.111.111.113"); } public static void main(String[] args) throws Exception { // 簡單使用,經過try-with-resource try (Jedis jedis = masterPool.getResource()) { jedis.get("key1"); } catch (Exception e) { e.printStackTrace(); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

3. 主從的意義

  1. Redis須要讀寫分離嗎? 
    可能你們會思考過這樣一個問題,在MySQL中經常使用的讀寫分離,在Redis這種內存DB中是否還會須要?shell

    反對者的觀點是:Redis是內存存儲,讀寫都很是快,若是將讀且分離到MasterSlaves上不只可能形成主從不一樣步的麻煩,甚至不見得會提高整個DB的處理能力和速度。ruby

    同意者的觀點是:Redis提供的MasterSlave複製功能;官網中的介紹服務器

    Replication can be used both for scalability, in order to have multiple slaves for read-only queries (for example, slow O(N) operations can be offloaded to slaves), or simply for data redundancy.markdown

    甚至配置文件中的參數slave-read-only yes都在提示着使用者,Redis給你提供了讀寫分離的功能。因此,爲何不要用呢?tcp

    通過思考事後,我以爲:分佈式

    1 若是使用者的業務數據量不大,則徹底沒必要作讀寫分離,讀寫均在Master上作便可。可是主從複製仍是須要的,可將Slave做爲簡單的數據轉儲。 
    2 若是使用者的業務數據量比較大,只用一個物理機Master承擔讀寫已不能知足業務或性能的需求,那麼則能夠作讀且分離。即,在項目代碼中封裝一下對Redis的操做(如封裝Jedis操做),將寫操做映射給Master,將讀操做按照你本身定義的分配策略,映射給某個Slave性能


一個企業級系統最重要的指標就是「可用性」和「高性能」。

顯然,上面的主從複製、讀寫分離可以簡單的提供「高性能」,但也只是提高了「讀」的性能,並不能擴展「寫」。(寫的擴展這裏暫且不表)

另外一方面,「可用性」也是極其重要的。如上結構可用性並不高,一旦Master宕機則Redis將當即不可寫,Slave將只剩下舊數據,系統隨即不可用。 
必然的,Redis提供了高可用(High Availability)方案,其中之一就是Sentinel-哨兵。


2、Sentinel - 高可用

1. 什麼是Sentinel?

見名知意,它是Redis提供的哨兵程序,它是分佈式程序,能夠這樣描述它們:

哨兵通常是好幾個一塊兒站崗,他們共同監視一個Master以及其Slaves。當哨兵看到Master掛掉了,他們就會互相確認有沒有看走眼,一旦多數哨兵都說它掛了,那麼他們就能得出結論:Master掛了。 
此時第一個發現的Sentinel會負責進行自動故障遷移,它會當即在Slaves中選出一個擔任Master,全部Slaves從屬於新Master,全部客戶端對Master的操做轉而到這臺新Master上。

Sentinel的主要工做以下:

  1. 監控(Monitoring): Sentinel 會不斷地檢查你的主服務器和從服務器是否運做正常。

  2. 提醒(Notification): 當被監控的某個 Redis 服務器出現問題時, Sentinel 能夠經過 API 向管理員或者其餘應用程序發送通知。

  3. 自動故障遷移(Automatic failover): 當一個主服務器不能正常工做時, Sentinel 會開始一次自動故障遷移操做, 它會將失效主服務器的其中一個從服務器升級爲新的主服務器, 並讓失效主服務器的其餘從服務器改成複製新的主服務器; 當客戶端試圖鏈接失效的主服務器時, 集羣也會向客戶端返回新主服務器的地址, 使得集羣可使用新主服務器代替失效服務器。

2. 配置Sentinel

哨兵應該被放在獨立的服務器上,最好最少應該有3個哨兵(3臺服務器)。

  1. 配置文件sentinel.conf

    // 26379模式是sentinel的運行端口,6379是redis-server的 port 26379 // 做爲守護進程 daemonize yes // 工做目錄,設置到你統一規劃的地方 dir /tmp // log文件 dir /.... // protected-mode必需要設置的,不設置不行 protected-mode no // 配置監視的Master,注意無需配置其Slave,Sentinel會本身去詢問Master // sentinel monitor master-name ip redis-port quorum // quorum 哨兵們認爲master客觀死亡(Objectively Down)所須要的法定人。不管是否設置這個值,想要啓動failover都必須有多數哨兵贊成 sentinel monitor yewu01 127.0.0.1 6379 2 // 若是30000 ms後master仍是不迴應,就說明Master處於主觀死亡(Subjectively Down) sentinel down-after-milliseconds yewu01 30000 // 當發生failover的同時,1個slave開始與新master進行同步。意思是:此slave開始接收master的RDB文件而不能對外提供服務了,而其它slave還能對外服務(具體可否對外服務看第二個//),因此越少意味着redis能越快恢復對外服務 // 同時還要搭配配置slave的redis.conf中的 slave-serve-stale-data參數,指定是否可用過時數據 sentinel parallel-syncs yewu01 1 // 執行failover多久算failover超時 sentinel failover-timeout yewu01 180000
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
  2. 運行sentinel 
    雖然 Redis Sentinel 釋出爲一個單獨的可執行文件 redis-sentinel , 但實際上它只是一個運行在特殊模式下的 Redis 服務器, 你能夠在啓動一個普通 Redis 服務器時經過給定 --sentinel 選項來啓動 Redis Sentinel 。

    // 1. 用redis-server加參數 --sentinel的方式啓動 redis-server /path/to/sentinel.conf --sentinel // 2. 用redis-sentinel 方式啓動 redis-sentinel /path/to/sentinel.conf //注意!注意!注意!不要忘記在防火牆添加端口,個人是CentOS7,因此以下 firewall-cmd --zone=public --add-port=26379/tcp --permanent 
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  3. 查看狀態 
    redis-cli -h <hostname> -p 26379登陸到Sentinel;

    Sentinel 可接受的命令(官網頁面搜索Sentinel API):

    • PING :返回 PONG 。
    • SENTINEL masters :列出全部被監視的主服務器,以及這些主服務器的當前狀態。
    • SENTINEL master <master name>:特定主服務器的當前狀態。
    • SENTINEL slaves <master name>:列出給定主服務器的全部從服務器,以及這些從服務器的當前狀態。
    • SENTINEL sentinels <master name> Show a list of sentinel instances for this master, and their state.
    • SENTINEL get-master-addr-by-name <master name> : 返回給定名字的主服務器的 IP 地址和端口號。 若是這個主服務器正在執行故障轉移操做, 或者針對這個主服務器的故障轉移操做已經完成, 那麼這個命令返回新的主服務器的 IP 地址和端口號。
    • SENTINEL reset <pattern>: 重置全部名字和給定模式 pattern 相匹配的主服務器。 pattern 參數是一個 Glob 風格的模式。 重置操做清楚主服務器目前的全部狀態, 包括正在執行中的故障轉移, 並移除目前已經發現和關聯的, 主服務器的全部從服務器和 Sentinel 。
    • SENTINEL failover : 當主服務器失效時, 在不詢問其餘 Sentinel 意見的狀況下, 強制開始一次自動故障遷移 (不過發起故障轉移的 Sentinel 會向其餘 Sentinel 發送一個新的配置,其餘 Sentinel 會根據這個配置進行相應的更新)。
  4. sentinel.conf配置被改變

    每當一個Sentinel啓動後,它就會修改並通知其它Sentinel同時修改自身的sentinel.conf文件,例如:

    生成一個myid

    sentinel myid 0f9bd55b18aa54a5f5efc6fb7b3371da56d48d4a
    • 1

    文件最後會加上以下:

    # Generated by CONFIG REWRITE sentinel known-sentinel yewu01 192.168.0.1 26379 58a141a0f97669925bcc84e3a3b3dbc8602dea99 sentinel known-sentinel yewu01 192.168.0.2 26379 a0fbf10df21374f8b5cac1f410d9df3b26618575 sentinel current-epoch 0
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

3. failover - 故障轉移

  1. 執行pkill redis-sever關掉Master觀察Sentinel日誌以下:

    這是一個被選爲failover執行者的sentinel的日誌,英文挺清晰明瞭的就不翻譯了:

    6480:X 14 Feb 19:46:54.746 # +sdown master yewu01 10.173.244.98 6379 6480:X 14 Feb 19:46:54.798 # +odown master yewu01 10.173.244.98 6379 #quorum 3/2 6480:X 14 Feb 19:46:54.798 # +new-epoch 1 6480:X 14 Feb 19:46:54.798 # +try-failover master yewu01 10.173.244.98 6379 6480:X 14 Feb 19:46:54.807 # +vote-for-leader 214bd3df8363327488cd8c430166cf48cd2ab33a 1 6480:X 14 Feb 19:46:54.819 # f7462491e6881da2c1efbfd6465ece6380c653cf voted for 214bd3df8363327488cd8c430166cf48cd2ab33a 1 6480:X 14 Feb 19:46:54.823 # 6c95942bbcc39a0703ec5d54a76d6a696a500a17 voted for 214bd3df8363327488cd8c430166cf48cd2ab33a 1 6480:X 14 Feb 19:46:54.907 # +elected-leader master yewu01 10.173.244.98 6379 6480:X 14 Feb 19:46:54.907 # +failover-state-select-slave master yewu01 10.173.244.98 6379 6480:X 14 Feb 19:46:54.974 # +selected-slave slave 10.174.249.145:6379 10.174.249.145 6379 @ yewu01 10.173.244.98 6379 6480:X 14 Feb 19:46:54.974 * +failover-state-send-slaveof-noone slave 10.174.249.145:6379 10.174.249.145 6379 @ yewu01 10.173.244.98 6379 6480:X 14 Feb 19:46:55.057 * +failover-state-wait-promotion slave 10.174.249.145:6379 10.174.249.145 6379 @ yewu01 10.173.244.98 6379 6480:X 14 Feb 19:46:55.534 # +promoted-slave slave 10.174.249.145:6379 10.174.249.145 6379 @ yewu01 10.173.244.98 6379 6480:X 14 Feb 19:46:55.534 # +failover-state-reconf-slaves master yewu01 10.173.244.98 6379 6480:X 14 Feb 19:46:55.581 * +slave-reconf-sent slave 10.251.22.210:6379 10.251.22.210 6379 @ yewu01 10.173.244.98 6379 6480:X 14 Feb 19:46:55.957 # -odown master yewu01 10.173.244.98 6379 6480:X 14 Feb 19:46:56.041 * +slave-reconf-inprog slave 10.251.22.210:6379 10.251.22.210 6379 @ yewu01 10.173.244.98 6379 6480:X 14 Feb 19:46:56.042 * +slave-reconf-done slave 10.251.22.210:6379 10.251.22.210 6379 @ yewu01 10.173.244.98 6379 6480:X 14 Feb 19:46:56.096 # +failover-end master yewu01 10.173.244.98 6379 6480:X 14 Feb 19:46:56.096 # +switch-master yewu01 10.173.244.98 6379 10.174.249.145 6379 6480:X 14 Feb 19:46:56.097 * +slave slave 10.251.22.210:6379 10.251.22.210 6379 @ yewu01 10.174.249.145 6379 6480:X 14 Feb 19:46:56.097 * +slave slave 10.173.244.98:6379 10.173.244.98 6379 @ yewu01 10.174.249.145 6379 6480:X 14 Feb 19:47:26.148 # +sdown slave 10.173.244.98:6379 10.173.244.98 6379 @ yewu01 10.174.249.145 6379
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    這是非failover執行者的Sentinel的日誌:

    30052:X 14 Feb 19:46:54.725 # +sdown master yewu01 10.173.244.98 6379 30052:X 14 Feb 19:46:54.816 # +new-epoch 1 30052:X 14 Feb 19:46:54.823 # +vote-for-leader 214bd3df8363327488cd8c430166cf48cd2ab33a 1 30052:X 14 Feb 19:46:55.584 # +config-update-from sentinel 214bd3df8363327488cd8c430166cf48cd2ab33a 10.251.22.210 26379 @ yewu01 10.173.244.98 6379 30052:X 14 Feb 19:46:55.584 # +switch-master yewu01 10.173.244.98 6379 10.174.249.145 6379 30052:X 14 Feb 19:46:55.584 * +slave slave 10.251.22.210:6379 10.251.22.210 6379 @ yewu01 10.174.249.145 6379 30052:X 14 Feb 19:46:55.584 * +slave slave 10.173.244.98:6379 10.173.244.98 6379 @ yewu01 10.174.249.145 6379 30052:X 14 Feb 19:47:25.602 # +sdown slave 10.173.244.98:6379 10.173.244.98 6379 @ yewu01 10.174.249.145 6379
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    日誌顯示,其中一個Slave被提高爲了Master

  2. failover後配置被變動

    Sentinel首先經過命令的方式來作redis-serversentinel的配變動。以後會將配置持久化到redis.confsentinel.conf文件中。

    1. redis.conf中 
      被選爲Master的,其slaveof鍵值被直接刪除; 
      仍然仍是Slave的,其slaveof值被指定爲新Master的地址;

    2. 全部Sentinel的sentinel.conf中 
      sentinel monitor 被指定爲新Master的地址;

      // epoch 「時期」(版本的意思)被自增1 sentinel current-epoch 1
      • 1
      • 2

4. Jedis操做

顯然,通過故障轉移後,主從結構已經發生了改變且主已經死亡,若是還按照以前那樣寫死IP的方式鏈接Redis的話,勢必會出現錯誤。能夠想到,在Sentinel結構下,你必須向哨兵詢問來獲取誰是Master

private static final JedisSentinelPool pool; static { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxTotal(10); jedisPoolConfig.setMaxIdle(5); jedisPoolConfig.setMinIdle(5); Set<String> sentinels = new HashSet<>(Arrays.asList( "111.111.111.111:26379", "111.111.111.112:26379", "111.111.111.113:26379" )); GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); poolConfig.setMaxTotal(10); poolConfig.setMaxIdle(5); poolConfig.setMinIdle(5); pool = new JedisSentinelPool("yewu01", sentinels, jedisPoolConfig); } public static void main(String[] args) throws Exception { String key1 = "key1"; try (Jedis jedis = pool.getResource()) { jedis.set(key1, "222"); System.out.println(jedis.get(key1)); } catch (Exception e) { e.printStackTrace(); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

以上。

相關文章
相關標籤/搜索