Redis深刻系列-0x017:Redis同步

概述

基礎的Redis同步使用很是簡單,配置主從同步可讓從節點徹底複製節點。無論主節點發生任何事,從節點會在連接斷開以後自動重連。redis

這個機制工做使用了三臺機子:數據庫

  • 當主節點和從節點鏈接的很好的時候,主節點經過發送主節點上接收並執行的命令流到從節點,從而保證從節點更新:客戶端寫、key過時或者回收等。
  • 當主從節點之間的鏈接斷開,好比網絡問題或者主從節點以爲超時,從節點將從新連接而且嘗試部分從新同步:這意味着他將從新同步在斷開連接以後流中的命令。
  • 當部分從新同步失敗之後,從節點將會請求一個徹底同步,這降火執行一個更加複雜的操做,主節點須要建立一個當前數據的鏡像,發送給從節點,而且在數據集發生改變的時候繼續發送命令流。

Redis默認使用高性能高延遲的異步複製,這是大部分Redis使用場景的天然複製模式。從節點按期異步的從主節點獲取大量的數據。緩存

能夠在客戶端使用WAIT命令來請求同步複製確認的數據。然而WATI命令只能確保指定數量的數據被複制到其餘實例:數據寫入依舊會在故障轉移或者因故障轉移的致使的緣由中丟失,取決於Redis持久化配置。你能夠查看Sentinel或者Redis Cluster文檔查看更多關於高可用和故障轉移的信息。接下來的文檔主要歸納Redis簡單的數據同步的一些基本的特徵。安全

接下來是一些關於Redis同步很重要的事實:網絡

  • Redis使用異步複製,從節點異步的從主節點獲取大量的數據。
  • 一個主節點能夠有多個從節點
  • 從節點能夠接受其餘從節點的鏈接,在鏈接不少從節點到同一個主節點以外,從節點也能夠鏈接到其餘從節點,相似級聯的方式。從Redis 4.0之後,全部的子從節點都將從主節點收到相同的複製流。
  • Redis同步在主節點是非堵塞的。這意味着主節點能夠繼續處理請求,當一個或者多個從節點作初始化數據同步或者增量同步的時候。
  • 同步在從節點也是非堵塞的。若是你在配置文件中配置好了,在從節點初始化同步的時候可使用舊版本的數據集去響應請求。除此以外,你也能夠配置Redis從節點在複製流來的的時候返回一個錯誤給客戶端,在初始化同步的時候,舊的數據集將被刪除,行的數據必須被加載。從節點將會在這個短暫時間窗口堵塞正在進來的鏈接(這將在巨大的數據集上花費長達許多秒的時間)。從Redis 4.0開始,刪除就數據將會在另外一個線程進行,可是加載新的初始化數據集依舊會在主線程執行,而且堵塞從節點。
  • 爲了擁有多個從節點去處理只讀請求(好比O(N)的慢查詢操做能夠由從節點分擔),同步是可伸縮的,也是安全可靠的。
  • 避免主節點將全部數據集寫入磁盤產生的損耗也是由辦法的:一個典型的技術是經過配置不讓主節點持久化數據到磁盤,而後配置從節點去作這件事,或者開始AOF。可是這個操做要很是當心,由於重啓住節點將清空數據集:若是此時從節點去同步它,將會讓從節點也清空。

當主節點的持久化關閉的時候,安全的同步數據

若是使用Redis同步,強烈建議在主節點和從節點都打開持久化。若是這由於擔憂延遲致使磁盤緩慢,實例應該經過修改配置,避免在重啓的時候自動重啓。
爲了更好的理解在持久化關閉的時候,自動重啓是很是危險的,檢查下面數據數據從主節點和從節點都消失的模式:併發

  • 咱們設置節點A做爲主節點,關閉持久化,節點B和C從A處同步數據。
  • 節點A奔潰,然而他有自動重啓系統,他將會自動重啓。然而,由於持久化關閉,因此主節點將會以空數據集重啓。
  • 節點B和C依舊從節點A複製數據,可是由於A是空的,因此他們也會將本身的數據同步爲空。

Redis Sentinel用來作高可用的時候,主節點上將會關閉持久化,同時也關閉自動重啓。好比主節點能夠快速重啓,快到Sentinel都來不及捕捉錯誤因此上面歸納的失敗的模式就發生了。less

任什麼時候候數據安全都是重要的是,當主節點使用同步並關閉持久化的時候,自動重啓也要被關閉異步

Redis同步是怎麼工做的

每個Redis主節點有一個同步ID,是一個巨大的位隨機字符串標記數據集。同時主節點也爲發送到從節點的同步流提供一個增加偏移量,爲了讓從節點更新數據集狀態。同步偏移量即便在沒有從節點;連接的時候也會增加,因此每一次都將產生一對:性能

Replication ID, offset

