1. 程式人生 > >深入理解Redis的主從複製

深入理解Redis的主從複製

前言

主從複製,主機資料更新後根據配置和策略,自動同步到備機的master/slaver機制,Master以寫為主,Slave以讀為主。這樣從節點就可以起到兩個作用,第一就是當作主節點的資料備份,當主節點出現故障的時候從節點可以當作備用機器,並且保證資料沒有丟失。第二就是從節點可以分擔主節點大部分“讀”這個操作的流量。

一、Redis如何建立主從複製關係

在Redis中我們的例項可以劃分為主節點與從節點,也就是說對於一個Redis例項要麼是主節點(master),要麼是從節點(slave),只有這兩種情況,並且資料的複製是單向的,只能由主節點到從節點。

檢視例項是否主從複製狀態資訊命令為  : info replication

127.0.0.1:55975> info replication
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

從上面的資訊可以看出這個預設配置的Redis例項是一個主節點,並且沒有從節點。

這時如果另外一個埠號為6379的redis例項想要與這臺端口為55975的redis建立主從複製關係有幾種方式:

  • 直接在Redis的配置檔案中將slaveof {masterHost} {masterPort} 開啟,masterHost 與masterPort為對應主節點的ip與埠
  • 直接使用Redis命令  slaveof {masterHost} {masterPort} 
# Master-Slave replication. Use slaveof to make a Redis instance a copy of
# another Redis server. A few things to understand ASAP about Redis replication.
#
# 1) Redis replication is asynchronous, but you can configure a master to
#    stop accepting writes if it appears to be not connected with at least
#    a given number of slaves.
# 2) Redis slaves are able to perform a partial resynchronization with the
#    master if the replication link is lost for a relatively small amount of
#    time. You may want to configure the replication backlog size (see the next
#    sections of this file) with a sensible value depending on your needs.
# 3) Replication is automatic and does not need user intervention. After a
#    network partition slaves automatically try to reconnect to masters
#    and resynchronize with them.
#
slaveof 127.0.0.1 6397
127.0.0.1:55975> slaveof 127.0.0.1 6397
OK
127.0.0.1:55975> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:6
master_sync_in_progress:0
slave_repl_offset:143
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

這時這個執行在55975埠的Redis例項就為從節點了,並且可以看到由引數master_host與master_port知道它的主節點是誰。

建立了主從複製關係之後,我們在主Redis例項上操作的資料就會同步複製到從節點上來,如下圖。

127.0.0.1:6379> dbsize
(integer) 0
127.0.0.1:55975> dbsize
(integer) 0
127.0.0.1:6379> set hello lee
OK
127.0.0.1:55975> dbsize
(integer) 1
127.0.0.1:55975> keys *
1) "hello"
127.0.0.1:55975> get hello
"lee"

slaveof命令的用法還可以用來斷開主從複製

  • slaveof no one   : 當使用了這個命令,這時從節點就與主節點之間斷開復制了,並且從節點也晉升為主節點了
  • slave of {newMasterHost} {newMasterPort}   : 這個命令可以用來切換主節點,斷開舊主節點複製關係,建立新主節點複製複製關係。
127.0.0.1:55975> slaveof no one
OK
127.0.0.1:55975> info replication
# Replication
role:master
connected_slaves:0
master_repl_offset:5835
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

 主從複製注意事項

  • 從安全性考慮安全性考慮一般主節點都會設定密碼,也就是在配置檔案中將requirepass開啟,那麼從節點也必須在配置檔案中將masterauth配置開啟並且賦上正確的密碼,否則複製不成功

# Require clients to issue AUTH <PASSWORD> before processing any other
# commands.  This might be useful in environments in which you do not trust
# others with access to the host running redis-server.
#
# This should stay commented out for backward compatibility and because most
# people do not need auth (e.g. they run their own servers).
#
# Warning: since Redis is pretty fast an outside user can try up to
# 150k passwords per second against a good box. This means that you should
# use a very strong password otherwise it will be very easy to break.
#
requirepass 123456
# If the master is password protected (using the "requirepass" configuration
# directive below) it is possible to tell the slave to authenticate before
# starting the replication synchronization process, otherwise the master will
# refuse the slave request.
#
masterauth 123456
  • 不要修改從節點的slave-read-only屬性為 no ,因為這樣就可能導致主從節點資料不一致的情況。
#
# Since Redis 2.6 by default slaves are read-only.
#
# Note: read only slaves are not designed to be exposed to untrusted clients
# on the internet. It's just a protection layer against misuse of the instance.
# Still a read only slave exports by default all the administrative commands
# such as CONFIG, DEBUG, and so forth. To a limited extent you can improve
# security of read only slaves using 'rename-command' to shadow all the
# administrative / dangerous commands.
slave-read-only yes

Redis主從複製原理

