1. 程式人生 > >redis 系列22 復制Replication (下)

redis 系列22 復制Replication (下)

child 現在 against you 凍結 msg possible 心跳檢測 有一個

原文:redis 系列22 復制Replication (下)

一. 復制環境準備

  1.1 主庫環境(172.168.18.201)

環境

說明

操作系統版本 CentOS 7.4.1708
IP地址 172.168.18.201
網關Gateway 172.168.18.1
DNS 172.168.16.11
Redis版本和端口 4.0.6 和 6379
Redis 密碼 123456
是否RDB持久化 開啟
是否 AOF持久化 開啟

  1.2 從庫環境(172.168.18.203)

環境

說明

操作系統版本 CentOS 7.4.1708
IP地址 172.168.18.203
網關Gateway 172.168.18.1
DNS 172.168.16.11
Redis版本和端口 4.0.6 和 6379
Redis密碼 123456
是否RDB持久化 開啟
是否 AOF持久化 開啟
是否只讀庫 只讀

二. 復制配置

  2.1 主庫環境密碼設置

    在201主庫上,找到redis目錄下的redis.conf文件,打開文件找到requirepass,在500行,下面腳本修改,密碼為:123456

    -- 原腳本 
    500 # requirepass foobared
    -- 修改後
    500  requirepass 123456

    修改後,設置防為墻,重啟redis服務,重新登錄主服務器,客戶端連接成功,腳本如下:

    [root@hsr bin]# iptables -F
    [root@hsr bin]# ./redis-cli -h 172.168.18.201 -p 6379 -a 123456
    172.168.18.201:6379> config get requirepass 
    1) "requirepass
" 2) "123456"

    在slave從庫203上,使用203從庫的redis客戶端連接201主庫redis服務器,主從網絡連接沒有問題,連接成功,腳本如下:

    [root@hsr bin]# ./redis-cli -h 172.168.18.201 -p 6379 -a 123456
    172.168.18.201:6379> config get requirepass 
    1) "requirepass"
    2) "123456"

  2.2 主庫設置RDB持久化和AOF持久化

    redis服務器默認是使用的RDB持久化,下面是save自動保存的觸發條件點,以及rdb文件名, 腳本如下:

    172.168.18.201:6379> config get save
    1) "save"
    2) "900 1 300 10 60 10000"
    172.168.18.201:6379> config get dbfilename
    1) "dbfilename"
    2) "dump.rdb"

    修改redis.conf文件,開啟AOF持久化,在配置文件中找到appendonly將no改為yes, appendonly.aof 文件路徑默認產生在啟動所在的目錄,為./dir。緩沖區數據寫入磁盤也是默認模式Everysec ,相關腳本如下:

    -- 在672行開啟AOF
    672 appendonly  yes
    --  263行文件默認路徑
    263 dir ./

    --- 關閉redis服務,重啟後查看
    172.168.18.201:6379> config get appendonly
    1) "appendonly"
    2) "yes"

    172.168.18.201:6379> config get appendfsync
    1) "appendfsync"
    2) "everysec"
    -- 開啟後,持久化文件生成如下列表:
    [root@hsr bin]# ls -l
    總用量 11544
    -rw-r--r-- 1 root root      56 12月 11 14:27 appendonly.aof
    -rw-r--r-- 1 root root     108 12月 11 14:23 dump.rdb

  2.3 從庫配置

    從庫也一樣,設置密碼為123456, 設置防火墻,開啟AOF持久化,從庫默認是只讀模式。參考主庫設置,這裏就不再介紹,最後查看腳本如下:

    [root@xuegod64 redis]# redis-cli -h 172.168.18.203 -p 6379 -a     123456
    172.168.18.203:6379> config get appendonly
    1) "appendonly"
    2) "yes"
    172.168.18.203:6379> config get requirepass
    1) "requirepass"
    2) "123456"
    172.168.18.203:6379> config get slave-read-only
    1) "slave-read-only"
    2) "yes"

  2.4 啟動復制

    在從庫203上設置slaveof參數,讓一個從服務器去復制主服務器。下面修改從庫配置文件,先不用重啟redis服務,腳本如下:

    -- 將280行配置
    280 # slaveof <masterip> <masterport>
    -- 修改後如下,設置好對應的主庫ip和端口
    280 slaveof 172.168.18.201  6379

  2.5 設置身份驗證

    在從庫203上設置身份驗證 masterauth選項(slave 對 master 進行驗證),在需要進行身份驗證時,從服務器將向主服務器發送一條auth命令,命令的參數為從服務器masterauth選項的值。

    -- 將287行配置修改
    287 # masterauth <master-password>
    -- 修改後如下, 設置主庫的密碼為123456
    287 masterauth 123456
    -- 最後客戶端關閉從庫服務,重啟服務
    [root@xuegod64 redis]# redis-cli -h 172.168.18.203 -p 6379 -a 123456
    172.168.18.203:6379> shutdown
    not connected> exit
    [root@xuegod64 redis]# redis-server redis.conf

  

三.復制數據同步測試

  3.1 測試主從數據同步

    -- 在主庫201設置一個kev value, 腳本如下:
    172.168.18.201:6379> set repl "hello"
    OK
    -- 在從庫203上讀取主庫該key成功,腳本如下:
    172.168.18.203:6379> get repl
    "hello"

    -- 在主庫刪除該key,腳本如下:
    172.168.18.201:6379> del repl
    (integer) 1
    --在從庫上讀取該key,腳本如下:
    172.168.18.203:6379> get repl
    (nil)    

  3.2 測試從庫是否只讀

    --下面在從庫寫入一個key,錯誤信息如下:
    172.168.18.203:6379> set msg1 "hello"
    (error) READONLY You cant write against a read only slave.

  3.3 在從庫開啟了日誌記錄,查看redis.log文件,相關復制的信息如下:

19424:S 11 Dec 15:11:18.610 * Connecting to MASTER 172.168.18.201:6379
19424:S 11 Dec 15:11:18.610 * MASTER <-> SLAVE sync started
19424:S 11 Dec 15:11:18.611 * Non blocking connect for SYNC fired the event.
19424:S 11 Dec 15:11:18.612 * Master replied to PING, replication can continue...
19424:S 11 Dec 15:11:18.613 * Partial resynchronization not possible (no cached master)
19424:S 11 Dec 15:11:18.615 * Full resync from master: 0c208c84b99e1970721404abf88a92d80c50d0d2:0
19424:S 11 Dec 15:11:18.708 * MASTER <-> SLAVE sync: receiving 191 bytes from master
19424:S 11 Dec 15:11:18.708 * MASTER <-> SLAVE sync: Flushing old data
19424:S 11 Dec 15:11:18.708 * MASTER <-> SLAVE sync: Loading DB in memory
19424:S 11 Dec 15:11:18.708 * MASTER <-> SLAVE sync: Finished with success
19424:S 11 Dec 15:11:18.710 * Background append only file rewriting started by pid 19428
19424:S 11 Dec 15:11:18.748 * AOF rewrite child asks to stop sending diffs.
19428:C 11 Dec 15:11:18.748 * Parent agreed to stop sending diffs. Finalizing AOF...
19428:C 11 Dec 15:11:18.749 * Concatenating 0.00 MB of AOF diff received from parent.
19428:C 11 Dec 15:11:18.749 * SYNC append only file rewrite performed
19428:C 11 Dec 15:11:18.749 * AOF rewrite: 6 MB of memory used by copy-on-write
19424:S 11 Dec 15:11:18.812 * Background AOF rewrite terminated with success
19424:S 11 Dec 15:11:18.812 * Residual parent diff successfully flushed to the rewritten AOF (0.00 MB)
19424:S 11 Dec 15:11:18.812 * Background AOF rewrite finished successfully

四. 復制運行狀態參數信息

  4.1 主庫緩沖隊列信息

    緩沖隊列的大小默認是1MB,可以在redis.conf中的配置項repl-backlog-size進行設置,還有一個配置項repl-backlog-ttl,表示當主從斷開後,緩沖隊列的緩存時間。

    172.168.18.201:6379> config get repl-backlog-ttl
    1) "repl-backlog-ttl"
    2) "3600"

    172.168.18.201:6379> config get repl-backlog-size
    1) "repl-backlog-size"
    2) "1048576"

  4.2 info replication命令查看主庫當前復制狀態信息

172.168.18.201:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=172.168.18.203,port=6379,state=online,offset=3328,lag=1
master_replid:0c208c84b99e1970721404abf88a92d80c50d0d2
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:3328
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:3328

  4.3 info replication命令查看從庫當前復制狀態信息

172.168.18.203:6379> info replication
# Replication
role:slave
master_host:172.168.18.201
master_port:6379
master_link_status:up
master_last_io_seconds_ago:5
master_sync_in_progress:0
slave_repl_offset:3398
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:0c208c84b99e1970721404abf88a92d80c50d0d2
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:3398
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:3398

  註意:上一篇講到主從偏移量相同時,表示主從服務器處於一致狀態,反之則不一致。但這裏顯示的主從偏移量不一致,以後再了解。

  4.4 role命令查看主庫和從庫信息

    ROLE命令它提供 master 和 slave 的復制狀態以及它們的復制偏移量,連接的 slaves 列表等等。role輸出一個數組,第一個參數是 master, slave, sentinel 三個中的一個。

172.168.18.201:6379> role
1) "master"
2) (integer) 3594
3) 1) 1) "172.168.18.203"
      2) "6379"
      3) "3594"

172.168.18.203:6379> role
1) "slave"
2) "172.168.18.201"
3) (integer) 6379
4) "connected"
5) (integer) 3482

  

五. 復制的內部實現步驟

  5.1 客戶端設置主服務器的地址和端口

    從服務器首先將主服務器IP地址和端口保存到服務器狀態的redisserver結構下masterhost和masterport屬性中。

  5.2 建立套接字連接

    在slaveof命令執行之後,從服務器將根據命令所設置的ip地址和端口,創建連向主服務器的套接字連接:

    (1)如果從服務器成功連接到主服務器,那麽從服務器將為這個套接字關聯一個專門用於處理復制工作的文件事件處理器。執行的工作包括如接收RDB文件,主服務器傳播的寫命令等。

    (2)如果主服務器成功接受從服務器,將為該套接字創建相應的客戶端狀態,並將從服務器看作是一個連接到主服務器的客戶端來對待。這時從服務器將同時具有服務器和客戶端兩個身份。

  5.3 發送ping命令

    從服務器成為主服務器客戶端之後,做的第一件事就是向主服務器發送一個ping命令。該命令有兩個作用:

    (1) 雖然主從服務器成功建立起了套接字連接,但雙方並未使用該套接字進行過任何通信,通過發送ping命令可以檢查套接字的讀寫狀態是否正常。

    (2) 通過發送ping命令可以檢查主服務器能否正常處理命令請求。

    從服務器發送ping命令之後將遇到三種情況的其中一種:

    (1) 如果主服務器向從服務器返回了一個命令回復,但從服務器卻不能在規定的時限(timeout)內讀出命令回復內容,那麽表示主從服務器之間的網絡連接狀態不佳,這種情況,從服務器會斷開重新創建連向主服務器的套接字。

    (2) 如果主服務器向從服務器返回了一個錯誤,那麽從服務器會斷開並重新創建連向主服務器的套接字。

    (3) 如果主服務向從服務器成功回復,那麽網絡正常並且主服務器可以正常處理從服務器發送的命令請求。

  5.4 身份驗證

    從服務器收到主服務器返回的ping 回復後,接著決定是否進行身份驗證:

    (1) 如果從服務器設置了masterauth選項,那麽進行身份驗證。

    (2) 如果從服務器沒有設置masterauth選項,那麽不進行身份驗證。

    從服務器在身份驗證階級可以遇到的情況有以下幾種:

    (1)如果主服務器沒有設置requirepass選項, 從服務器也沒有設置masterauth選項,那麽復制工作可以繼續進行。

    (2)如果從服務器的masterauth選項設置的密碼與主服務器密碼不相同,那麽主服務器返回一個invalid password錯誤。

    (3)主服務器沒有設置requirepass選項,但從服務器設置了masterauth選項,那麽主服務器將返回一個no password is set 錯誤。

技術分享圖片

  5.5 發送端口信息

    從服務器在身份驗證後,從服務器將執行replconf listening-port port_number,向主服務器發送從服務器的監聽端口號。

技術分享圖片

    主服務器在接受到這個命令之後,會將端口號記錄在從服務器所對應的客戶端狀態的slave_listening_port屬性中。通過info replication命令查看從服務器端口號。

  5.6 數據同步

    從服務器將向主服務器發送psync命令,執行同步操作,並將自己的數據庫更新到主服務器數據庫當前所處的狀態。

  5.7 命令傳播

    當完成了同步之後,主從服務器就會進入命令傳播階段,這時主服務器只要一直將自己執行的命令發送給從服務器,而從服務器只要一直接收並執行主服務器發來的寫命令,就可以保證 主從一致了。

      

