一、主從複製簡而言之爲將主redis的數據同步到從redis,達到主從數據一致。主從複製應用:java
二、怎樣設置主從?redis
a、在從redis中使用執行命令 slaveof host port [slaveof no one命令表示禁止和主機的同步]數據庫
b、在從redis的配置文件中配置slaveof host port服務器
三、主從複製原理spa
全量複製:slave鏈接上master時候,master將整個快照發給slave,slave加載快照的數據,此時爲全量複製.net
增量複製:master每次接收到在本身數據庫的寫操做,同時會把寫命令傳給slave日誌
因爲全部的寫操做都是先在Master上操做,而後同步更新到Slave上,因此從Master同步到Slave機器有必定的延遲,當系統很繁忙的時候,延遲問題會更加嚴重,Slave機器數量的增長也會使這個問題更加嚴重。code
四、常見問題blog
-->從頭開始複製,不是從切入點(建立從的時間),主從數據保持一致了部署
-->從機通常配置爲slave-read-only yes,即爲不可set,只能夠讀
-->從機不上位,原地待命
-->主機回來後仍是主機身份,主機新增,從機仍然順利複製
-->若是經過命令slaveof設置的主從,重新啓動從機後身份會變成主機,須要重新用命令設置爲原來主機的從機,那麼此時數據就同步了;
若是是經過當前從機的配置文件配置的,那麼啓動後仍然是從機,且數據是同步的
-->清空全部數據,並與新主機的數據同步
五、哨兵模式
監控主機是否發生故障,若是發生了故障,根據投票數自動將從機切換爲主機。一個哨兵能夠同時監控多個主機。
新建配置sentinel.conf文件,並添加內容(這裏是最簡化的配置):
sentinel monitor 被監控主機名字(隨意) 127.0.0.1(主機的IP) 6379(主機redis的端口號) 1(至少1 個 Sentinel 贊成才進行故障切換)
啓動哨兵:redis-sentinel sentinel.conf
a、每一個 Sentinel 以每秒鐘一次的頻率向它所知的主服務器、從服務器以及其餘 Sentinel 實例發送一個 PING 命令。
b、若是一個實例(instance)距離最後一次有效回覆 PING 命令的時間超過 down-after-milliseconds 選項所指定的值, 那麼這個實例會被 Sentinel 標記爲主觀下線。 一個有效回覆能夠是: +PONG 、 -LOADING 或者 -MASTERDOWN 。
c、若是一個主服務器被標記爲主觀下線, 那麼正在監視這個主服務器的全部 Sentinel 要以每秒一次的頻率確認主服務器的確進入了主觀下線狀態。
d、若是一個主服務器被標記爲主觀下線, 而且有足夠數量的 Sentinel (至少要達到配置文件指定的數量)在指定的時間範圍內贊成這一判斷, 那麼這個主服務器被標記爲客觀下線。
e、在通常狀況下, 每一個 Sentinel 會以每 10 秒一次的頻率向它已知的全部主服務器和從服務器發送 INFO 命令。 當一個主服務器被 Sentinel 標記爲客觀下線時, Sentinel 向下線主服務器的全部從服務器發送 INFO 命令的頻率會從 10 秒一次改成每秒一次。
f、當沒有足夠數量的 Sentinel 贊成主服務器已經下線, 主服務器的客觀下線狀態就會被移除。 當主服務器從新向 Sentinel 的 PING 命令返回有效回覆時, 主服務器的主管下線狀態就會被移除。
假設127.0.0.1 6379 6380 6381三個端口分別啓動了redis服務,6380爲master,其它爲slave,而後啓動哨兵(只監控一個master)
哨兵的日誌:
2793:X 19 Aug 02:02:42.868 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128. 2793:X 19 Aug 02:02:42.883 # Sentinel ID is bfbd85c34ae2f4d8f0cd584dda8a90bb44ebe7af 2793:X 19 Aug 02:02:42.883 # +monitor master host6379 127.0.0.1 6380 quorum 1 【監視主機】 2793:X 19 Aug 02:02:42.884 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ host6379 127.0.0.1 6380 【sentinel識別到的從機6379】 2793:X 19 Aug 02:02:42.885 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ host6379 127.0.0.1 6380 【sentinel識別到的從機6381】
關閉6380的服務,日誌:
2820:X 19 Aug 02:21:32.136 # +sdown master host6379 127.0.0.1 6380 【主觀下線】 2820:X 19 Aug 02:21:32.136 # +odown master host6379 127.0.0.1 6380 #quorum 1/1 【客觀下線】 2820:X 19 Aug 02:21:32.136 # +new-epoch 2 2820:X 19 Aug 02:21:32.136 # +try-failover master host6379 127.0.0.1 6380 2820:X 19 Aug 02:21:32.147 # +vote-for-leader bfbd85c34ae2f4d8f0cd584dda8a90bb44ebe7af 2 2820:X 19 Aug 02:21:32.147 # +elected-leader master host6379 127.0.0.1 6380 2820:X 19 Aug 02:21:32.147 # +failover-state-select-slave master host6379 127.0.0.1 6380 【故障轉移操做如今處於select-slave狀態-sentinel選擇能夠升級爲主的從機】 2820:X 19 Aug 02:21:32.206 # +selected-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ host6379 127.0.0.1 6380 【已經找到能夠升級爲主的從機】 2820:X 19 Aug 02:21:32.207 * +failover-state-send-slaveof-noone slave 127.0.0.1:6381 127.0.0.1 6381 @ host6379 127.0.0.1 6380【故障轉移操做如今處於send-slaveof-noone狀態-執行slaveof no one命令將從升級爲主】 2820:X 19 Aug 02:21:32.292 * +failover-state-wait-promotion slave 127.0.0.1:6381 127.0.0.1 6381 @ host6379 127.0.0.1 6380【故障轉移操做如今處於wait-promotion狀態-等待從升級爲主】 2820:X 19 Aug 02:21:32.853 # +promoted-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ host6379 127.0.0.1 6380 2820:X 19 Aug 02:21:32.853 # +failover-state-reconf-slaves master host6379 127.0.0.1 6380【故障轉移操做如今處於reconf-slaves狀態-從新配置院主機的全部從機】 2820:X 19 Aug 02:21:32.906 * +slave-reconf-sent slave 127.0.0.1:6379 127.0.0.1 6379 @ host6379 127.0.0.1 6380 2820:X 19 Aug 02:21:33.863 * +slave-reconf-inprog slave 127.0.0.1:6379 127.0.0.1 6379 @ host6379 127.0.0.1 6380 2820:X 19 Aug 02:21:33.863 * +slave-reconf-done slave 127.0.0.1:6379 127.0.0.1 6379 @ host6379 127.0.0.1 6380 2820:X 19 Aug 02:21:33.939 # +failover-end master host6379 127.0.0.1 6380【故障轉移操做順利完成。全部從服務器都開始複製新的主服務器了】 2820:X 19 Aug 02:21:33.939 # +switch-master host6379 127.0.0.1 6380 127.0.0.1 6381【配置變動,主服務器的 IP 和地址已經改變。 這是絕大多數外部用戶都關心的信息】 2820:X 19 Aug 02:21:33.940 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ host6379 127.0.0.1 6381 2820:X 19 Aug 02:21:33.940 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ host6379 127.0.0.1 6381 2820:X 19 Aug 02:22:03.944 # +sdown slave 127.0.0.1:6380 127.0.0.1 6380 @ host6379 127.0.0.1 6381
從日誌能夠看出,主機從6380切換到了6381。上面日誌也能夠當作一次故障轉移的步驟。
此時,啓動6380端口的服務,日誌:
2820:X 19 Aug 02:30:57.570 # -sdown slave 127.0.0.1:6380 127.0.0.1 6380 @ host6379 127.0.0.1 6381 2820:X 19 Aug 02:31:07.500 * +convert-to-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ host6379 127.0.0.1 6381
從日誌能夠看出,原主機down機後,再恢復時候,哨兵會將其做爲當前主機(6381)的從機使用
注:在故障切換的時候各個實例的配置文件和sentinel.conf配置文件會自動作出相應的修改
哨兵+主從複製保證了redis的高可用,一般爲保證哨兵的健壯性,將哨兵部署爲集羣,至少3個節點
a、爲何redis哨兵集羣不能爲2個節點?
若是哨兵集羣僅僅部署了個2個哨兵實例,Configuration: quorum = 1
+----+ +----+
| M1 |---------| R1 |
| S1 | | S2 |
+----+ +----+
master宕機,s1(哨兵1)和s2中只要有1個哨兵認爲master宕機就能夠執行切換,同時s1和s2中會選舉出一個哨兵來執行故障轉移。同時這個時候,也就是大多數(majority)哨兵都是運行的,可是若是整個M1和S1運行的機器宕機了,那麼哨兵只有1個了,此時就沒有majority來容許執行故障轉移,雖然另一臺機器還有一個R1,可是故障轉移不會執行。
b、經典的3節點哨兵模式:Configuration: quorum = 2,majority
+----+ +----+
| R2 | | R3 |
| S2 | | S3 |
+----+ +----+
若是M1所在機器宕機了,那麼三個哨兵還剩下2個,S2和S3能夠一致認爲master宕機,而後選舉出一個來執行故障轉移。同時3個哨兵的majority是2,因此還剩下的2個哨兵運行着,就能夠容許執行故障轉移
c、小結:每次一個哨兵要作主備切換,首先須要quorum數量的哨兵認爲odown,而後選舉出一個哨兵來作切換,這個哨兵還得獲得majority哨兵的受權,才能正式執行切換。若是quorum < majority,好比5個哨兵,majority就是3,quorum設置爲2,那麼就3個哨兵受權就能夠執行切換。可是若是quorum >= majority,那麼必須quorum數量的哨兵都受權,好比5個哨兵,quorum是5,那麼必須5個哨兵都贊成受權,才能執行切換
六、客戶端API鏈接使用redis
首先細讀redis.conf文件如下說明,正確配置redis.conf的bind、protect-mode並確認防火牆,不然會致使鏈接不上redis。
直連redis代碼:
package com; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.JedisSentinelPool; import java.util.HashSet; import java.util.Set; public class Main { public static void main(String[] args) { JedisPool jedisPool=new JedisPool("192.168.1.113", 6381); Jedis jedis=jedisPool.getResource(); Set<String> out=jedis.keys("*"); System.out.println(out); jedis.set("zhongguo","weida"); } }
首先細讀sentinel.conf文件如下說明,正確配置redis.conf的bind、protect-mode並確認防火牆,不然會致使鏈接不上redis。
經過哨兵鏈接redis代碼:
package com; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.JedisSentinelPool; import java.util.HashSet; import java.util.Set; public class Main { public static void main(String[] args) { Set<String> sentinels=new HashSet<String>(); sentinels.add("192.168.1.113:26379");//若是有多個哨兵,可繼續添加 JedisSentinelPool jedisSentinelPool=new JedisSentinelPool("host6379", sentinels); Jedis jedis=jedisSentinelPool.getResource(); Set<String> out=jedis.keys("*"); System.out.println(out); jedis.set("shoudu","beijing"); } }