當前位置:
首頁 > 最新 > redis複製功能

redis複製功能

引用文章:http://www.redis.cn/topics/replication.html

Redis官方網站:http://redis.io

基於Redis複製,使用和配置主從複製變得非常簡單,同時也使得Redis slave節點能精確複製Redis master節點的內容。每當slave與master間的連接斷開,slave都會自動重連master,無論斷開期間master發生什麼,slave都會嘗試讓自身成為master的精確副本。

這個系統運行依靠三個主要機制:

·當masterslave正常連接時,master會發送一系列命令流到slave節點,以此將自身數據集的改變應用於slave,如:客戶端寫入,key的過期與清除等

·masterslave間連接斷開(如網路問題,主從連接超時),此後slave重新連接上master並會進行部分重同步,也就是說,他只會嘗試同步斷開連接期間丟失的命令流

·當無法進行部分重同步時,slave會請求進行全量重同步;master需創建所有數據的快照,將至發送給slave,之後在數據集更改時持續發送命令流到slave

Redis默認使用非同步複製,特點:高延遲、高性能。

客戶端可使用「WAIT」命令來請求同步複製某些特定數據。但,WAIT命令只能確保在其他Redis實例中有指定數量的已確認副本:在故障轉移期間,由於不同原因的故障轉移或是由於Redis持久性的實際配置,故障轉移期間確認的寫入操作可能仍然會丟失。你可以查看Sentinel或Redis集群文檔,了解關於高可用性和故障轉移的更多信息。本文的其餘部分主要描述Redis基本複製功能的基本特性

以下是關於Redis 複製功能的幾個特性:

·Redis使用非同步複製。自Redis 2.8起,slave會以每秒一次的頻率向master報告複製流(replication stream)的處理進度。

·一個master可擁有多個slave

·不僅master可以有從伺服器,從伺服器也可以有自己的從伺服器,自Redis 4.0起,所有的sub-slave將會從master收到完全一樣的複製流。

·主從複製功能不會阻塞master,意味著master與一個或多個slave進行初次同步或部分重同步時,也可以繼續處理命令請求

·複製功能也不會阻塞slave,只要在redis.conf文件中進行了相應的設置,即使從伺服器正在進行初次同步,伺服器也可以使用舊版本的數據集來處理命令查詢,同時也可以配置成這樣:若slave與master間的複製流斷開時,slave向客戶端返回錯誤信息。不管怎麼配置,在從伺服器刪除舊版本數據集並載入新版本數據集的那段時間內,連接請求會被阻塞,自Redis 4.0開始,可以配置Redis使刪除舊數據集的操作在另一個不同的線程中進行,但是,載入新數據集的操作依然需要在主線程中進行並且會阻塞slave

·複製功能可用於數據冗餘(data redundancy),也可通過配置讓多個slave處理只讀命令請求來提升擴展性(scalability)(如O(N)複雜度的慢操作可以被下放到slave)

·可以使用複製來避免master節點將數據寫入磁碟造成的開銷:配置master配置文件關閉Redis master的持久化功能,然後slave配置為不定期保存或啟用AOF。但必須小心處理此配置,因為重新啟動的master節點是空數據集,若slave視圖與它同步,那麼這個slave也會被清空

當master關閉持久化功能時,複製的安全性問題

配置Redis複製功能時,強烈建議在masterslave中都啟用持久化。當不可能啟用時(如磁碟讀寫性能差而導致的延時問題),應配置實例以避免伺服器重新引導後Redis實例自動啟動(避免啟動空的master導致slave被清空)

可以嘗試還原以下場景:

1、我們設置節點A為master並關閉它的持久化設置,節點B和C從節點A複製數據。

2、節點A崩潰,但是他有一些自動重啟的系統可以重啟進程。但是由於持久化被關閉了,節點重啟後其數據集合為空。

3、節點B和節點C會從節點A複製數據,但是節點A的數據集是空的,因此複製的結果是它們會銷毀自身之前的數據副本。

使用Redis 哨兵模式(sentinel)實現高可用,且配置master的持久化功能為關閉,此時若允許自動重啟進程也很危險,如master可以重啟的足夠快以至於sentinel沒有探測到故障,因此上述場景也可能發生。

Redis複製功能工作原理

每個Redis master都有一個replication ID(一個較大的偽隨機數字元串,標記了一個給定的數據集)。每個master也持有一個偏移量,master將自己產生的複製流發送給slave時,發送多少個位元組的數據,自身的偏移量就會增加多少,目的是當有新的操作修改自己的數據集時,他可以以此更新slave的狀態。複製偏移量即使在沒有一個slave連接到master也會自增,所以基本每對給定的replicationID,offset都會標識一個master數據集的確切版本。

