Redis主從同步及哨兵原理

 

一、複製過程redis

  複製過程大體分爲6個過程:數據庫

  流程圖以下:緩存

  

  1)保存主節點信息安全

    執行slaveof後從節點只保存主節點的地址信息便直接返回,這時創建複製流程尚未開始,在從節點執行info replication能夠看到以下信息:服務器

master_host:xxx
master_port:xxx
master_link_status:down

    從統計信息能夠看出,主節點的ip和port被保存下來,可是主節點的鏈接狀態master_link_status是下線狀態。執行slaveof後Redis會打印以下日誌:網絡

SLAVE OF 127.0.0.1:6379 enabled (user request from 'id=65 addr=127.0.0.1:58090
fd=5 name= age=11 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=
32768 obl=0 oll=0 omem=0 events=r cmd=slaveof')

  2)從節點內部經過每秒運行的定時任務維護複製相關邏輯,當定時任務發現存在新的主節點後,會嘗試與該節點創建網絡鏈接。從節點會創建一個socket套接字,專門用於接受主節點發送的複製命令。如鏈接成功,打印日誌以下:併發

* Connecting to MASTER 127.0.0.1:6379
* MASTER <-> SLAVE sync started

    若是從節點沒法創建鏈接,定時任務會無限重試直到鏈接成功或執行slaveof no one取消複製。less

    鏈接失敗,能夠在從節點執行info replication查看master_link_down_since_seconds指標,它會記錄與主節點鏈接失敗的系統時間。此時日誌以下socket

# Error condition on socket for SYNC: {socket_error_reason}

  3) 發送ping命令性能

    鏈接創建成功後從節點發送ping請求進行首次通訊,ping請求主要目的以下:

    - 檢測主從之間網絡套接字是否可用

    - 檢測主節點當前是否可接受處理命令

    若是發送ping命令後,從節點沒有收到主節點的pong回覆或者超時,好比網絡超時或者主節點正在阻塞沒法響應命令,從節點會斷開復制連接,下次定時任務時任務會重連。

    從節點與主節點創建鏈接流程如圖

    

    從節點發送ping命令流程

    

  4)權限驗證

    若是主節點設置了requirepass參數,則須要密碼驗證,從節點必須配置masterauth參數保證與主節點相同的密碼才能經過驗證;若是驗證失敗複製將終止,從節點從新發起復制流程。

  5)同步數據集

    主從複製連接正常通訊後,對於首次創建複製的場景,主節點會把持有的數據所有發送給從節點,這部分是耗時最長的步驟。Redis在2.8版本之後採用新複製命令psync進行數據同步,原來的sync命令也一樣支持,爲了新舊版本的兼容性。新同步劃分爲兩種狀況:全量同步和部分同步。

  6)命令持續複製

    當主節點把當前數據同步給從節點或,便完成了複製的創建流程,接下來主節點會持續地把寫命令發送給從節點,保證主從數據一致性。

 

二、數據同步

  Redis在2.8及以上版本使用psync命令完成主從數據同步,同步過程分爲全量複製和部分複製。

  全量複製:通常用於初次複製場景,Redis早期支持的複製功能只有全量複製,它會把從節點所有數據一次性發送給從節點,當數據較大時,會對主從節點和網絡形成很大的開銷。

  部分複製:用於處理在主從複製中因網絡閃斷等緣由形成的數據丟失場景,當從節點再次連上主節點後,若是條件容許,主節點會補發丟失數據給從節點。由於補發的數據遠遠小於全量數據,能夠有效避免全量複製的開銷。

  部分複製是對老版複製的重大優化,有效避免了沒必要要的全量複製操做。所以當使用複製功能時,儘可能採用2.8以上版本的Redis。

  psync命令運行須要如下組件支持:

  - 主從節點各自複製偏移量

  - 主節點複製積壓緩衝區

  - 主節點運行id

  1)複製偏移量

    參與複製的主從節點都會維護自身複製偏移量,主節點處理完寫入命令後,會把命令的字節長度作累加記錄,統計信息在info replication中的master_repl_offset指標中。

    從節點每秒上報自身的複製偏移量給主節點,所以主節點也會保存從節點的複製偏移量。都可以經過info replication查看。