六. 復制的心跳檢測

  在命令傳播階級,從服務器默認會以每秒一次的頻率,向主服務器發送命令:replconf ack offset。 發送replconf ack命令對於主從服務器有三個作用:

(1) 檢測主從服務器的網絡連接狀態。

(2) 輔助實現min-slaves選項。

(3) 檢測命令丟失。

  6.1 檢測主從服務器的網絡連接狀態

    主從服務器可以通過發送和接收replconf ack 命令來檢查兩者之間的網絡連接是否正常:如果主服務器超過一秒鐘沒有收到從服務器發來的replconf ack命令,那麽主服務器就知道主從服務器之間的連接出現問題了。

    通過向主服務器發送info replication命令,在列出的從服務器列表的lag一欄中,我們可以看到相應從服務器最後一次向主服務器發送replconf ack 命令距離現在過了多少秒。 

    172.168.18.201:6379> info replication
    # Replication
    role:master
    connected_slaves:1
   slave0:ip=172.168.18.203,port=6379,state=online,offset=92368,lag=0

    上面lag=0 表示剛剛發送過 replconf ack命令。 在一般情況下,lag的值應該在0秒或者1秒之間跳動,如果超過1秒的話,那麽說明主從服務器之間的連接出現了故障。

  6.2 輔助實現min-slaves配置選項

    redis的min-slaves-to-write和min-slaves-max-lag兩個選項可以防止主服務器在不安全的情況下執行寫命令。意思是:至少有 N 個 slave ,並且滯後小於 M 秒,則寫入將被接受,反之寫入不被接受,master 將會回復一個 error。

    --例如:在主庫配置如下:
    min-slaves-to-write 3
    min-slaves-max-lag 10

    如果從服務器的數量少於3個,或者三個從服務器的延遲(lag)值都大於或等於10秒時,主服務器將拒絕執行寫命令,這裏的lag延遲值就是上面提到的INFO replication命令的lag值。

  6.3 檢測命令丟失

    如果因為網絡故障,主服務器傳播給從服務器的寫命令在半路丟失,那麽當從服務器向主服務器發送replconf ack命令時,主服務器將發覺從服務器當前的復制偏移量小於自己的復制偏移量,然後主服務器就會根據從服務器提交的復制偏移量,在復制積壓緩沖區裏面找到從服務器缺少的數據,並將這些數據重新發送給從服務器。

    註意:主服務向從服務器補發缺失數據這一操作的原理和部分重同步操作的原理非常相似,區別在於,補發缺失數據操作在主從服務器沒有斷線的情況下執行,而部分重同步操作則在主從服務器斷線並重連之後執行。

  

7 Redis復制如何處理 key 的過期

  (1) slave 不會讓 key 過期,而是等待 master 讓 key 過期。當一個 master 讓一個 key 到期(或由於 LRU 算法將之驅逐)時,它會合成一個 DEL 命令並傳輸到所有的 slave。

  (2) 由於這是 master 驅動的 key 過期行為,master 無法及時提供 DEL 命令,所以有時候 slave 的內存中仍然可能存在在邏輯上已經過期的 key 。為了處理這個問題,slave 使用它的邏輯時鐘以報告只有在不違反數據集的一致性的讀取操作(從主機的新命令到達)中才存在 key。

  (3) 當一個Lua腳本運行時,master 中的時間是被凍結的,這樣腳本運行的時候,一個給定的鍵要麽存在要麽不存在。這可以防止 key 在腳本中間過期,保證將相同的腳本發送到 slave ,從而在二者的數據集中產生相同的效果。

  一旦一個 slave 被提升為一個 master ,它將開始獨立地過期 key,而不需要任何舊 master 的幫助。

8.啟動復制的其它方法

  (1)在從庫啟動Redis服務的時候,可以指定主服務器信息,命令:redis-server --slaveof masterip masterport。 例如:redis-server --slaveof 172.168.18.201 6379 。

(2)在從庫客戶端指定主服務器信息,命令:redis> SLAVEOF masterip masterport。這樣SLAVEOF命令會停止與原有主服務器的同步,轉而向新主服務器進行同步。

 

redis 系列22 復制Replication (下)