引言
大概是因?yàn)镽edis是個(gè)人開(kāi)發(fā)的產(chǎn)品,,所以Redis的高可用方案是被分成了幾塊來(lái)實(shí)現(xiàn):主從復(fù)制,、主從切換以及虛擬IP或客戶端方案。
從Redis 2.8開(kāi)始加入對(duì)Sentinel機(jī)制從而實(shí)現(xiàn)了服務(wù)器端的主從切換,,但目前尚未發(fā)現(xiàn)實(shí)現(xiàn)虛擬IP或客戶端切換方案,。
主從復(fù)制研究
wget http://download./releases/redis-2.8.2.tar.gz
tar xzf redis-2.8.2.tar.gz
mv redis-2.8.2 /opt/
cp redis.conf redis-master.conf
cp redis.conf redis-slave.conf
cd /opt/redis-2.8.2
make
以下是關(guān)于 Redis 復(fù)制功能的幾個(gè)重要方面:
1. 一個(gè)Master可以有多個(gè)Slave;
2. Redis使用異步復(fù)制,。從2.8開(kāi)始,,Slave會(huì)周期性(每秒一次)發(fā)起一個(gè)Ack確認(rèn)復(fù)制流(replication stream)被處理進(jìn)度;
3. 不僅主服務(wù)器可以有從服務(wù)器,, 從服務(wù)器也可以有自己的從服務(wù)器,, 多個(gè)從服務(wù)器之間可以構(gòu)成一個(gè)圖狀結(jié)構(gòu),;
4. 復(fù)制在Master端是非阻塞模式的,這意味著即便是多個(gè)Slave執(zhí)行首次同步時(shí),,Master依然可以提供查詢服務(wù),;
5. 復(fù)制在Slave端也是非阻塞模式的:如果你在redis.conf做了設(shè)置,Slave在執(zhí)行首次同步的時(shí)候仍可以使用舊數(shù)據(jù)集提供查詢,;你也可以配置為當(dāng)Master與Slave失去聯(lián)系時(shí),,讓Slave返回客戶端一個(gè)錯(cuò)誤提示;
6. 當(dāng)Slave要?jiǎng)h掉舊的數(shù)據(jù)集,,并重新加載新版數(shù)據(jù)時(shí),,Slave會(huì)阻塞連接請(qǐng)求(一般發(fā)生在與Master斷開(kāi)重連后的恢復(fù)階段);
7. 復(fù)制功能可以單純地用于數(shù)據(jù)冗余(data redundancy),,也可以通過(guò)讓多個(gè)從服務(wù)器處理只讀命令請(qǐng)求來(lái)提升擴(kuò)展性(scalability): 比如說(shuō),, 繁重的 SORT 命令可以交給附屬節(jié)點(diǎn)去運(yùn)行。
8. 可以通過(guò)修改Master端的redis.config來(lái)避免在Master端執(zhí)行持久化操作(Save),,由Slave端來(lái)執(zhí)行持久化,。
分別修改redis-master.conf和redis-slave.conf,
daemonize項(xiàng),改為yes(缺省為no):daemonize yes
maxmemory項(xiàng),,設(shè)最大占用內(nèi)存為50MB:maxmemory 50mb
而有6種內(nèi)存過(guò)期策略,,通過(guò)maxmemory-policy修改,一般使用默認(rèn)值或allkeys-lru:
volatile-lru:只對(duì)設(shè)置了過(guò)期時(shí)間的key進(jìn)行LRU(默認(rèn)值)
allkeys-lru : 是從所有key里 刪除 不經(jīng)常使用的key
volatile-random:隨機(jī)刪除即將過(guò)期key
allkeys-random:隨機(jī)刪除
volatile-ttl : 刪除即將過(guò)期的
noeviction : 永不過(guò)期,,返回錯(cuò)誤
修改redis-slave.conf中的端口,,避免和Master的相同:port 7379
Redis復(fù)制工作原理:
1. 如果設(shè)置了一個(gè)Slave,無(wú)論是第一次連接還是重連到Master,,它都會(huì)發(fā)出一個(gè)SYNC命令,;
2. 當(dāng)Master收到SYNC命令之后,會(huì)做兩件事:
a) Master執(zhí)行BGSAVE,,即在后臺(tái)保存數(shù)據(jù)到磁盤(rdb快照文件),;
b) Master同時(shí)將新收到的寫(xiě)入和修改數(shù)據(jù)集的命令存入緩沖區(qū)(非查詢類);
3. 當(dāng)Master在后臺(tái)把數(shù)據(jù)保存到快照文件完成之后,,Master會(huì)把這個(gè)快照文件傳送給Slave,,而Slave則把內(nèi)存清空后,加載該文件到內(nèi)存中,;
4. 而Master也會(huì)把此前收集到緩沖區(qū)中的命令,,通過(guò)Reids命令協(xié)議形式轉(zhuǎn)發(fā)給Slave,Slave執(zhí)行這些命令,,實(shí)現(xiàn)和Master的同步,;
5. Master/Slave此后會(huì)不斷通過(guò)異步方式進(jìn)行命令的同步,達(dá)到最終數(shù)據(jù)的同步一致;
6. 需要注意的是Master和Slave之間一旦發(fā)生重連都會(huì)引發(fā)全量同步操作,。但在2.8之后版本,,也可能是部分同步操作。
部分復(fù)制
2.8開(kāi)始,,當(dāng)Master和Slave之間的連接斷開(kāi)之后,,他們之間可以采用持續(xù)復(fù)制處理方式代替采用全量同步。
Master端為復(fù)制流維護(hù)一個(gè)內(nèi)存緩沖區(qū)(in-memory backlog),,記錄最近發(fā)送的復(fù)制流命令,;同時(shí),Master和Slave之間都維護(hù)一個(gè)復(fù)制偏移量(replication offset)和當(dāng)前Master服務(wù)器ID(Master run id),。當(dāng)網(wǎng)絡(luò)斷開(kāi),,Slave嘗試重連時(shí):
a. 如果MasterID相同(即仍是斷網(wǎng)前的Master服務(wù)器),并且從斷開(kāi)時(shí)到當(dāng)前時(shí)刻的歷史命令依然在Master的內(nèi)存緩沖區(qū)中存在,,則Master會(huì)將缺失的這段時(shí)間的所有命令發(fā)送給Slave執(zhí)行,然后復(fù)制工作就可以繼續(xù)執(zhí)行了,;
b. 否則,,依然需要全量復(fù)制操作;
Redis 2.8 的這個(gè)部分重同步特性會(huì)用到一個(gè)新增的 PSYNC 內(nèi)部命令,, 而 Redis 2.8 以前的舊版本只有 SYNC 命令,, 不過(guò), 只要從服務(wù)器是 Redis 2.8 或以上的版本,, 它就會(huì)根據(jù)主服務(wù)器的版本來(lái)決定到底是使用 PSYNC 還是 SYNC :
如果主服務(wù)器是 Redis 2.8 或以上版本,,那么從服務(wù)器使用 PSYNC 命令來(lái)進(jìn)行同步。
如果主服務(wù)器是 Redis 2.8 之前的版本,,那么從服務(wù)器使用 SYNC 命令來(lái)進(jìn)行同步,。
配置Slave
只需要將redis-slave.conf中REPLICATION段中的slaveof <masterip> <masterport>行的注釋去掉,并修改為:
slaveof 127.0.0.1 6379
即完成該Slave的配置,,并指向本地端口為6379的Master端,。
masterauth
如果Master端通過(guò)requirepass設(shè)置了密碼,Slave需要對(duì)應(yīng)的通過(guò)masterauth <password>設(shè)置密碼,;
slave-serve-stale-data
當(dāng)Slave和Master斷開(kāi)連接時(shí),,Slave是直接返回錯(cuò)誤提示還是利用歷史數(shù)據(jù)響應(yīng)客戶端(或是直接返回空數(shù)據(jù),當(dāng)全量復(fù)制進(jìn)行時(shí)),。yes是缺省值,,即利用歷史數(shù)據(jù)響應(yīng)。
slave-read-only
缺省模式下,,Slave服務(wù)器是只讀的,。
repl-ping-slave-peroid
即心跳檢測(cè)間隔時(shí)間,缺省值為10秒。
repl-timeout 60
復(fù)制超時(shí)
啟動(dòng)Redis
#redis-server redis-master.conf
#redis-server redis-slave.conf
使用ps查看進(jìn)程
#ps -ef | grep redis
還可以用netstat查看端口
#netstat -tpln
驗(yàn)證主從復(fù)制
#redis-cli set test 1000
#redis-cli get test #只能說(shuō)明目前Master工作正常,,不能說(shuō)明Slave已經(jīng)復(fù)制數(shù)據(jù)
根據(jù)剛剛查看到的端口號(hào),,把端口號(hào)是6379的Master進(jìn)程殺掉
#kill -9 XXXX(PID號(hào))
#redis-cli -p 7379 get test #連接到Slave上,讀取test
#redis-cli -p 7379 set test 1000 #會(huì)提示Slave只讀錯(cuò)誤,,不能寫(xiě)入