Redis主从复制、哨兵机制
一、主從架構
在Redis中,用戶可以通過執行SALVEOF命令或者設置salveof選項,讓一個服務器去復制(replicate)另一個服務器,我們稱呼被復制的服務器為主服務器(master),而對主服務器進行復制的服務器則被稱為從服務器(salve)
二、主從復制
和Mysql主從復制的原因一樣,Redis雖然讀取寫入的速度都特別快,但是也會產生讀壓力特別大的情況。為了分擔讀壓力,Redis支持主從復制,Redis的主從結構可以采用一主多從或者級聯結構,Redis主從復制可以根據是否是全量分為全量同步和增量同步。下圖為級聯結構。?
2.1?全量同步
Redis全量復制一般發生在Slave初始化階段,這時Slave需要將Master上的所有數據都復制一份。具體步驟如下:?
- 從服務器連接主服務器,發送SYNC命令;?
- 主服務器接收到SYNC命名后,開始執行BGSAVE命令生成RDB文件并使用緩沖區記錄此后執行的所有寫命令;?
- 主服務器BGSAVE執行完后,向所有從服務器發送快照文件,并在發送期間繼續記錄被執行的寫命令;?
- 從服務器收到快照文件后丟棄所有舊數據,載入收到的快照;?
- 主服務器快照發送完畢后開始向從服務器發送緩沖區中的寫命令;?
- 從服務器完成對快照的載入,開始接收命令請求,并執行來自主服務器緩沖區的寫命令;
?
完成上面幾個步驟后就完成了從服務器數據初始化的所有操作,從服務器此時可以接收來自用戶的讀請求。
2.2 增量同步
Redis增量復制是指Slave初始化后開始正常工作時主服務器發生的寫操作同步到從服務器的過程。?
增量復制的過程主要是主服務器每執行一個寫命令就會向從服務器發送相同的寫命令,從服務器接收并執行收到的寫命令。
2.3 Redis主從同步策略
主從剛剛連接的時候,進行全量同步;全同步結束后,進行增量同步。當然,如果有需要,slave 在任何時候都可以發起全量同步。redis 策略是,無論如何,首先會嘗試進行增量同步,如不成功,要求從機進行全量同步。
?
注意點
如果多個Slave斷線了,需要重啟的時候,因為只要Slave啟動,就會發送sync請求和主機全量同步,當多個同時出現的時候,可能會導致Master IO劇增宕機。
Redis主從復制的配置十分簡單,它可以使從服務器是主服務器的完全拷貝。需要清除Redis主從復制的幾點重要內容:
1)Redis使用異步復制。但從Redis 2.8開始,從服務器會周期性的應答從復制流中處理的數據量。
2)一個主服務器可以有多個從服務器。
3)從服務器也可以接受其他從服務器的連接。除了多個從服務器連接到一個主服務器之外,多個從服務器也可以連接到一個從服務器上,形成一個圖狀結構。
4)Redis主從復制不阻塞主服務器端。也就是說當若干個從服務器在進行初始同步時,主服務器仍然可以處理請求。
5)主從復制也不阻塞從服務器端。當從服務器進行初始同步時,假設你在redis.conf配置文件是這么配置的,它使用舊版本的數據來應對查詢請求。否則的話,你可以配置當復制流關閉時讓從服務器給客戶端返回一個錯誤。但是,當初始同步完成后,需要刪除舊的數據集和加載新的數據集,在這個短暫的時間內,從服務器會阻塞連接進來的請求。
6)主從復制可以用來增強擴展性,使用多個從服務器來處理只讀的請求(比如,繁重的排序操作可以放到從服務器去做),也可以簡單的用來做數據冗余。
7)使用主從復制可以為主服務器免除把數據寫入磁盤的消耗:在主服務器的redis.conf文件中配置“避免保存”(注釋掉所有“保存“命令),然后連接一個配置為“進行保存”的從服務器即可。但是這個配置要確保主服務器不會自動重啟(要獲得更多信息請閱讀下一段)
2.4 主從復制的一些特點:
1)采用異步復制;
2)一個主redis可以含有多個從redis;
3)每個從redis可以接收來自其他從redis服務器的連接;
4)主從復制對于主redis服務器來說是非阻塞的,這意味著當從服務器在進行主從復制同步過程中,主redis仍然可以處理外界的訪問請求;
5)主從復制對于從redis服務器來說也是非阻塞的,這意味著,即使從redis在進行主從復制過程中也可以接受外界的查詢請求,只不過這時候從redis返回的是以前老的數據,如果你不想這樣,那么在啟動redis時,可以在配置文件中進行設置,那么從redis在復制同步過程中來自外界的查詢請求都會返回錯誤給客戶端;(雖然說主從復制過程中對于從redis是非阻塞的,但是當從redis從主redis同步過來最新的數據后還需要將新數據加載到內存中,在加載到內存的過程中是阻塞的,在這段時間內的請求將會被阻,但是即使對于大數據集,加載到內存的時間也是比較多的);
6)主從復制提高了redis服務的擴展性,避免單個redis服務器的讀寫訪問壓力過大的問題,同時也可以給為數據備份及冗余提供一種解決方案;
7)為了編碼主redis服務器寫磁盤壓力帶來的開銷,可以配置讓主redis不在將數據持久化到磁盤,而是通過連接讓一個配置的從redis服務器及時的將相關數據持久化到磁盤,不過這樣會存在一個問題,就是主redis服務器一旦重啟,因為主redis服務器數據為空,這時候通過主從同步可能導致從redis服務器上的數據也被清空;
2.5 Redis大概主從同步是怎么實現的?
全量同步:
master服務器會開啟一個后臺進程用于將redis中的數據生成一個rdb文件,與此同時,服務器會緩存所有接收到的來自客戶端的寫命令(包含增、刪、改),當后臺保存進程處理完畢后,會將該rdb文件傳遞給slave服務器,而slave服務器會將rdb文件保存在磁盤并通過讀取該文件將數據加載到內存,在此之后master服務器會將在此期間緩存的命令通過redis傳輸協議發送給slave服務器,然后slave服務器將這些命令依次作用于自己本地的數據集上最終達到數據的一致性。
部分同步:
從redis 2.8版本以前,并不支持部分同步,當主從服務器之間的連接斷掉之后,master服務器和slave服務器之間都是進行全量數據同步,但是從redis 2.8開始,即使主從連接中途斷掉,也不需要進行全量同步,因為從這個版本開始融入了部分同步的概念。部分同步的實現依賴于在master服務器內存中給每個slave服務器維護了一份同步日志和同步標識,每個slave服務器在跟master服務器進行同步時都會攜帶自己的同步標識和上次同步的最后位置。當主從連接斷掉之后,slave服務器隔斷時間(默認1s)主動嘗試和master服務器進行連接,如果從服務器攜帶的偏移量標識還在master服務器上的同步備份日志中,那么就從slave發送的偏移量開始繼續上次的同步操作,如果slave發送的偏移量已經不再master的同步備份日志中(可能由于主從之間斷掉的時間比較長或者在斷掉的短暫時間內master服務器接收到大量的寫操作),則必須進行一次全量更新。在部分同步過程中,master會將本地記錄的同步備份日志中記錄的指令依次發送給slave服務器從而達到數據一致。
2.6 主從同步中需要注意幾個問題
1)在上面的全量同步過程中,master會將數據保存在rdb文件中然后發送給slave服務器,但是如果master上的磁盤空間有效怎么辦呢?那么此時全部同步對于master來說將是一份十分有壓力的操作了。此時可以通過無盤復制來達到目的,由master直接開啟一個socket將rdb文件發送給slave服務器。(無盤復制一般應用在磁盤空間有限但是網絡狀態良好的情況下)
2)主從復制結構,一般slave服務器不能進行寫操作,但是這不是死的,之所以這樣是為了更容易的保證主和各個從之間數據的一致性,如果slave服務器上數據進行了修改,那么要保證所有主從服務器都能一致,可能在結構上和處理邏輯上更為負責。不過你也可以通過配置文件讓從服務器支持寫操作。(不過所帶來的影響還得自己承擔哦。。。)
3)主從服務器之間會定期進行通話,但是如果master上設置了密碼,那么如果不給slave設置密碼就會導致slave不能跟master進行任何操作,所以如果你的master服務器上有密碼,那么也給slave相應的設置一下密碼吧(通過設置配置文件中的masterauth);
4)關于slave服務器上過期鍵的處理,由master服務器負責鍵的過期刪除處理,然后將相關刪除命令已數據同步的方式同步給slave服務器,slave服務器根據刪除命令刪除本地的key。
2.7 當主服務器不進行持久化時復制的安全性
在進行主從復制設置時,強烈建議在主服務器上開啟持久化,當不能這么做時,比如考慮到延遲的問題,應該將實例配置為避免自動重啟。
?
為什么不持久化的主服務器自動重啟非常危險呢?
為了更好的理解這個問題,看下面這個失敗的例子,其中主服務器和從服務器中數據庫都被刪除了。
?
設置節點A為主服務器,關閉持久化,節點B和C從節點A復制數據。
這時出現了一個崩潰,但Redis具有自動重啟系統,重啟了進程,因為關閉了持久化,節點重啟后只有一個空的數據集。
節點B和C從節點A進行復制,現在節點A是空的,所以節點B和C上的復制數據也會被刪除。
當在高可用系統中使用Redis Sentinel,關閉了主服務器的持久化,并且允許自動重啟,這種情況是很危險的。
比如主服務器可能在很短的時間就完成了重啟,以至于Sentinel都無法檢測到這次失敗,那么上面說的這種失敗的情況就發生了。
如果數據比較重要,并且在使用主從復制時關閉了主服務器持久化功能的場景中,都應該禁止實例自動重啟。
2.8 redis實現持久化的兩種方式
1)RDB方式(默認)
RDB方式的持久化是通過快照(snapshotting)完成的,當符合一定條件時Redis會自動將內存中的所有數據進行快照并存儲在硬盤上。進行快照的條件可以由用戶在配置文件中自定義,由兩個參數構成:時間和改動的鍵的個數。當在指定的時間內被更改的鍵的個數大于指定的數值時就會進行快照。RDB是redis默認采用的持久化方式,在配置文件中已經預置了3個條件:
- save 900 1????? #900秒內有至少1個鍵被更改則進行快照
- save 300 10???? #300秒內有至少10個鍵被更改則進行快照
- save 60 10000?? #60秒內有至少10000個鍵被更改則進行快照
可以存在多個條件,條件之間是"或"的關系,只要滿足其中一個條件,就會進行快照。 如果想要禁用自動快照,只需要將所有的save參數刪除即可。
Redis默認會將快照文件存儲在當前目錄(可CONFIG GET dir來查看)的dump.rdb文件中,可以通過配置dir和dbfilename兩個參數分別指定快照文件的存儲路徑和文件名。
Redis實現快照的過程
- Redis使用fork函數復制一份當前進程(父進程)的副本(子進程);
- 父進程繼續接收并處理客戶端發來的命令,而子進程開始將內存中的數據寫入硬盤中的臨時文件;
- 當子進程寫入完所有數據后會用該臨時文件替換舊的RDB文件,至此一次快照操作完成。
- 在執行fork的時候操作系統(類Unix操作系統)會使用寫時復制(copy-on-write)策略,即fork函數發生的一刻父子進程共享同一內存數據,當父進程要更改其中某片數據時(如執行一個寫命令 ),操作系統會將該片數據復制一份以保證子進程的數據不受影響,所以新的RDB文件存儲的是執行fork一刻的內存數據。
Redis在進行快照的過程中不會修改RDB文件,只有快照結束后才會將舊的文件替換成新的,也就是說任何時候RDB文件都是完整的。這使得我們可以通過定時備份RDB文件來實 現Redis數據庫備份。RDB文件是經過壓縮(可以配置rdbcompression參數以禁用壓縮節省CPU占用)的二進制格式,所以占用的空間會小于內存中的數據大小,更加利于傳輸。
除了自動快照,還可以手動發送SAVE或BGSAVE命令讓Redis執行快照,兩個命令的區別在于,前者是由主進程進行快照操作,會阻塞住其他請求,后者會通過fork子進程進行快照操作。 Redis啟動后會讀取RDB快照文件,將數據從硬盤載入到內存。根據數據量大小與結構和服務器性能不同,這個時間也不同。通常將一個記錄一千萬個字符串類型鍵、大小為1GB的快照文件載入到內 存中需要花費20~30秒鐘。 通過RDB方式實現持久化,一旦Redis異常退出,就會丟失最后一次快照以后更改的所有數據。這就需要開發者根據具體的應用場合,通過組合設置自動快照條件的方式來將可能發生的數據損失控制在能夠接受的范圍。如果數據很重要以至于無法承受任何損失,則可以考慮使用AOF方式進行持久化。
2)AOF方式
默認情況下Redis沒有開啟AOF(append only file)方式的持久化,可以在redis.conf中通過appendonly參數開啟:
appendonly yes
在啟動時Redis會逐個執行AOF文件中的命令來將硬盤中的數據載入到內存中,載入的速度相較RDB會慢一些。
開啟AOF持久化后每執行一條會更改Redis中的數據的命令,Redis就會將該命令寫入硬盤中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通過dir參數設置的,默認的文件名是appendonly.aof,可以通過appendfilename參數修改:
appendfilename appendonly.aof
配置redis自動重寫AOF文件的條件
auto-aof-rewrite-percentage 100? # 當目前的AOF文件大小超過上一次重寫時的AOF文件大小的百分之多少時會再次進行重寫,如果之前沒有重寫過,則以啟動時的AOF文件大小為依據
auto-aof-rewrite-min-size 64mb?? # 允許重寫的最小AOF文件大小
配置寫入AOF文件后,要求系統刷新硬盤緩存的機制
# appendfsync always?? # 每次執行寫入都會執行同步,最安全也最慢
appendfsync everysec?? # 每秒執行一次同步操作
# appendfsync no?????? # 不主動進行同步操作,而是完全交由操作系統來做(即每30秒一次),最快也最不安全
?
Redis允許同時開啟AOF和RDB,既保證了數據安全又使得進行備份等操作十分容易。此時重新啟動Redis后Redis會使用AOF文件來恢復數據,因為AOF方式的持久化可能丟失的數據更少
?
三、哨兵模式
在前面講的master/slave模式,在一個典型的一主多從的系統中,slave在整個體系中起到了數據冗余備份和讀寫分離的作用。當master遇到異常終端后,需要從slave中選舉一個新的master繼續對外提供服務,這種機制類似于在zk中通過leader選舉、kafka中可以基于zk的節點實現master選舉。所以在redis中也需要一種機制去實現master的決策,redis并沒有提供自動master選舉功能,而是需要借助一個哨兵來進行監控。
3.1 什么是哨兵
哨兵是一個獨立的進程,它的作用就是監控Redis系統的運行狀況,使用哨兵后的架構圖:
它的功能包括兩個:
?1. 監控master和slave是否正常運行。
?2. master出現故障時自動將slave數據庫升級為master。
哨兵單點問題
為了解決master選舉問題,又引出了一個單點問題,也就是哨兵的可用性如何解決,在一個一主多從的Redis系統中,可以使用多個哨兵進行監控任務以保證系統足夠穩定。此時哨兵不僅會監控master和slave,同時還會互相監控;這種方式稱為哨兵集群,哨兵集群需要解決故障發現、和master決策的協商機制問題。
3.2?master的故障發現
哨兵監控一個系統時,只需要配置監控master即可,哨兵會自動發現所有slave;當master出現故障宕機,等待指定時間后(默認是30秒),會自動進行切換。
sentinel節點會定期向master節點發送心跳包來判斷存活狀態,一旦master節點沒有正確響應,sentinel會把master設置為“主觀不可用狀態”,然后它會把“主觀不可用”發送給其他所有的sentinel節點去確認,當確認的sentinel節點數大于>quorum時,則會認為master是“客觀不可用”,接著就開始進入選舉新的master流程;但是這里又會遇到一個問題,就是sentinel中,本身是一個集群,如果多個節點同時發現master節點達到客觀不可用狀態,那誰來決策選擇哪個節點作為master呢?這個時候就需要從sentinel集群中選擇一個leader來做決策。而這里用到了一致性算法Raft算法、它和Paxos算法類似,都是分布式一致性算法。但是它比Paxos算法要更容易理解;Raft和Paxos算法一樣,也是基于投票算法,只要保證過半數節點通過提議即可。
3.3?配置實現哨兵監控:
在其中任意一臺服務器上創建一個sentinel.conf文件,文件內容如下:
port 6040sentinel monitor mymaster 192.168.11.131 6379 1# sentinel monitor name ip port quorum?其中name表示要監控的master的名字,這個名字是自己定義。ip和port表示master的ip和端口號。 最后一個1表示最低通過票數,也就是說至少需要幾個哨兵節點統一才可以。sentinel down-after-milliseconds mymaster 5000#表示如果5s內mymaster沒響應,就認為SDOWNsentinel failover-timeout mymaster 15000#表示如果15秒后,mysater仍沒活過來,則啟動failover,從剩下的slave中選一個升級為master3.4 兩種方式啟動哨兵
redis-sentinel sentinel.conf
redis-server /path/to/sentinel.conf --sentinel
?3.5?實操
?
+sdown:表示哨兵主管認為master已經停止服務了。
+odown:表示哨兵客觀認為master停止服務了。關于主觀和客觀,后面會給大家講解。接著哨兵開始進行故障恢復,挑選一個slave升級為master。
+try-failover:表示哨兵開始進行故障恢復。
+failover-end:表示哨兵完成故障恢復。
+slave:表示列出新的master和slave服務器,我們仍然可以看到已經停掉的master,哨兵并沒有清楚已停止的服務的實例,這是因為已經停止的服務器有可能會在某個時間進行恢復,恢復以后會以slave角色加入到整個集群中。?
總結
以上是生活随笔為你收集整理的Redis主从复制、哨兵机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 阿里云宝塔apache启动失败解决办法
- 下一篇: 计算器小程序设计