NoSQL之【Redis】學習(四):復制說明


       Redis目前支持復制,不支持集群(在開發中)。Redis復制流程概述:Redis的復制功能是完全建立在之前我們討論過的基於內存快照的持久化策略基礎上的,也就是說無論你的持久化策略選擇的是什么,只要用到了Redis的復制功能,就一定會有內存快照發生,即使主沒有開啟了snapshot持久,也會有rbd文件生成(原因下面說明)。那么首先要注意你的系統內存容量規划。

Redis復制流程在Slave和Master端各自是一套狀態機流轉,涉及的狀態信息是:

整個流程過程如下:
    Slave端在配置文件中添加了slave of指令,於是Slave啟動時讀取配置文件,初始狀態為REDIS_REPL_CONNECT。
    Slave端在定時任務serverCron(Redis內部的定時器觸發事件)中連接Master,發送sync命令,然后阻塞等待master發送回其內存快照文件(最新版的Redis已經不需要讓
Slave阻塞)。 Master端收到sync命令簡單判斷是否有正在進行的內存快照子進程,沒有則立即開始內存快照,有則等待其結束,當快照完成后會將該文件發送給Slave端。 Slave端接收Master發來的內存快照文件,保存到本地,待接收完成后,清空內存表,重新讀取Master發來的內存快照文件,重建整個內存表數據結構,並最終狀態置位為
REDIS_REPL_CONNECTED狀態,Slave狀態機流轉完成。 Master端在發送快照文件過程中,接收的任何會改變數據集的命令都會暫時先保存在Slave網絡連接的發送緩存隊列里(list數據結構),待快照完成后,依次發給Slave,之后
收到的命令相同處理,並將狀態置位為 REDIS_REPL_ONLINE。

整個復制過程完成,流程如下圖所示:

 

Redis復制機制的缺陷:

      從上面的流程可以看出,Slave從庫在連接Master主庫時,Master會進行內存快照,然后把整個快照文件發給Slave,也就是沒有象MySQL那樣有復制位置的概念,即無增量復制,這會給整個集群搭建帶來非常多的問題。
比如一台線上正在運行的Master主庫配置了一台從庫進行簡單讀寫分離,這時Slave由於網絡或者其它原因與Master斷開了連接,那么當Slave進行重新連接時,需要重新獲取整個Master的內存快照,Slave所有數據跟着全部清除,然后重新建立整個內存表,一方面Slave恢復的時間會非常慢,另一方面也會給主庫帶來壓力。
所以基於上述原因,如果你的Redis集群需要主從復制,那么最好事先配置好所有的從庫,避免中途再去增加從庫

注意:

Redis的復制功能沒有增量復制,每次重連都會把主庫整個內存快照發給從庫,所以需要避免向在線服務的壓力較大的主庫上增加從庫。
Redis的復制由於會使用快照持久化方式,所以如果你的Redis持久化方式選擇的是日志追加方式(aof),那么系統有可能在同一時刻既做aof日志文件的同步刷寫磁盤,又做快照寫磁盤操作,這個時候Redis的響應能力會受到影響。所以如果選用aof持久化,則加從庫需要更加謹慎。

以上來自Redis復制與可擴展集群搭建中的復制介紹。

按照 NoSQL之【Redis】學習(一):安裝說明 這篇文章裝好Redis。配置從Redis,很簡單,只需要修改配置文件(redis_slave.conf)的幾個參數:

#Pid 文件
pidfile /var/run/redis2.pid #端口 port 6380 #套接字文件 unixsocket /tmp/redis2.sock #日志文件 logfile /var/log/redis/redis2.log #持久化文件目錄 dir /var/lib/redis2
#從配置選項 # slaveof
<masterip> <masterport> slaveof 192.168.200.202 6379

指定配置文件啟動后(/usr/local/bin/redis-server /etc/redis_slave.conf),日志信息如下:

1 [22108] 27 May 11:53:00.495 * MASTER <-> SLAVE sync started
2 [22108] 27 May 11:53:00.498 * Non blocking connect for SYNC fired the event.
3 [22108] 27 May 11:53:00.498 * Master replied to PING, replication can continue...
4 [22108] 27 May 11:53:00.563 * MASTER <-> SLAVE sync: receiving 18 bytes from master
5 [22108] 27 May 11:53:00.563 * MASTER <-> SLAVE sync: Loading DB in memory
6 [22108] 27 May 11:53:00.563 * MASTER <-> SLAVE sync: Finished with success

從Redis已經完成,測試replication:

主:192.168.200.25 6379
從:192.168.200.202 6379