127.0.0.1:6379> info replication # Replication role:master ... master_repl_offset:1055130

------------------------------------

127.0.0.1:6379> info replication connected_slaves:1 slave0:ip=127.0.0.1,port=6380,state=online,offset=1055214,lag=1

    從節點在接收到主節點發送的命令後,也會累加記錄自身的偏移量。統計信息在info replication中的slave_repl_offset指標中:

127.0.0.1:6380> info replication # Replication role:slave ... slave_repl_offset:1055214

    經過對比主從節點的複製偏移量,能夠判斷主從節點數據是否一致。

    提示:能夠經過主節點的統計信息,計算出master_repl_offset - slave_offset字節量,判斷主從節點複製相差的數據量,根據這個差值斷定當前複製的健康度。

  2)複製積壓緩衝區

    複製積壓緩衝區是保存在主節點上的一個固定長度的隊列,默認大小爲1MB,當主節點有鏈接的從節點時被建立,這時主節點響應寫命令時,不但會把命令發送給從節點,還會寫入複製積壓緩衝區。

    因爲緩衝區本質上是先進先出的定長隊列,因此能實現保存最近已複製數據的功能,用於部分複製和複製命令丟失的數據補救。複製緩衝區相關統計信息也保存在主節點的info replication中:

127.0.0.1:6379> info replication # Replication role:master ... repl_backlog_active:1 // 開啓複製緩衝區
repl_backlog_size:1048576 // 緩衝區最大長度
repl_backlog_first_byte_offset:7479 // 起始偏移量,計算當前緩衝區可用範圍
repl_backlog_histlen:1048576 // 已保存數據的有效長度。

  3)主節點運行ID

    每一個Redis節點啓動後都會動態分配一個40位的十六進制字符串做爲運行ID。運行ID的主要做用是用來惟一識別Redis節點,好比從節點保存主節點的運行ID識別本身正在複製的是哪一個主節點。若是隻使用ip+port的方式識別主節點,那麼主節點重啓變動了總體數據集(如替換RDB/AOF),從節點再基於偏移量複製數據將是不安全的,所以當運行ID變化後從節點將作全量複製。能夠運行info server命令查看當前節點的運行ID:

127.0.0.1:6379> info server # Server redis_version:3.0.7 ... run_id:545f7c76183d0798a327591395b030000ee6def9

    須要注意的是Redis關閉再啓動後,運行ID會隨之改變。Redis不改變ID重啓,可使用redis-cli debug reload

    注意:debug reload命令會阻塞當前Redis節點主線程,阻塞期間會生成本地RDB快照並清空數據以後再加載RDB文件,所以對於大數據量的節點和沒法容忍阻塞的應用場景,謹慎使用。

  4)psync命令

    從節點使用psync命令完成部分複製和全量複製功能,命令格式:psync {runid} {offset}

    - runid:從節點所複製主節點的運行id

    - offset:當前從節點已複製的數據偏移量

    psync運行流程

    

    流程說明:

    1)從節點發送psync命令給主節點,參數runid是當前從節點保存的主節點運行ID,參數offset是當前從節點保存的複製偏移量,若是是第一次複製則爲-1。

    2)主節點根據psync參數和自身數據狀況決定響應結果:

    - 若是回覆 FULLRESYNC {runid} {offset},那麼從節點觸發全量複製

    - 若是回覆CONTINUE,從節點將觸發部分複製流程

    - 若是回覆ERR,說明主節點版本低於2.8,沒法識別psync命令,從節點將發送舊版的sync命令觸發全量複製流程。

 