標記主機數據集精確的版本
當從節點鏈接到主節點的時候,他們使用PSYNC命令發送他們目前爲止執行的舊的同步ID和偏移量。這種方式下,主節點能夠值發送增加部分,然而,若是主節點沒有足夠的日誌備份,或者從節點使用了一個過去的同步ID,主節點沒法找到他,就會發生全量同步:這種狀況下,從節點將會獲得一個完成的數據複製集,重新開始。
更多全量同步工做的方式:
主節點開始一個後臺進程保存數據,產生一個RDB文件。同時開始緩存從客戶端來的全部寫命令。當後臺保存進程完成,主節點將會把數據文件發送給從節點,他保存在磁盤中,而後加載到內存。主節點也會立刻發送緩存命令到從節點。這將會以Redis協議自己相同的命令流格式完成。
你能夠足跡經過telnet嘗試。在服務店正在執行一些工做的時候鏈接Redis端口併發送SYNC命令。你能夠看到大部分的傳輸而且主節點收到的全部命令都會telnet中打印出來。事實上SYNC是一箇舊的協議,不在新的Redis實例上使用,可是依舊向後兼容的:他不容許從新增量同步,因此PSYNC用來代替他。ui

  • 就像已經說過的,從節點在主從節點由於某些斷開的時候自動從新鏈接。若是主節點同時接到多個從節點同步請求,他只會啓動一個單獨的線程去服務他們。

無盤同步

正常狀況下,一個全量同步須要建立一個RDB文件,而後從磁盤中讀取這個文件,再發送給從節點。

然而磁盤讀取是很是慢的,這將給主節點形成很是大的壓力。Redis 2.8.18之後支持無盤同步。在這種設置下,子進程能夠直接經過網絡發送RDB給從節點,從而避免使用磁盤當作中間存儲。

配置

配置Redis同步是很簡單的,添加如下命令到配置文件就能夠了:

slaveof 192.168.1.1 6379

固然你必須使用你主節點的IP和端口覆蓋192.168.1.1 6379參數。當你使用SLAVEOF命令的時候,主節點就會開始同步數據到從節點

固然還有一些參數用來開啓同步日誌,讓主節點加載到內存中去執行增量同步。能夠查看Redis發行版中的redis.conf文件查看更新信息。

無盤同步可使用repl-diskless-sync配置參數開啓。延遲傳輸從而等待更多子節點連接主節點可使用repl-diskless-sync-delay配置參數控制。更多栗子請查閱發行版中的redis.conf文件。

只讀的從節點

Read-only slave
Redis 2.6開始,從節點支持只讀模式,而且這是默認開啓的。這個行爲能夠用slave-read-only來控制,能夠在redis.conf修改,也可使用CONFIG SET來設置。

只讀的本身誒單拒絕全部的寫命令,因此不可能寫入從節點,由於會發生錯誤。這並不覺得這這個特性是爲了在不被信任的網絡和客戶端中暴露本身,由於管理命令,好比像DEBUGCONFIG之類的依舊可使用。固然,只讀實例的安全性能夠經過在redus.conf中的rename-command禁用命令來提高。

你可能會想爲何要容許只讀的從節點實例能夠被改成可寫的。這些寫入的數據將會被主節點再次同步數據的時候刪除,這裏有幾個合理的用戶場景來講明爲何要短暫的在可寫從節點存儲數據。

好比統計慢Set或者Sorted Set操做,並存儲他們到本地,這是一個可寫從節點很常見的用戶場景

然而,要記住,4.0之前的可寫從節點沒辦法作到key的過時時間設置,這意味着,若是你使用EXPIRE或者其餘命令去設置一個key最大的TTL,這個key將會泄露,你將沒法使用讀命令找到他,你將會在key的統計中看到他,而且他依舊佔據着內存。因此,在一般狀況下可寫從節點使用TTL將會致使問題(4.0版本之前)。

Redis 4.0 RC3和更新的版本徹底解決了這個發生在key寫入超過63個數據庫的問題(可是默認狀況下Redis實例只有16個數據庫),而且如今可寫從節點能夠像主節點同樣驅逐過時的key

一樣須要記住的是從Redis4.0之後,從節點寫入的數據只存在本地,不會傳播到鏈接到該子節點的子從節點,子從節點接收到的同步流將會和最高的主節點發送給中間節點如出一轍。下面是栗子:

A ---> B ---> C

即便B是可寫的,C也不會看到B寫入的數據,只會看到A中的數據

設置從節點鏈接主節點時候的驗證

若是你的主節點經過requirepass配置屬性設置了密碼,設置從節點使用密碼同步也是很是簡單的:
使用redis-cli鏈接從節點,輸入:

config set masterauth <password>

爲了永遠記住他,添加到配置文件中:

masterauth <password>

只有N個從節點連接的時候才容許寫入

Redis 2.8之後,能夠設置主節點只有在有N臺從節點連接的時候能夠寫入請求。

