和Mysql主從複製的緣由同樣,Redis雖然讀取寫入的速度都特別快,可是也會產生讀壓力特別大的狀況。爲了分擔讀壓力,Redis支持主從複製,Redis的主從結構能夠採用一主多從或者級聯結構,Redis主從複製能夠根據是不是全量分爲全量同步和增量同步。下圖爲級聯結構。 redis
全量同步
Redis全量複製通常發生在Slave初始化階段,這時Slave須要將Master上的全部數據都複製一份。具體步驟以下:
- 從服務器鏈接主服務器,發送SYNC命令;
- 主服務器接收到SYNC命名後,開始執行BGSAVE命令生成RDB文件並使用緩衝區記錄此後執行的全部寫命令;
- 主服務器BGSAVE執行完後,向全部從服務器發送快照文件,並在發送期間繼續記錄被執行的寫命令;
- 從服務器收到快照文件後丟棄全部舊數據,載入收到的快照;
- 主服務器快照發送完畢後開始向從服務器發送緩衝區中的寫命令;
- 從服務器完成對快照的載入,開始接收命令請求,並執行來自主服務器緩衝區的寫命令;sql
完成上面幾個步驟後就完成了從服務器數據初始化的全部操做,從服務器此時能夠接收來自用戶的讀請求。數據庫
增量同步
Redis增量複製是指Slave初始化後開始正常工做時主服務器發生的寫操做同步到從服務器的過程。
增量複製的過程主要是主服務器每執行一個寫命令就會向從服務器發送相同的寫命令,從服務器接收並執行收到的寫命令。
Redis主從同步策略
主從剛剛鏈接的時候,進行全量同步;全同步結束後,進行增量同步。固然,若是有須要,slave 在任什麼時候候均可以發起全量同步。redis 策略是,不管如何,首先會嘗試進行增量同步,如不成功,要求從機進行全量同步。
注意點
若是多個Slave斷線了,須要重啓的時候,由於只要Slave啓動,就會發送sync請求和主機全量同步,當多個同時出現的時候,可能會致使Master IO劇增宕機。編程
Redis主從複製的配置十分簡單,它可使從服務器是主服務器的徹底拷貝。須要清除Redis主從複製的幾點重要內容:json
1
2
3
4
5
6
7
8
9
10
11
|
1)Redis使用異步複製。但從Redis 2.8開始,從服務器會週期性的應答從複製流中處理的數據量。
2)一個主服務器能夠有多個從服務器。
3)從服務器也能夠接受其餘從服務器的鏈接。除了多個從服務器鏈接到一個主服務器以外,多個從服務器也能夠鏈接到一個從服務器上,造成一個
圖狀結構。
4)Redis主從複製不阻塞主服務器端。也就是說當若干個從服務器在進行初始同步時,主服務器仍然能夠處理請求。
5)主從複製也不阻塞從服務器端。當從服務器進行初始同步時,它使用舊版本的數據來應對查詢請求,假設你在redis.conf配置文件是這麼配置的。
不然的話,你能夠配置當複製流關閉時讓從服務器給客戶端返回一個錯誤。可是,當初始同步完成後,須要刪除舊的數據集和加載新的數據集,在
這個短暫的時間內,從服務器會阻塞鏈接進來的請求。
6)主從複製能夠用來加強擴展性,使用多個從服務器來處理只讀的請求(好比,繁重的排序操做能夠放到從服務器去作),也能夠簡單的用來作數據冗餘。
7)使用主從複製能夠爲主服務器免除把數據寫入磁盤的消耗:在主服務器的redis.conf文件中配置「避免保存」(註釋掉全部「保存「命令),而後鏈接一個配
置爲「進行保存」的從服務器便可。可是這個配置要確保主服務器不會自動重啓(要得到更多信息請閱讀下一段)
|
1
2
3
4
5
6
7
8
9
10
11
|
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服務器上的數據也被清空;
|
Redis大概主從同步是怎麼實現的?緩存
1
2
3
4
5
6
7
8
9
10
11
12
|
全量同步:
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服務器從而達到數據一致。
|
1
2
3
4
5
6
7
8
9
10
11
12
|
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。
|
1
2
3
4
5
6
7
8
9
10
11
12
|
在進行主從複製設置時,強烈建議在主服務器上開啓持久化,當不能這麼作時,好比考慮到延遲的問題,應該將實例配置爲避免自動重啓。
爲何不持久化的主服務器自動重啓很是危險呢?
爲了更好的理解這個問題,看下面這個失敗的例子,其中主服務器和從服務器中數據庫都被刪除了。
設置節點A爲主服務器,關閉持久化,節點B和C從節點A複製數據。
這時出現了一個崩潰,但Redis具備自動重啓系統,重啓了進程,由於關閉了持久化,節點重啓後只有一個空的數據集。
節點B和C從節點A進行復制,如今節點A是空的,因此節點B和C上的複製數據也會被刪除。
當在高可用系統中使用Redis Sentinel,關閉了主服務器的持久化,而且容許自動重啓,這種狀況是很危險的。
好比主服務器可能在很短的時間就完成了重啓,以致於Sentinel都沒法檢測到此次失敗,那麼上面說的這種失敗的狀況就發生了。
若是數據比較重要,而且在使用主從複製時關閉了主服務器持久化功能的場景中,都應該禁止實例自動重啓。
|
1
2
3
4
5
6
7
8
9
10
11
12
|
若是設置了一個從服務器,在鏈接時它發送了一個SYNC命令,無論它是第一次鏈接仍是再次鏈接都沒有關係。
而後主服務器開始後臺存儲,而且開始緩存新鏈接進來的修改數據的命令。當後臺存儲完成後,主服務器把數據文件發送到從服務器,
從服務器將其保存在磁盤上,而後加載到內存中。而後主服務器把剛纔緩存的命令發送到從服務器。這是做爲命令流來完成的,而且
和Redis協議自己格式相同。
你能夠經過telnet本身嘗試一下。在Redis服務器工做時鏈接到Redis端口,發送SYNC命令,會看到一個批量的傳輸,而且主服務器接收
的每個命令都會經過telnet會話從新發送一遍。
當主從服務器之間的鏈接因爲某些緣由斷開時,從服務器能夠自動進行重鏈接。當有多個從服務器同時請求同步時,主服務器只進行一個後臺存儲。
當鏈接斷開又從新連上以後,通常都會進行一個完整的從新同步,可是從Redis2.8開始,只從新同步一部分也能夠。
|
1
2
3
4
5
6
7
8
9
10
|
從Redis 2.8開始,若是遭遇鏈接斷開,從新鏈接以後能夠從中斷處繼續進行復制,而沒必要從新同步。
它的工做原理是這樣:
主服務器端爲複製流維護一個內存緩衝區(
in
-memory backlog)。主從服務器都維護一個複製偏移量(replication offset)和master run
id
,
當鏈接斷開時,從服務器會從新鏈接上主服務器,而後請求繼續複製,假如主從服務器的兩個master run
id
相同,而且指定的偏移量在內存緩衝
區中還有效,複製就會從上次中斷的點開始繼續。若是其中一個條件不知足,就會進行徹底從新同步(在2.8版本以前就是直接進行徹底從新同步)。
由於主運行
id
不保存在磁盤中,若是從服務器重啓了的話就只能進行徹底同步了。
部分從新同步這個新特性內部使用PSYNC命令,舊的實現中使用SYNC命令。Redis2.8版本能夠檢測出它所鏈接的服務器是否支持PSYNC命令,不支持的
話使用SYNC命令。
|
1
2
3
4
|
一般來說,一個徹底從新同步須要在磁盤上建立一個RDB文件,而後加載這個文件以便爲從服務器發送數據。
若是使用比較低速的磁盤,這種操做會給主服務器帶來較大的壓力。Redis從2.8.18版本開始嘗試支持無磁盤的複製。
使用這種設置時,子進程直接將RDB經過網絡發送給從服務器,不使用磁盤做爲中間存儲。
|
1
2
3
4
5
6
7
8
9
10
|
主從複製的配置十分簡單:把下面這行加入到從服務器的配置文件中便可。
slaveof 192.168.1.1 6379
固然你須要把其中的192.168.1.1 6379替換爲你本身的主服務器IP(或者主機名
hostname
)和端口。另外你能夠調用SLAVEOF命令,
主服務器就會開始與從服務器同步。
關於部分從新同步,還有一些針對複製內存緩衝區的優化參數。查看Redis介質中的Redis.conf示例得到更多信息。
使用repl-diskless-
sync
配置參數來啓動無磁盤複製。使用repl-diskless-
sync
-delay 參數來配置傳輸開始的延遲時間,以便等待
更多的從服務器鏈接上來。查看Redis介質中的Redis.conf示例得到更多信息。
|
1
2
3
4
5
6
7
8
|
從Redis 2.6開始,從服務器支持只讀模式,而且是默認模式。這個行爲是由Redis.conf文件中的slave-
read
-only 參數控制的,
能夠在運行中經過CONFIG SET來啓用或者禁用。
只讀的從服務器會拒絕全部寫命令,因此對從服務器不會有誤寫操做。但這不表示能夠把從服務器實例暴露在危險的網絡環境下,
由於像DEBUG或者CONFIG這樣的管理命令仍是能夠運行的。不過你能夠經過使用rename-
command
命令來爲這些命令更名來增長安全性。
你可能想知道爲何只讀限制還能夠被還原,使得從服務器還能夠進行寫操做。雖然當主從服務器進行從新同步或者從服務器重啓後,
這些寫操做都會失效,仍是有一些使用場景會想從服務器中寫入臨時數據的,但未來這個特性可能會被去掉。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
從Redis 2.8版本開始,能夠配置主服務器鏈接N個以上從服務器才容許對主服務器進行寫操做。可是,由於Redis使用的是異步主從複製,
沒辦法確保從服務器確實收到了要寫入的數據,因此仍是有必定的數據丟失的可能性。
這一特性的工做原理以下:
1)從服務器每秒鐘
ping
一次主服務器,確認處理的複製流數量。
2)主服務器記住每一個從服務器最近一次
ping
的時間。
3)用戶能夠配置最少要有N個服務器有小於M秒的確認延遲。
4)若是有N個以上從服務器,而且確認延遲小於M秒,主服務器接受寫操做。
還能夠把這看作是CAP原則(一致性,可用性,分區容錯性)不嚴格的一致性實現,雖然不能百分百確保一致性,但至少保證了丟失的數據不會超過M秒內的數據量。
若是條件不知足,主服務器會拒絕寫操做並返回一個錯誤。
1)min-slaves-to-write(最小從服務器數)
2)min-slaves-max-lag(從服務器最大確認延遲)
|
====== 經過redis實現服務器崩潰等數據恢復 ======
因爲redis存儲在內存中且提供通常編程語言經常使用的數據結構存儲類型,因此常常被用於作服務器崩潰宕機的數據恢復處理。服務器能夠在某些指定過程當中將須要保存的數據以json對象等方式存儲到redis中,也就是咱們常說的快照,當服務器運行時讀取redis來判斷是否有待須要恢復數據繼續處理的業務。當一次業務處理結束後再刪除redis的數據便可。redis提供兩種將內存數據導出到硬盤實現數據備份的方法:安全