三、全量複製

  全量複製是Redis最先支持的複製方式,也是主從第一次創建複製時必須經歷的階段。觸發全量複製的命令是sync和psync。

  全量複製流程:

  

  流程說明:

  1)發送psync命令進行數據同步,因爲是第一次進行復制,從節點沒有複製偏移量和主節點的運行ID,全部發送psync-1

  2)主節點根據psync-1解析出當前爲全量複製,回覆+FULLRESYNC響應。

  3)從節點接收主節點的響應數據保存運行ID和偏移量offset,執行到當前步驟時從節點打印以下日誌:

Partial resynchronization not possible (no cached master) Full resync from master: 92d1cb14ff7ba97816216f7beb839efe036775b2:216789

  4)主節點執行bgsave保存RDB文件到本地,主節點bgsave相關日誌以下:

M * Full resync requested by slave 127.0.0.1:6380 M * Starting BGSAVE for SYNC with target: disk C * Background saving started by pid 32618 C * RDB: 0 MB of memory used by copy-on-write M * Background saving terminated with success

  提示:Redis 3.0以後在輸出的日誌開頭會有MSC等標識,對應的含義是:M=當前爲主節點日誌,S=當前爲從節點日誌,C=子進程日誌。

  save和bgsave的區別:save直接調用 rdbSave ,阻塞 Redis 主進程,直到保存完成爲止。在主進程阻塞期間,服務器不能處理客戶端的任何請求。BGSAVE 則 fork 出一個子進程,子進程負責調用 rdbSave ,並在保存完成以後向主進程發送信號,通知保存已完成。由於 rdbSave 在子進程被調用,因此 Redis 服務器在BGSAVE 執行期間仍然能夠繼續處理客戶端的請求。

  5)主節點發送RDB文件給從節點,從節點把接收的RDB文件保存在本地並直接做爲從節點的數據文件,接收完RDB後從節點能夠在日誌中查看主節點發送的數據量:

16:24:03.057 * MASTER <-> SLAVE sync: receiving 24777842 bytes from master

  注意:對於數據量大的主節點,好比生成的RDB文件超過6GB以上傳輸文件這一步操做很是耗時,速度取決於主從節點之間的網絡帶寬,針對數據量較大的節點,建議調大repl-timeout參數防止出現全量同步數據超時。

  關於無盤複製:爲了下降主節點的磁盤開銷,Redis支持無盤複製,生成的RDB文件不保存到硬盤而是直接經過網絡發送給從節點,經過repl-diskless-sync參數控制,默認關閉。無盤複製適用於主節點所在機器磁盤性能較差但網絡帶寬較充裕的場景。注意無盤複製目前依然處於試驗階段。

  6)對於從節點開始接收RDB快照到接收完成期間,主節點仍然響應讀寫命令,所以主節點會把這期間寫命令數據保存在複製客戶端緩衝區內,當從節點加載完RDB文件後,主節點再把緩衝區內的數據發送給從節點,保證主從之間數據一致性。若是主節點建立和傳輸RDB的時間過長,對於高流量寫入場景很是容易形成主節點複製客戶端緩衝區溢出。默認配置爲client-output-buffer-limit slave 256MB 64MB 60.若是60秒內緩衝區消耗持續大於64MB或者直接超過356MB時,主節點將直接關閉複製客戶端鏈接,形成全量同步失敗,日誌以下:

M 27 May 12:13:33.669 # Client id=2 addr=127.0.0.1:24555 age=1 idle=1 flags=S qbuf=0 qbuf-free=0 obl=18824 oll=21382 omem=268442640 events=r cmd=psync scheduled to be closed ASAP for overcoming of output buffer limits.

  所以須要根據主節點數據量和寫命令併發量調整client-output-buffer-limit slave配置,避免全量複製期間客戶端緩衝區溢出。

  7)從節點接收完主節點傳送來的所有數據後清空自身舊數據,該步驟對應以下日誌:

16:24:02.234 * MASTER <-> SLAVE sync: Flushing old data

  8)從節點清空數據後開始加載RDB文件,對於較大的RDB依然耗時。對於讀寫分離的場景,能夠設置slave-serve-stale-data參數爲no,關閉命令執行,在完成同步前不響應讀命令。

  9)從節點成功加載完RDB後,若是當前節點開啓了AOF持久化功能,它會馬上作bgrewriteaof操做,爲了保證全量複製後AOF持久化文件馬上可用。

  RDB和AOF區別:RDB是將Redis某一時刻的數據持久化到磁盤上,相似於快照;AOF是將redis執行過的全部寫指令記錄下來,在下次redis從新啓動時,只要把這些寫指令從前到後再重複執行一遍,就能夠實現數據恢復,默認每秒鐘fsync一次。

 

四、部分複製

  部分複製主要是Redis針對全量複製的太高開銷作出的一種優化措施,使用psync {runid} {offset}命令實現,當從節點正在複製主節點時,若是出現異常狀況,從節點要求補發丟失的命令數據,若是主節點的複製積壓緩衝區內存在這部分數據則直接發送給從節點,這樣就能夠保持主從節點複製的一致性。

  部分複製過程:

  

  流程說明:

  1)當主從節點之間網絡出現中斷時,若是超過repl-timeout時間,主節點會認爲從節點故障並中斷複製連接。

  2)主從鏈接中斷期間主節點依然響應命令,寫命令保存在複製積壓緩衝區,默認最大緩存1MB。

  3)當主從節點網絡恢復後,從節點會再次鏈接主節點。

  4)鏈接恢復後,因爲從節點保存了自身已複製的偏移量和主節點的運行ID,所以會把他們當作psync參數發送給主節點,要求進行部分複製操做。

  5)主節點接收到psync命令後首先覈對參數runid,若是一致,說明以前複製的是當前主節點,以後根據參數offset在自身複製積壓緩衝區查找,找到發送+CONTINUE響應。

  6)主節點根據偏移量把複製積壓緩衝區裏的數據發送給從節點,保證主從複製進入正常狀態。

 

五、哨兵模式

  Redis Sentinel經過三個定時監控任務完成對各個節點的發現和控制:

  1)每隔10秒,每一個sentinel節點會向主節點和從節點發送info命令獲取最新的拓撲結構。經過解析info replication能夠找到相應的從節點。此定時任務做用於三個方面:

  - 經過向主節點執行info命令,獲取從節點的信息。

  - 當有新的節點加入時,能夠馬上感知出來。

  - 節點不可達或者故障轉移後,能夠經過info命令實時更新節點拓撲信息。

  2)每隔2秒,每隔sentinel節點會向Redis數據節點的__sentinel__:hello頻道上發送該sentinel節點對於主節點的判斷以及當前sentinel節點的信息,同時每隔sentinel節點也會訂閱該頻道,來了解其餘sentinel節點以及他們對主節點的判斷,所以此任務主要做用以下:

  - 發現新的sentinel節點

  - sentinel節點之間交換主節點的狀態,做爲後面客觀下線以及領導者選舉的依據。

  3)每隔1秒,每隔sentinel節點會向主節點、從節點、其餘sentinel節點發送一條ping命令作一次心跳檢測。

 

六、Redis集羣

6.1 數據分佈

  Redis Cluster把數據集劃分到多個節點,每一個節點負責總體數據的一個子集。Redis Cluster槽範圍是0~16383,槽是集羣內數據管理和遷移的基本單位。採用大範圍槽的主要目的是爲了方便數據拆分和集羣擴展,每一個節點會負責必定數量的槽。

6.2 集羣功能限制

  1)key批量操做支持有限。如mset、mget,目前只支持具備相同slot值的key執行批量操做。對於映射爲不一樣slot值的key不被支持。

  2)key事務操做支持有限。同理只支持多key在同一節點上的事務操做,當多個key分佈在不一樣的節點上時沒法使用事務功能。

  3)key做爲數據分區的最小粒度,所以不能將一個大的鍵值對象如hash、list等映射到不一樣的節點。

  4)不支持多數據空間。單機支持16個數據庫,集羣只有db0。

  5)複製結構只支持一層。

相關文章
相關標籤/搜索