1、主從複製簡而言之為將主redis的數據同步到從redis,達到主從數據一致。主從複製應用: 讀寫分離 容災備份 2、怎樣設置主從? 原則:配從不配主 方式: a、在從redis中使用執行命令 slaveof host port [slaveof no one命令表示禁止和主機的同步] b、在從r ...
1、主從複製簡而言之為將主redis的數據同步到從redis,達到主從數據一致。主從複製應用:
- 讀寫分離
- 容災備份
2、怎樣設置主從?
- 原則:配從不配主
- 方式:
a、在從redis中使用執行命令 slaveof host port [slaveof no one命令表示禁止和主機的同步]
b、在從redis的配置文件中配置slaveof host port
- 查詢主從信息:info replication
3、主從複製原理
全量複製:slave連接上master時候,master將整個快照發給slave,slave載入快照的數據,此時為全量複製
增量複製:master每次接收到在自己資料庫的寫操作,同時會把寫命令傳給slave
- 主從複製存在的問題:
由於所有的寫操作都是先在Master上操作,然後同步更新到Slave上,所以從Master同步到Slave機器有一定的延遲,當系統很繁忙的時候,延遲問題會更加嚴重,Slave機器數量的增加也會使這個問題更加嚴重。
4、常見問題
- 切入點問題?slave1、slave2是從頭開始複製還是從切入點開始複製?比如從k4進來,那之前的123是否也可以複製
-->從頭開始複製,不是從切入點(創建從的時間),主從數據保持一致了
- 從機是否可以寫?set可否?
-->從機一般配置為slave-read-only yes,即為不可set,只可以讀
- 主機shutdown後情況如何?從機是上位還是原地待命
-->從機不上位,原地待命
- 主機又回來了後,主機新增記錄,從機還能否順利複製?
-->主機回來後還是主機身份,主機新增,從機仍然順利複製
- 其中一臺從機down後情況如何?依照原有它能跟上大部隊嗎?
-->如果通過命令slaveof設置的主從,從新啟動從機後身份會變成主機,需要從新用命令設置為原來主機的從機,那麼此時數據就同步了;
如果是通過當前從機的配置文件配置的,那麼啟動後仍然是從機,且數據是同步的
- 如果從機中途變更主機,數據變化?
-->清空所有數據,並與新主機的數據同步
5、哨兵模式
- 什麼是哨兵模式?
監控主機是否發生故障,如果發生了故障,根據投票數自動將從機切換為主機。一個哨兵可以同時監控多個主機。
- 怎麼啟動哨兵?
新建配置sentinel.conf文件,並添加內容(這裡是最簡化的配置):
sentinel monitor 被監控主機名字(隨意) 127.0.0.1(主機的IP) 6379(主機redis的埠號) 1(至少1 個 Sentinel 同意才進行故障切換)
啟動哨兵:redis-sentinel sentinel.conf
- 每個哨兵(sentinel)定期執行的任務
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配置文件會自動做出相應的修改
- 多哨兵模式(來源博客https://blog.csdn.net/enlyhua/article/details/80544135)
哨兵+主從複製保證了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
+----+ | M1 | | S1 | +----++----+ +----+
| 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個哨兵都同意授權,才能執行切換
6、客戶端API連接使用redis
- 直連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"); } }
- 通過哨兵連接redis
首先細讀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"); } }