當slave連接到master,它們使用「PSYNC」命令發送它們記錄的舊的master replication ID和它們至今為止處理的偏移量。通過此種方式,master能僅發送slave所需的增量部分。但若master的緩衝區中沒有足夠的命令積壓緩衝記錄,或如果slave引用了不再知道的歷史記錄(replication ID),則會轉而進行一個全量重同步,此時slave會得到一個完整的數據集副本,從新開始同步。

下面是一個全量同步的細節:

Master開啟一個後台保存進程,用於生成RDB快照文件。同時它開始緩衝所有從客戶端收到的新的寫入命令。當後台保存RDB快照文件完成時,master將數據集文件傳輸給slave,slave將之保存在磁碟,載入到內存,然後master會發送所有緩衝命令給slave。這個過程以指令流的形式完成且與Redis協議本身格式相同。

可以使用telnet進行嘗試,在伺服器正在做一些工作的同時,連接到redis埠並發出「SYNC」命令,將會看到一個批量傳輸情況。且之後每個master接收到的命令都將在telnet會話中被重新發出。實際上「SYNC」是一個舊協議,在新的redis版本中已經不再被使用,但仍然向後兼容,但它並不允許部分重同步,替換命令是「PSYNC

之前說過,當主從之間的連接因為一些原因崩潰之後,slave 能夠自動重連。如果master收到了多個slave要求同步的請求,它會執行一個單獨的後台保存,以便於為多個slave服務.

無盤複製

一般一個全量重同步要求在磁碟上創建RDB文件,master發送給slave,slave從磁碟載入進內存,然後slave以此數據為基本進行數據同步。如果磁碟性能很低的話,這對master 是一個壓力很大的操作。Redis 2.8.18 是第一個支持無磁碟複製的版本。在此設置中,子進程直接發送RDB文件給slave,無需使用磁碟作為中間儲存介質

主從複製相關配置

啟用Redis slave的複製功能:

slaveofmasterIP/masterDOMAIN_NAMEmasterPORT

指定master的IP/域名、埠

masterauth master-password

指定master的認證秘鑰,默認沒有

slave-read-only yes

slave只讀模式,將短暫數據存儲在writable slave中還是有一些合理的用例的。如,計算slow Set或者Sorted Set的操作並將它們存儲在本地key中是多次觀察到的使用writable slave的用例。

但注意,4.0 版本之前的writable slaves不能用TTL來淘汰key。這意味著,如果你使用EXPIRE或者其他命令為key設置了最大TTL,你將會在鍵值計數(count of keys)中看到這個key,且它還在#內存中。所以總的來說,將writable slaves和設置過TTL的key混用將會導致問題。Redis 4.0 RC3及更高版本徹底解決了這個問題,現在writable slaves能夠像master一樣清除TTL過期的key了,#但DB編號大於63(默認Redis實例只有16個資料庫)的key除外。

另請注意,由於Redis 4.0 writable slaves 僅能本地,並且不會將數據傳播到與該實例相連的sub-slave上。sub-slave將總是接收與最頂層masterintermediate slaves發送的複製流相同的複製流。#所以例如在以下設置中:

A —> B> C

即使節點B是可寫的,C也不會看到B的寫入,而是將擁有和master實例A相同的數據集

repl-diskless-sync no/yes

新的從節點和重連後不能繼續備份的從節點,需要做所謂的「完全備份」,即將一個RDB文件從主節點傳送到從節點。這個傳送有以下兩種方式:

1)硬碟備份:redis主節點創建一個新的進程,用於把RDB文件寫到硬碟上。過一會兒,其父進程遞增地將文件傳送給從節點。

2)無硬碟備份:redis主節點創建一個新的進程,子進程直接把RDB文件寫到從節點的套接字,不需要用到硬碟。

在硬碟備份的情況下,主節點的子進程生成RDB文件。一旦生成,多個從節點可以立即排成隊列使用主節點的RDB文件。在無硬碟備份的情況下,一次RDB傳送開始,新的從節點到達後,需要等#待現在的傳送結束,才能開啟新的傳送。

若使用無硬碟備份,主節點會在開始傳送之間等待一段時間(可配置,以秒為單位),希望等待多個子站到達後並行傳送。

在硬碟低速而網路高速(高帶寬)情況下,無硬碟備份更好。

repl-diskless-sync-delay 5

當啟用無硬碟備份,伺服器等待一段時間後才會通過套接字向從節點傳送RDB文件,這個等待時間是可配置的。這一點很重要,因為一旦傳送開始,就不可能再為一個新到達的從節點服務。從節點#則要排隊等待下一次RDB傳送。因此伺服器等待一段時間以期更多的從節點到達。延遲時間以秒為單位,默認為5秒。要關掉這一功能,只需將它設置為秒,傳送會立即啟動

slave-serve-stale-data yes

當一個從節點失去與主節點的連接,或者正在與主節點同步,從節點可以有以下兩種行為:

1)若slave-serve-stale-data設置為yes(默認),從節點會繼續響應客戶端的請求,有可能數據是過時的,若正在進行第一次同步,數據集有可以是空的。

2)若slave-serve_stale-data設置為no,從節點會對除了(INFO和SLAVEOF)以外的所有命令返回「正在與主節點同步」。

repl-ping-slave-period 10

從節點以一個預先設置好的時間間隔向伺服器發送PING。這個時間間隔可以通過repl_ping_slave_period選項改變。默認值是10秒。

repl-timeout 60

接下來的選項為以下內容設置備份的超時時間:

1)從從節點的角度,同步期間的批量傳輸的I/O

2)從節點角度認為的主節點超時(數據,ping)

3)主節點角度認為的從節點超時(REPLCONF ACK pings)

確認這些值比定義的repl-ping-slave-period要大,否則每次主節點和從節點之間通信低速時都會被檢測為超時。

repl-disable-tcp-nodelay no

同步之後是否禁用從節點上的TCP_NODELAY?

若你選擇yes,redis會使用較少量的TCP包和帶寬向從節點發送數據。但這會導致在從節點增加一點數據的延時。linux內核默認配置情況下最多40毫秒的延時。

若選擇no,從節點的數據延時不會那麼多,但備份需要的帶寬相對較多。

默認情況下我們將潛在因素優化,但在高負載情況下或者在主從節點都跳的情況下,把它切換為yes是個好主意

repl-backlog-size 1mb

設置備份的backlog大小。backlog是一個緩衝區,當從節點斷開一段時間的情況時,它替從節點接收存儲數據,因此當從節點重連時,通常不需要完全備份,只需要一個部分同步就可以,即把從節#點斷開時錯過的一部分數據接收。Backlog越大,從節點可以斷開並稍後執行部分同步的斷開時間就越長。只要有一個從節點連接,就會立刻分配一個backlog

repl-backlog-ttl 3600

主節點有一段時間沒有與從節點連接,對應的backlog就會自動釋放。接下來這個選項用於配置釋放前等待的秒數,秒數從斷開的那一刻開始計算。值為表示不釋放。

slave-priority 100

默認優先順序是100。

從節點優先順序是可以從redis的INFO命令輸出中查到的一個整數。當主節點不能正常工作時,redis sentinel使用它來選擇一個從節點並將它提升為主節點。

低優先順序的從節點被認為更適合於提升,因此若有三個從節點優先順序分別是10,100,25,sentinel會選擇優先順序為10的從節點,因為它的優先順序最低。

然而優先順序值為的從節點不能升級為主節點,因此優先順序為的從節點永遠不會被redis sentinel提升。

==========防止主伺服器在異常(或不安全)情況下執行寫命令,可配置master的min-slaves-to-write和min-slaves-max-lag 10========

min-slaves-to-write 3

min-slaves-max-lag 10

主節點可以停止接受寫請求,當與它連接的從節點少於N個,滯後少於M秒。

N個從節點必須是在線狀態。

延遲的秒數必須

這一選項並不保證N個備份都會接受寫請求,但是會限制在指定秒數內由於從節點數量不夠導致的寫操作丟失的情況。

若想要至少3個從節點且延遲少於10秒,這樣寫:

min-slaves-to-write 3

min-slaves-max-lag 10

設置某一個為0表示禁用這一功能。

默認情況下default min-slaves-to-write設置為(禁用)而min-slaves-max-lag設置為10。

slave-announce-ip 5.5.5.5

slave-announce-port 1234

當使用Docker或其他類型的容器使用埠轉發或網路地址轉換時,Redis複製需要特別小心,特別是在使用Redis Sentinel或其他系統(其中掃描master INFO或ROLE命令的輸出情況以便於發現 #slave地址的)

問題是ROLE 命令和 INFO 輸出的複製部分在發布到 master 實例中時,將顯示 slave 具有的用於連接到 master 的 IP 地址,而在使用 NAT 的環境中,和 slave 實例的邏輯地址(客戶機用來 #連接 slave 的地址)相比較可能會不同。

類似地,slaves 將以 redis.conf 文件中監聽的埠為序列出,在重新映射埠的情況下,該埠可能與轉發的埠不同。

為了解決這兩個問題,從Redis 3.2.2 開始,可以強制一個 slave 向 master 通告一對任意的 IP 和埠

Redis複製如何處理key的過期

Redis過期機制能限制key的存活時間,此功能依賴於redis實例的時間計數器,但即使使用Lua腳本更改了這些key,Redis slave也能正常複製具有過期時間的key。

為實現此特性,Redis使用以下三種主要技術使過期的key的複製能夠正確工作(Redis不能依靠主從使用同步時鐘,因為這是一個無法解決的並且會導致race condition和數據集不一致的問題):

·slave無法讓key過期,只能等待master讓key過期。當master讓一個key過期(或由於LRU演算法將之清除)時,master會合成一個DEL命令並發送到所有slave。

·但由於這是master驅動的key過期行為,所以有時候master可能無法及時提供DEL命令,會導致slave內存中仍然存在邏輯上已經過期的key,為解決此問題,slave基於自己的時間計數器,向那些讀操作返回「此key不存在」的消息,直到從master接收到DEL命令(在不違反數據集一致性的前提下),如此便避免了客戶端能讀到邏輯過期key的問題。在實際應用中,使用slave 程序進行縮放的 HTML 碎片緩存,將避免返回已經比期望的時間更早的數據項(In practical terms, an HTML fragments cache that uses slaves to scale will avoid returning items that are already older than the desired time to live,這句話沒看太懂)

·在Lua腳本執行期間,不執行任何key過期操作。當一個Lua腳本運行是,理論上master的時間計數器是被凍結的,這樣腳本運行時,一個給定的key只有存在於不存在兩種選擇。時間被凍結後,能防止key在腳本運行期間過期,能保證相同腳本發送到slave後,master和slave二者的數據集中產生相同的效果

一旦slave被提升為master,他將獨自管理key的過期時間。

命令「INFO」和「ROLE」

INFO replication #只顯示與複製相關的信息

ROLE #提供 master 和 slave 的複製狀態以及它們的複製偏移量,連接的slaves列表等

·Master上使用命令「ROLE」

127.0.0.1:6379> role

1) "master"#當前角色

2) (integer) 1792#當前master複製偏移量,master和slave共享此偏移量,在部分重同步中,需要先獲取偏移量以便確認要重同步的部分,然後才能繼續進行部分重同步

3) 1) 1) "172.25.10.12"#slave IP

2) "6379"#slave PORT

3) "1792"#最後一個確認的複製偏移量

·slave上使用命令「ROLE」

127.0.0.1:6379> ROLE

1) "slave"#當前角色

2) "172.25.10.13" #master IP

3) (integer) 6379 #master PORT

4) "connected" #複製狀態,從master視角看複製狀態可以是:connect(實例需要連接到他的master),connecting(slave-master連接正在進#行),sync(master和slave正在嘗試同步),connected(slave在線)

5) (integer) 2954 #根據master複製偏移量,slave到目前為止接收到的數據量

·哨兵模式里使用命令「ROLE」

127.0.0.1:6379> ROLE

1) "sentinel"#當前角色

2) 1) "resque-master"

2) "html-fragments-master"

3) "stats-master"

4) "metadata-master"

重新啟動和故障轉移後的部分重同步

從Redis 4.0 開始,當一個實例在故障轉移後被提升為master時,它仍然能夠與舊master 的 slaves 進行部分重同步。為此,slave 會記住前任master的舊replication ID和複製偏移量,因此即使詢問舊的replication ID,其也可以將部分複製緩衝提供給連接的slave。

但,升級的slave的新replication ID將不同,因為它構成了數據集的不同歷史記錄。例如,master可以返回可用,並且可以在一段時間內繼續接受寫入命令,因此在被提升的slave中使用相同的replication ID將違反一對複製標識和偏移對只能標識單一數據集的規則。

另外,slave在關機並重新啟動後,能夠在RDB文件中存儲所需信息,以便與master進行重同步。這在升級的情況下很有用。當需要時,最好使用「SHUTDOWN」命令來執行slave的保存和退出操作。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 企鵝狗 的精彩文章:

TAG:企鵝狗 |