當我們配置了slaveof {masterHost} {masterPort} 或輸入了 slaveof {masterHost} {masterPort} 命令時,Redsi將會執行以下建立複製的流程:

  1. 儲存主節點資訊(如主機節點的 IP 以及 埠號)
  2. 與主節點建立socket連線 (建立成功日誌會打印出* Connecting to MASTER 127.0.0.1:6379[32500]    * MASTER <-> SLAVE sync started[32500] )表示連線成功
  3. 向主節點發送ping命令,若沒有收到主節點的pong回覆或者超時了就會每隔一秒輪詢重試,若主節點響應了則日誌會打印出(Master replied to PING, replication can continue...)
  4. 進行許可權的驗證(若主節點配置了requirepass屬性,則需要進行密碼的驗證,通過了則繼續)
  5. 同步資料
  6. 持續複製資料

這裡複製又分為全量複製與增量複製

全量複製我們redis從節點第一次與主節點建立複製關係時都是全量複製,這也是耗時最長的,因為第一次主節點要將自己全部的資料都發送的從節點,若主節點資料量龐大則每次都會佔用很大的網路資源,所以我們應該儘量避免全量複製。

增量複製:若主從複製由於網路等問題導致資料丟失的時候,主節點會補發丟失的資料給從節點,所以資源開銷遠遠小於全量複製,它的原理就是在主從複製的節點中都維護了一個複製偏移量與一個複製積壓緩衝區,主節點處理完寫入命令後會累加命令位元組長度並向複製積壓緩衝區寫入命令,從節點每秒也會上報自己的複製偏移量給主節點,這樣判斷主從節點的複製偏移量差值即可判斷資料是否一致,若不一致即用可使用緩衝區進行補救。

並且這裡Redis對複製偏移量還做了一定的保障措施,每個Redis節點每次啟動之後都會分配一個新的40位的16進位制的run_id,這樣可以用來讓從節點根據run_id知道自己複製的是哪個主節點的資料,若run_id改變了就表明是一個新的主節點,於是從節點就會開始全量複製。也就是說run_id保障的是若主節點進行了重啟或者替換了RDB\AOF檔案,從節點如果還是基於偏移量複製資料就會導致資料不正確。

全量複製的原理流程如下

  1. 從節點發送psync命令請求同步資料,因為是第一次複製沒有儲存複製偏移量與run_id,所以傳送的是psync?-1
  2. 主節點看到是psync?-1就知道是全量複製了,則回覆給從節點+FULLRESYNC響應給從節點
  3. 從節點接收主節點的run_id與偏移量
  4. 主節點進行bgsave,儲存最新的RDB到本地磁碟中
  5. 主節點發送RDB檔案給從節點
  6. 因為從節點接收RDB時,主節點還在響應新的命令,主節點會把這段時間的命令放入客戶端的緩衝區,從節點載入完RDB檔案之後再把緩衝區的內容發給從節點從而保證了資料的一致性
  7. 從節點清空舊資料
  8. 從節點載入主節點的RDB檔案
  9. 從節點載入完RDB檔案後,判斷從節點開啟了AOF持久化沒有,如果沒有則完成了全量複製,如果有則會bgrewriteaof。

Redis主從複製的集中叢集結構

  • 一主一從的結構

一般用來主節點掛了,從節點提供故障轉移

  • 一主多從的結構

這種用於讀的訪問量較大的場景,主Redis只用來作寫的操作,從Redis用來做讀的操作,實現讀寫分離,讓從redis幫主redis分擔更多的壓力

  • 樹型結構 

若主節點下面有多個從節點,也就是我們一主多從的結構時,當主節點重新啟動時,多個從節點都會同時發起請求全量複製,主節點同時給多個從節點發送RDB快照,就可能導致主節點的網路資源嚴重消耗、延遲變大,這時就可以考慮樹狀結構加入中間節點來保護主節點。

可能遇到的問題

配置了配置檔案中的slaveof {masterIp} {masterPort} 啟動redis的時候報錯

"Invalid argument during startup: unknown conf file parameter :  slaveof"

這裡的原因可能是將原來的配置檔案的#註釋去掉導致slaveof引數前面多了一個空格導致,將空格去掉即可

# Master-Slave replication. Use slaveof to make a Redis instance a copy of
# another Redis server. A few things to understand ASAP about Redis replication.
#
# 1) Redis replication is asynchronous, but you can configure a master to
#    stop accepting writes if it appears to be not connected with at least
#    a given number of slaves.
# 2) Redis slaves are able to perform a partial resynchronization with the
#    master if the replication link is lost for a relatively small amount of
#    time. You may want to configure the replication backlog size (see the next
#    sections of this file) with a sensible value depending on your needs.
# 3) Replication is automatic and does not need user intervention. After a
#    network partition slaves automatically try to reconnect to masters
#    and resynchronize with them.
#
 slaveof 127.0.0.1 6379    #這一行前面多了一個空格,導致報錯