#測試前檢查MS一致性:
root@zhoujy:~# redis -h 192.168.200.25
redis 192.168.200.25:6379> keys *
(empty list or set) 
redis 192.168.200.25:6379> 
root@zhoujy:~# redis -h 192.168.200.202
redis 192.168.200.202:6379> keys *
(empty list or set)
redis 192.168.200.202:6379> #測試同步
root@zhoujy:~# redis -h 192.168.200.25
redis 192.168.200.25:6379> set name zhoujinyi
OK
redis 192.168.200.25:6379> set sex man
OK
redis 192.168.200.25:6379> set age 27
OK
redis 192.168.200.25:6379> save
OK
redis 192.168.200.25:6379> keys *
1) "name"
2) "age"
3) "sex"
redis 192.168.200.25:6379> 
root@zhoujy:~# redis -h 192.168.200.202
redis 192.168.200.202:6379> keys *
1) "age"
2) "sex"
3) "name"
redis 192.168.200.202:6379> 

上面結果顯示,數據已經從M同步到了S。

注意:創建復制時,可以很清楚的看到Master上僅在第一次做Slave同步時創建了dump.rdb文件,之后就通過增量傳輸命令的方式給Slave了,rdb文件沒有再增大。而Slave的RDB和AOF 隨着數據的增加而增大,並且AOF的增長速度大於RDB。

在上一篇文章NoSQL之【Redis】學習(三):Redis持久化 Snapshot和AOF說明 里面已經說了:

利用Replication機制來彌補aof、snapshot性能上的不足,達到了數據可持久化。即Master上Snapshot和AOF都不做,來保證Master的讀寫性能,而Slave上則同時開啟Snapshot
和AOF來進行持久化,保證數據的安全性

既然Master上持久化不做,只在Slave上做持久化,那Master崩潰數據就會全部丟失,那如何恢復呢?接下來進行測試:

Master的配置:關閉自動持久化

#save 900 1
#save 300 10
#save 60 10000

appendonly no

Slave的配置:開啟自動持久化

save 900 1
save 300 10
save 60 10000

appendonly yes
appendfilename appendonly.aof
appendfsync everysec
no-appendfsync-on-rewrite yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

這些配置的意思請看NoSQL之【Redis】學習(二):配置說明 ,重啟主從服務器,使配置生效。

測試:

# 檢查配置是否生效
redis 192.168.200.25:6379> keys *
(empty list or set)
redis 192.168.200.25:6379> CONFIG GET save 1) "save"
2) ""
redis 192.168.200.25:6379> CONFIG GET append*
1) "appendonly"
2) "no"

redis 192.168.200.202:6379> CONFIG GET save 1) "save"
2) "900 1 300 10 60 10000"
redis 192.168.200.202:6379> CONFIG GET append*
1) "appendonly"
2) "yes"
3) "appendfsync"
4) "everysec" #檢查同步情況
root@zhoujy:~# redis -h 192.168.200.25
redis 192.168.200.25:6379> keys *
(empty list or set)
redis 192.168.200.25:6379> 
root@zhoujy:~# redis -h 192.168.200.202
redis 192.168.200.202:6379> keys *
(empty list or set)
redis 192.168.200.202:6379> 
root@zhoujy:~# redis -h 192.168.200.25
redis 192.168.200.25:6379> set name zhoujinyi
OK
redis 192.168.200.25:6379> set sex man
OK
redis 192.168.200.25:6379> set age 27
OK
redis 192.168.200.25:6379> keys *
1) "age"
2) "name"
3) "sex"
redis 192.168.200.25:6379> 
root@zhoujy:~# redis -h 192.168.200.202
redis 192.168.200.202:6379> keys *
1) "name"
2) "age"
3) "sex" #以上測試已經證明同步成功
#M崩潰恢復:
redis 192.168.200.25:6379> INFO               #通過INFO命令查看M的信息
# Server
……
# Clients
……
# Memory
……
# Persistence
rdb_changes_since_last_save:3                #離最后一次保存改變了3個key
aof_enabled:0 #關閉了aof持久
# Stats
……
# Replication
role:master #該實例為主服務器
connected_slaves:1                           #有一個從服務器連接
slave0:192.168.200.202,6379,online #從服務器的信息
          
# CPU
……
# Keyspace
db0:keys=3,expires=0 #該實例有3個key

#模擬主庫異常崩潰 root@zhoujy:
~# kill -9 1647 root@zhoujy:~# /etc/init.d/redis-server start #崩潰后啟動 Starting redis-server: redis-server. root@zhoujy:~# redis -h 192.168.200.25 #M崩潰恢復: redis 192.168.200.25:6379> INFO #通過INFO命令查看M的信息 # Server …… # Clients …… # Memory …… # Persistence rdb_changes_since_last_save:0 #離最后一次保存改變了0個key aof_enabled:0 #關閉了aof持久 # Stats …… # Replication role:master connected_slaves:1 slave0:192.168.200.202,6379,online #和之前信息一樣,那是不是數據也正常呢? # CPU …… # Keyspace #沒有key信息,數據丟失。---不正常,丟失了 redis 192.168.200.25:6379> keys * (empty list or set) #確實M上已經沒有數據 redis 192.168.200.25:6379> root@zhoujy:~# redis -h 192.168.200.202 #進入從庫看看是否正常 redis 192.168.200.202:6379> keys * (empty list or set) #S上也沒有數據了?Why?

