一. 複製環境準備 1.1 主庫環境(172.168.18.201) 環境 說明 1.2 從庫環境(172.168.18.203) 環境 說明 二. 複製配置 2.1 主庫環境密碼設置 在201主庫上,找到redis目錄下的redis.conf文件,打開文件找到requirepass,在500行,下 ...
一. 複製環境準備
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 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命令會停止與原有主伺服器的同步,轉而向新主伺服器進行同步。