然而,由於Redis使用的是異步複製,因此沒有辦法保證從節點確實收到的給定的寫入請求,縱遊一個窗口期的數據丟失。
接下來是解釋這個特性是如何工做的:
This is how the feature works:

  • 從節點每秒鐘都會ping主節點,告知它全部的複製流工做了。
  • 主節點會記住從每一個從節點收到的最新的ping
  • 用戶能夠給從節點配置一個在等於從節點的數量的最低值和不超過最高值之間的延遲

若是至少有N個從節點,若是少於延遲M秒,則寫入將被接受。
你可能以爲經最大努力保證數據安全的機制,雖然數據一致性沒法保證,可是至少只是幾秒的時間窗口內丟失數據。一般狀況下範圍數據丟失可比無範圍數據丟失好多了。
若是條件不知足,主節點將會返回一個錯誤,而且寫入請求將不被接受
下面是這個特性的兩個配置參數:

min-slaves-to-write <number of slaves>
min-slaves-max-lag <number of seconds>

查看更多信息,能夠查閱打包在Redis發行版中的redis.config

How Redis replication deals with expires on keys

Redis同步是如何解決key的過時的

Redis過時容許key有一個有限的生存時間。這種特性依賴於實例多時間的控制,從節點正確的複製key和過時,就是這些keylua修改過。

爲了實現這種特性,Redis不能信任主節點和從節點時鐘同步的能力,由於這沒法解決這個問題而且還會致使靜態條件和數據集分離,因此Redis使用三個主要技術來保證過時key的同步:

  • 從節點不讓key過時,而是等待主節點讓key過時。當主節點讓一個key過時(或者由於LRU被移除),它同步發往全部從節點的DEL命令。
  • 然而,由於只有主節點才執行過時操做,有些時候,從節點在內存中還保存這邏輯上已通過期的key,由於這時候主節點沒法提供一個DEL命令。爲了解決這個問題,從節點只用它本身的邏輯時鐘報告說這個key不存在,而且只供讀操做,並不去影響數據集的一致性(而後新的命令就會從主節點來)。這種方式下,從節點就避免了邏輯上過時的key還存在的問題。在真實的團推中,一個用從節點抓取的HTML片斷將會避免返回已經比指望存在時間多的緩存。
  • Lua腳本執行的時候,key將不會過時,當Lua腳本執行的時候,概念上來說,主節點的時間是中止的。因此一個key在腳本執行期間,要麼存在,要麼不存在。這防止key在腳本運行中間的時候過時,這也是爲了發送相同的腳本到全部的從節點,保證了對數據集的影響是一致的。

當一個從節點晉升爲主節點,他將會開始獨立的過時key,不須要舊的主節點的任何幫助。

DockerNAT中配置同步

當使用Docker或者其餘容器技術作端口轉發或網絡地址轉換的時候,Redis同步有一些須要額外注意,特別是使用Redis Sentinel或者其餘系統時,主節點INFOROLE命令須要輸出並掃描,用來發現從節點地址。

問題在ROLE命令,和同步章節的INFO輸出,當發送請求到主節點實例的時候,使用NAT的環境可能和從節點實例邏輯地址不一樣(能夠用來鏈接從節點的那個地址)。

一樣的,從節點將會被以配置文件中配置的監聽的端口列出,這可能會和轉發的端口不一樣,要注意端口可能被重映射。

爲了解決這個問題,從Redid 3.2.2開始,強制要求從節點聲明一個任意的IP和端口給主節點。這兩個配置指定是:

slave-announce-ip 5.5.5.5
slave-announce-port 1234

這被記錄在Redis發行版的redis.conf文件中。

INFOROLE命令

有兩個命令提供了不少關於主節點和從節點當前的同步參數。一個是INFO。若是這個命令被以INFO replication的方式調用,則只顯示和同步緊密相關的信息。另外一個更加計算機友好的命令是ROLE,提供了主節點和從節點同步的狀態,同步偏移,列出已鏈接的從節點等。

Redis 4.0之後支持重啓和故障轉移後的增量從新同步,當一個實例在故障轉之後提高爲主節點,他依舊能夠從舊的主節點那邊執行增量從新同步。爲了作到這一點,從節點記住了從前的主節點的的同步ID和偏移,因此,能夠提供部分的記錄去鏈接從節點,儘管他們請求的是舊的同步ID。

然而,晉升的從及誒單提供的新的同步ID將會不一樣,由於他構建了一個不一樣的數據集歷史。好比,有時候,主節點能夠返回可使用而且能夠繼續接受寫入,因此在晉升的從節點使用相同的同步ID將會破壞規則,即一個同步ID和偏移對只標記一個數據集。
此外,當優雅關閉或者重啓的時候,從節點能夠存儲從主節點同步必須的信息到RDB文件中。這對升級頗有用,當必須的時候,最好在從節點使用SHUTDOWN命令去執行一個保存-退出操做。

相關文章
相關標籤/搜索