1. 程式人生 > >redis 系列22 複製Replication (下)

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
Redis伺服器密碼
是否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服務,重新登入主伺服器,客戶端連線成功,指令碼如下:

    [[email protected] bin]# iptables -F
    [[email protected] 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伺服器,主從網路連線沒有問題,連線成功,指令碼如下:

    [[email protected] 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"
    -- 開啟後,持久化檔案生成如下列表:
    [[email protected] 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持久化,從庫預設是隻讀模式。參考主庫設定,這裡就不再介紹,最後檢視指令碼如下:

    [[email protected] 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
    -- 最後客戶端關閉從庫服務,重啟服務
    [[email protected] redis]# redis-cli -h 172.168.18.203 -p 6379 -a 123456
    172.168.18.203:6379> shutdown
    not connected> exit
    [[email protected] 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 can't 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命令會停止與原有主伺服器的同步,轉而向新主伺服器進行同步。