Slave上數據也隨着丟失的原因是上面提到過的一個復制的缺陷引起的:
Slave由於網絡或者其它原因與Master斷開了連接,那么當Slave進行重新連接時,需要重新獲取整個Master的內存快照,Slave所有數據跟着全部清除,然后重新建立整個內存表。上面的情況是因為這時Master已經丟失了數據,快照是空的,直接通過空的快照傳給Slave,導致Slave的數據也被清空了。那如何避免呢?

繼續測試

# 從上面的 “模擬異常崩潰” 開始測試
#模擬異常崩潰
root@zhoujy:/var/lib/redis# /etc/init.d/redis-server stop #關閉主Redis
Stopping redis-server: redis-server.
root@zhoujy:~# redis -h 192.168.200.202 #查看slave的狀態 redis 192.168.200.202:6379> INFO # Server …… # Clients …… # Memory …… # Persistence …… # Stats …… # Replication role:slave master_host:192.168.200.25 master_port:6379 master_link_status:down # Master已經不可訪問了(down)。Slave依然運行良好,並且保留有AOF與RDB文件。 master_last_io_seconds_ago:-1 master_sync_in_progress:0 master_link_down_since_seconds:160 slave_priority:100 slave_read_only:1 connected_slaves:0 # CPU …… # Keyspace db0:keys=3,expires=0 #看到從上還保留3個key #我們將通過Slave上保存好的AOF與RDB文件來恢復Master上的數據。把Slave上的RDB文件復制到主上。(保證文件名和配置文件一致)
1,首先,將Slave上的同步狀態取消,避免主庫在未完成數據恢復前就重啟,進而直接覆蓋掉從庫上的數據,導致所有的數據丟失(上面測試出現的情況)
redis
192.168.200.202:6379> CONFIG GET slaveof #查看同步配置 1) "slaveof" 2) "192.168.200.25 6379" redis 192.168.200.202:6379> SLAVEOF NO ONE #斷開同步 OK redis 192.168.200.202:6379> INFO #斷開同步成功 # Replication role:master connected_slaves:0 2,然后,把RDB文件復制到指定地方:
cp dump.rdb /var/lib/redis/zhoujy.rdb #注意相關權限(redis) root@zhoujy:/var/lib/redis
# /etc/init.d/redis-server start #啟動主Redis Starting redis-server: redis-server. 查看下日志里面的記錄* DB loaded from disk: 0.000 seconds”,已經從RDB文件里面恢復。進入查看下:
redis
192.168.200.25:6379> INFO # Keyspace db0:keys=3,expires=0 #主恢復了3個kye redis 192.168.200.25:6379> keys * #數據已恢復 1) "sex" 2) "age" 3) "name 3,最后,重新開啟主從:
redis 192.168.200.202:6379> SLAVEOF 192.168.200.25 6379 #從重新把主的內存快照取到,清空本地內存,重放取到的內存快照。
OK redis 192.168.200.202:6379> INFO # Replication role:slave master_host:192.168.200.25 master_port:6379 master_link_status:up master_last_io_seconds_ago:1 master_sync_in_progress:0 slave_priority:100 slave_read_only:1 connected_slaves:0

      通過此次實驗,我們通過在Slave上啟的快照,來保證了數據,恢復了Mater。根據上篇持久性介紹的文章,在大數據量的前提下,AOF的增長要比RDB快很多。所以要是對數據的一致性要求不是很高,允許丟失一些數據的話,建議只在從上開啟Snapshot來進行持久化,不開啟AOF(AOF會阻塞讀寫?)。同時可以考慮將save中的頻率調高一些或者調用一個計划任務來進行定期bgsave的快照存儲,來盡可能的保障本地化數據的完整性。樣的架構下,如果僅僅是Master掛掉,Slave完整,數據恢復可達到100%;如果Master與Slave同時掛掉的話,數據的恢復也可以達到一個可接受的程度。當然不允許數據丟失的話,就要開啟AOF了,不過最好新建的時候就開啟,不要中途開啟,上篇有說明。

總結:

       因為在Redis中,持久化和復制的重連都需要一定的開銷,極端情況下這個開銷會導致數據庫的不可用,所以根據自身的情況,建立合適的主從和持久化方案,可以讓Redis和系統更穩定的運行。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM