搞懂Redis複製原理

前言

  與大多數db同樣,Redis也提供了複製機制,以知足故障恢復和負載均衡等需求。複製也是Redis高可用的基礎,哨兵和集羣都是創建在複製基礎上實現高可用的。複製不只提升了整個系統的容錯能力,還能夠水平擴展,實如今一個重讀取的應用中,經過增長多個Redis只讀從實例來減輕主實例的壓力。html

  本文主要介紹Redis複製機制redis

 

一.配置與實踐

配置

  Redis實例分爲主節點(master)和從節點(slave),默認狀況下都是主節點。每個從節點只能有一個主節點,可是每個主節點能夠有多個從節點(注意數量,多個從節點會致使主節點寫命令屢次發送從而過分消耗網絡帶寬,可用樹狀結構下降主節點負載)。複製是單向的,只能從主節點複製到從節點。配置複製的方式由如下3種:網絡

  • 在redis-slave.conf配置文件中加入slaveof {masterHost} {masterPort}
  • 在redis-server啓動命令後加入 --slaveof {masterHost} {masterPort}
  • 啓動後直接使用命令slaveof {masterHost} {masterPort}

  綜上,Redis支持在啓動以前配置,也支持運行中動態配置。負載均衡

實踐

   咱們用動態配置的方法來配置,先起一個端口爲6379的Redis實例,做爲主節點:異步

redis-server /usr/local/Cellar/redis/4.0.9/.bottle/etc/redis.conf

  再起一個端口爲6380的Redis實例,做爲6379的從節點:spa

redis-server /usr/local/Cellar/redis/4.0.9/.bottle/etc/redis-slave.conf

  用客戶端連到從節點,使用slaveof命令,slaveof配置都是在從節點發起的。日誌

127.0.0.1:6380> slaveof 127.0.0.1 6379
OK

  從節點日誌:code

75585:S 06 May 16:27:50.389 * Connecting to MASTER 127.0.0.1:6379
75585:S 06 May 16:27:50.389 * MASTER <-> SLAVE sync started
75585:S 06 May 16:27:50.390 * Non blocking connect for SYNC fired the event.
75585:S 06 May 16:27:50.390 * Master replied to PING, replication can continue...
75585:S 06 May 16:27:50.390 * Trying a partial resynchronization (request 47770067272eb8101489fe7c00c8e838125c3aa3:1).
75585:S 06 May 16:27:50.392 * Full resync from master: e91e683b1e13332f97ecb9fa90ecdace460ab4ca:0
75585:S 06 May 16:27:50.392 * Discarding previously cached master state.
75585:S 06 May 16:27:50.491 * MASTER <-> SLAVE sync: receiving 215 bytes from master
75585:S 06 May 16:27:50.492 * MASTER <-> SLAVE sync: Flushing old data
75585:S 06 May 16:27:50.492 * MASTER <-> SLAVE sync: Loading DB in memory
75585:S 06 May 16:27:50.492 * MASTER <-> SLAVE sync: Finished with success

  主節點日誌:server

75553:M 06 May 16:27:50.391 * Slave 127.0.0.1:6380 asks for synchronization
75553:M 06 May 16:27:50.391 * Partial resynchronization not accepted: Replication ID mismatch (Slave asked for '47770067272eb8101489fe7c00c8e838125c3aa3', my replication IDs are '160af1c75f86edc50186e3e4a4dc6ecb5e3fa586' and '0000000000000000000000000000000000000000')
75553:M 06 May 16:27:50.391 * Starting BGSAVE for SYNC with target: disk
75553:M 06 May 16:27:50.391 * Background saving started by pid 75675
75675:C 06 May 16:27:50.395 * DB saved on disk
75553:M 06 May 16:27:50.490 * Background saving terminated with success
75553:M 06 May 16:27:50.491 * Synchronization with slave 127.0.0.1:6380 succeeded

  能夠看到,第一次創建複製關係的時候,主節點和從節點進行了一次全量複製,見圖:htm

  當完成複製的創建以後,接下來主節點會持續的把寫命令發送給從節點,保證主從數據一致。

  在主實例上添加新的key:

127.0.0.1:6379> set Lin 112131
OK

  在從實例查看剛剛添加的key:

127.0.0.1:6380> get Lin
"112131"

只讀

  因爲複製只能從主節點到從節點,對於從節點的數據修改主節點沒法感知,爲了不主從實例之間的數據不一致。從節點默認配置爲只讀模式:

slave-read-only yes

 

二.工做原理

  咱們先講3個比較關鍵的參數:master_replid、master_repl_offset和slave_repl_offset。咱們分別在master6379和slave6380上執行info replication

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=1093,lag=1 master_replid:e91e683b1e13332f97ecb9fa90ecdace460ab4ca
master_replid2:0000000000000000000000000000000000000000 master_repl_offset:1093
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1093


127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:9
master_sync_in_progress:0 slave_repl_offset:1107
slave_priority:100
slave_read_only:1
connected_slaves:0 master_replid:e91e683b1e13332f97ecb9fa90ecdace460ab4ca
master_replid2:0000000000000000000000000000000000000000 master_repl_offset:1107
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1107
  • master_replid是master啓動時生成的隨機字符串,用來標識主實例
  • master_repl_offset是複製流中的一個偏移量,master處理完寫入命令後,會把命令的字節長度作累加記錄,統計在該字段。該字段也是實現部分複製的關鍵字段。
  • slave_repl_offset一樣也是一個偏移量,從節點收到主節點發送的命令後,累加自身的偏移量,經過比較主從節點的複製偏移量能夠判斷主從節點數據是否一致。

  當從實例鏈接到主實例時,從實例會發送master_replid和master_repl_offset(標識與主實例同步的最後一個快照)請求部分複製。若是主實例接收部分複製的話則從最後一個偏移量開始增量進行部分複製,不然將進行全量複製。如圖:

 

三.數據同步

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

全量複製

  全量複製是Redis最先支持的複製方式,也是主從第一次創建複製的時候必須經歷的。它會把主節點所有數據一次性發送給從節點,當數據量較大的時候,會對主從節點和網絡形成很大開銷。主節點執行bgsave保存RDB文件,而後將這個文件發送給從節點,從節點收到RDB文件後,會先將內存中的全部數據清除,而後再將RDB文件中的數據導入。

  主實例在複製過程當中是徹底異步的,所以不會阻塞主節點的請求。在這一期間內主節點的全部寫入命令數據都保存在從客戶端緩衝區(slave client buffer)內,在從節點加載完RDB文件後,主節點會將這個緩衝區的內容發送給從節點。

  從客戶端緩衝區默認大小限制爲:

client-output-buffer-limit slave 256mb 64mb 60

  意思是若是60秒內緩衝區消耗持續大於64MB或者直接超過256MB時,主節點將直接關閉複製客戶端鏈接,形成全量同步失敗。

部分複製

  在高版本的Redis實現中,master_replid和offset存儲在RDB文件中。當從實例在複製過程當中,因網絡閃斷等緣由形成的數據丟失場景,Redis可以從rdb文件中從新加載master_replid和offset,從而使部分從新同步成爲可能。由於補發的數據遠小於全量數據,因此能夠有效的避免全量複製帶來的負載和消耗。

  以前說過,從節點鏈接主節點以後,會使用master_replid和master_repl_offset請求主節點,首先判斷master_replid是否和本身的master_replid一致,而後檢查請求中的master_repl_offset是否能從緩衝區(replication backlog)中獲取,若是偏移量在backlog範圍內,那麼能夠進行部分複製。若是在斷開鏈接期間主節點收到的寫入命令的數量超過了backlog緩衝區的容量,那麼會進行全量複製。默認狀況下backlog爲1MB。

 

 

 

 

參考

基本和redis篇第一個帖子同樣:

http://www.javashuo.com/article/p-eurptgyx-ds.html

相關文章
相關標籤/搜索