[TOC]
1. 主從賦值
從節(jié)點(diǎn)slave實(shí)例能精確得復(fù)制主節(jié)點(diǎn)master實(shí)例的內(nèi)容询一。每次當(dāng)slave和master斷開(kāi)時(shí),slave會(huì)自動(dòng)重連到master上健蕊,并且無(wú)論這期間master發(fā)生了什么,slave都會(huì)嘗試將自己成為master的精確副本晴及。
主從賦值的機(jī)制:
- master和slave正常連接時(shí):master會(huì)發(fā)送一連串的命令流來(lái)保持對(duì)slave的更新,以便于將自身的數(shù)據(jù)集復(fù)制給slave虑稼。包括客戶端的寫(xiě)入琳钉、key的過(guò)期與丟棄等等歌懒。
- master和slave斷開(kāi),重連后:slave重新連接上master后及皂,會(huì)嘗試進(jìn)行部分重同步。slave只會(huì)嘗試獲取在斷開(kāi)連接期間內(nèi)丟失的命令流验烧。
- 無(wú)法進(jìn)行重同步:如果無(wú)法進(jìn)行重同步,那么slave就請(qǐng)求進(jìn)行全量重同步碍拆。master需要?jiǎng)?chuàng)建所有數(shù)據(jù)的快照效扫,將之發(fā)送給slave,之后在數(shù)據(jù)集更改時(shí)菌仁,持續(xù)發(fā)送命令流到slave。
redis使用默認(rèn)的異步復(fù)制济丘,具有低延遲和高性能的特點(diǎn),也是大多數(shù)的自然復(fù)制模式摹迷。slave會(huì)異步確認(rèn)master周期性發(fā)送的命令流(數(shù)據(jù)流)。
客戶端可以使用WAIT
命令請(qǐng)求同步復(fù)制某些特定的數(shù)據(jù)峡碉。但是WAIT
命令只能確保在slave中存在指定數(shù)據(jù)的已確認(rèn)副本。雖然slave已確認(rèn)了副本存在鲫寄,但是slave在持久化副本的時(shí)候,還是會(huì)受到slave自己的持久化策略的影響地来,最終仍然會(huì)因持久化策略,導(dǎo)致同步期間的數(shù)據(jù)丟失咕宿。
2. 主從復(fù)制的特點(diǎn)
對(duì)于主從復(fù)制來(lái)說(shuō),一個(gè)master可能存在多個(gè)slave府阀,隨著slave的數(shù)量的增加,慢慢的master給slave發(fā)送數(shù)據(jù)流试浙,就成為了master性能下降的原因之一了。
所以在redis中川队,有以下功能來(lái)保證主從復(fù)制:
- 一個(gè)master可以有很多的slave
- redis使用異步復(fù)制,slave和master之間可以異步確認(rèn)處理的數(shù)據(jù)
- ==slave可以接受其他slave的連接固额。==除了多個(gè)slave可以連接到同一個(gè)master之外,slave之間也可以以層疊結(jié)構(gòu)連接到其他slave斗躏。在redis4.0開(kāi)始,所有的slave會(huì)收到完全一樣的賦值流啄糙。
- 主從復(fù)制在master是非阻塞的,master可以在一個(gè)或多個(gè)slave進(jìn)行初次同步或者是部分同步時(shí)沈堡,還可以繼續(xù)處理查詢請(qǐng)求。
- 主從復(fù)制在slave大部分也是非阻塞的诞丽。當(dāng)slave進(jìn)行初次同步時(shí),他可以使用舊數(shù)據(jù)集處理查詢請(qǐng)求(需要在redis.conf中配置)僧免,否則slave會(huì)返回error給客戶端。初次同步之后懂衩,舊的數(shù)據(jù)集會(huì)被刪除金踪,同時(shí)加載新的數(shù)據(jù)集,如果數(shù)據(jù)集很大热康,這個(gè)操作會(huì)造成slave短暫的卡頓劣领,在卡頓期間阻塞姐军。在redis4.0開(kāi)始奕锌,可以配置slave刪除舊的數(shù)據(jù)集在其他線程完成。但是加載新的數(shù)據(jù)集依然是主線程完成惊暴,依然會(huì)有小小的卡頓(非常不明顯)。
- 主從復(fù)制可以用在可伸縮性上辽话,比如讀多寫(xiě)少的場(chǎng)景,也可以作為備份機(jī)器使用(熱備份油啤,當(dāng)主節(jié)點(diǎn)出現(xiàn)問(wèn)題了,備份節(jié)點(diǎn)可以不做任何修改逮诲,在極其短的時(shí)間內(nèi)成為主節(jié)點(diǎn),實(shí)現(xiàn)主節(jié)點(diǎn)的操作)
- 主從復(fù)制可以轉(zhuǎn)移持久化梅鹦,提高性能。比如slaveA是熱備份機(jī)器齐唆,slaveB是持久化機(jī)器冻河。slaveB從master或者slaveA得到完整的數(shù)據(jù)集,然后寫(xiě)入硬盤(pán)芋绸,因?yàn)閙aster不需要做硬盤(pán)持久化,所以在一定的程度上可以提升性能摔敛。
3. 主從復(fù)制的安全
在第二小節(jié)中,我們談到马昙,利用主從賦值,可以將master的持久化轉(zhuǎn)移給slave行楞。要實(shí)現(xiàn)slave代替master進(jìn)行持久化,就需要master關(guān)閉持久化子房。
但是master關(guān)閉持久化會(huì)存在非常嚴(yán)重的隱患:
假設(shè)在主從賦值的過(guò)程中就轧,master重啟了田度,因?yàn)閙aster沒(méi)有配置持久化,而且也沒(méi)有從slave獲取持久化文件乎莉。那么重啟后的master就是一個(gè)沒(méi)有任何數(shù)據(jù)的redis實(shí)例。slave重新和master連接后奸笤,并不知道m(xù)aster發(fā)生了重啟惋啃,于是進(jìn)行部分同步,所以slave也將全部的數(shù)據(jù)刪除监右,成為了空數(shù)據(jù)的redis實(shí)例肥橙。將空數(shù)據(jù)持久化到硬盤(pán),同時(shí)刪除舊的持久化文件秸侣,此時(shí)就造成了數(shù)據(jù)全部丟失的嚴(yán)重問(wèn)題存筏。
如何解決:
關(guān)閉自動(dòng)重啟機(jī)制,當(dāng)master因各種原因宕機(jī)味榛,不應(yīng)該立即重啟,而是要從slave拿到持久化文件搏色,然后在啟動(dòng),讓重新后的master根據(jù)持久化文件進(jìn)行重建數(shù)據(jù)频轿。
4. 主從復(fù)制的原理
每一個(gè) master 都有一個(gè) replication ID
:這是一個(gè)較大的偽隨機(jī)字符串,標(biāo)記了一個(gè)給定的數(shù)據(jù)集耕赘。每個(gè) master 也持有一個(gè)偏移量膳殷,master 將自己產(chǎn)生的復(fù)制流發(fā)送給 slave 時(shí),發(fā)送多少個(gè)字節(jié)的數(shù)據(jù)赚窃,自身的偏移量就會(huì)增加多少,目的是當(dāng)有新的操作修改自己的數(shù)據(jù)集時(shí)是掰,它可以以此更新 slave 的狀態(tài)辱匿。復(fù)制偏移量即使在沒(méi)有一個(gè) slave 連接到 master 時(shí)炫彩,也會(huì)自增散休,所以基本上每一對(duì)給定的
Replication ID, offset
都會(huì)標(biāo)識(shí)一個(gè) master 數(shù)據(jù)集的確切版本戚丸。
當(dāng) slave 連接到 master 時(shí)扔嵌,它們使用 PSYNC
命令來(lái)發(fā)送它們記錄的舊的 master replication ID 和它們至今為止處理的偏移量。通過(guò)這種方式痢缎, master 能夠僅發(fā)送 slave 所需的增量部分。但是如果 master 的緩沖區(qū)中沒(méi)有足夠的命令積壓緩沖記錄署穗,或者如果 slave 引用了不再知道的歷史記錄(replication ID)嵌洼,則會(huì)轉(zhuǎn)而進(jìn)行一個(gè)全量重同步:在這種情況下, slave 會(huì)得到一個(gè)完整的數(shù)據(jù)集副本麻养,從頭開(kāi)始。
下面是一個(gè)全量同步的工作細(xì)節(jié):
master 開(kāi)啟一個(gè)后臺(tái)保存進(jìn)程备畦,以便于生產(chǎn)一個(gè) RDB 文件许昨。同時(shí)它開(kāi)始緩沖所有從客戶端接收到的新的寫(xiě)入命令。當(dāng)后臺(tái)保存完成時(shí)允粤, master 將數(shù)據(jù)集文件傳輸給 slave, slave將之保存在磁盤(pán)上类垫,然后加載文件到內(nèi)存琅坡。再然后 master 會(huì)發(fā)送所有緩沖的命令發(fā)給 slave。這個(gè)過(guò)程以指令流的形式完成并且和 Redis 協(xié)議本身的格式相同榆俺。
你可以用 telnet 自己進(jìn)行嘗試坞淮。在服務(wù)器正在做一些工作的同時(shí)連接到 Redis 端口并發(fā)出 SYNC 命令回窘。你將會(huì)看到一個(gè)批量傳輸市袖,并且之后每一個(gè) master 接收到的命令都將在 telnet 回話中被重新發(fā)出。事實(shí)上 SYNC 是一個(gè)舊協(xié)議苍碟,在新的 Redis 實(shí)例中已經(jīng)不再被使用,但是其仍然向后兼容:但它不允許部分重同步舷丹,所以現(xiàn)在 PSYNC
被用來(lái)替代SYNC
蜓肆。
之前說(shuō)過(guò)弄兜,當(dāng)主從之間的連接因?yàn)橐恍┰虮罎⒅螅?slave 能夠自動(dòng)重連蕊蝗。如果 master 收到了多個(gè) slave 要求同步的請(qǐng)求衍慎,它會(huì)執(zhí)行一個(gè)單獨(dú)的后臺(tái)保存渤滞,以便于為多個(gè) slave 服務(wù)纱兑。
5. 無(wú)需磁盤(pán)參與的復(fù)制
正常情況下精肃,一個(gè)全量重同步要求在磁盤(pán)上創(chuàng)建一個(gè) RDB 文件司抱,然后將它從磁盤(pán)加載進(jìn)內(nèi)存黎烈,然后 slave以此進(jìn)行數(shù)據(jù)同步。
如果磁盤(pán)性能很低的話照棋,這對(duì) master 是一個(gè)壓力很大的操作。Redis 2.8.18 是第一個(gè)支持無(wú)磁盤(pán)復(fù)制的版本溶锭。在此設(shè)置中符隙,子進(jìn)程直接發(fā)送 RDB 文件給 slave垫毙,無(wú)需使用磁盤(pán)作為中間儲(chǔ)存介質(zhì)拱绑。
6. 配置主從復(fù)制
6.1 配置文件
slaveof host port
將這個(gè)命令加入redis.conf文件中即可使得redis實(shí)例成為從節(jié)點(diǎn),host的redis實(shí)例是主節(jié)點(diǎn)膀藐。
6.2 配置命令
在從節(jié)點(diǎn)的redis實(shí)例中使用slaveof
命令迟几,也會(huì)將當(dāng)前節(jié)點(diǎn)設(shè)置為目標(biāo)節(jié)點(diǎn)的slave栏笆,不過(guò)重啟后會(huì)被redis.conf的配置重置。
小例子:
將slave設(shè)置為master的從節(jié)點(diǎn)蚜枢。
master增加數(shù)據(jù)
然后在slave查看厂抽,是否進(jìn)行復(fù)制
發(fā)現(xiàn)沒(méi)有進(jìn)行主從復(fù)制丁眼,是時(shí)間沒(méi)到嗎?那么就使用WAIT
命令強(qiáng)制進(jìn)行主從復(fù)制了
一直沒(méi)有進(jìn)行主從復(fù)制藐守。是打開(kāi)方式不對(duì)嗎,還是哪里出錯(cuò)了卢厂?
仔細(xì)回憶惠啄,slave的配置文件中有這樣一句:
應(yīng)該是這個(gè)配置導(dǎo)致的,我們注釋掉這個(gè)配置融柬,然后重啟
重新設(shè)置slave
但是我又失敗了趋距。。棚品。嗯嗯
配置中的protectted-mode是和bind配合使用的吧
在試
因?yàn)槲以趙in 10系統(tǒng)上啟動(dòng)的redis-server,而且前面就將redis-server注冊(cè)到操作系統(tǒng)的服務(wù)中心了
使用redis-server --service-insttall config-path
即可將redis-server注冊(cè)骡澈。
使用redis-server --service-stop
停止
使用redis-server --service-start
啟動(dòng)
使用redis-server --service-resart
重啟
重啟了
然后發(fā)現(xiàn)還是沒(méi)有同步掷空,看下日志
嗯,應(yīng)該是版本問(wèn)題造成的:
那么如果我本地在啟動(dòng)一個(gè)呢
我又在本地啟動(dòng)了一個(gè)护锤,端口是6301.
6301將是master,6300是slave
成功實(shí)現(xiàn)烙懦。我們?cè)?301中是沒(méi)有做任何操作的,但是6300已經(jīng)擁有了6301中的數(shù)據(jù)了氯析。
7. slave只讀
自從 Redis 2.6 之后莺褒, slave 支持只讀模式且默認(rèn)開(kāi)啟。redis.conf 文件中的 slave-read-only 變量控制這個(gè)行為遵岩,且可以在運(yùn)行時(shí)使用 CONFIG SET 來(lái)隨時(shí)開(kāi)啟或者關(guān)閉。
只讀模式下的 slave 將會(huì)拒絕所有寫(xiě)入命令舍哄,因此實(shí)踐中不可能由于某種出錯(cuò)而將數(shù)據(jù)寫(xiě)入 slave 。
由于slave不會(huì)將數(shù)據(jù)傳播到與該實(shí)例相連的slave上蠢熄,slave總是接收與頂層redis實(shí)例發(fā)送的數(shù)據(jù)流炉旷。
graph LR
A --> B
B --> C
對(duì)于C來(lái)說(shuō)签孔,C只會(huì)接收和A完全相同的數(shù)據(jù)流饥追。
如果數(shù)據(jù)流在B中發(fā)生了修改罐盔,那么C是不接收的。
8. slave 驗(yàn)證
redis實(shí)例是可以配置密碼的安全驗(yàn)證的。
所以六孵,如果slave需要連接到master,需要通過(guò)驗(yàn)證才行劫窒。
需要在slave的配置文件中配置
masterauth <password>
或者在命令行中使用
config set masterautn <password>
進(jìn)行配置
9. slave 數(shù)量控制
從Redis 2.8開(kāi)始拆座,只有當(dāng)至少有 N 個(gè) slave 連接到 master 時(shí),才有可能配置 Redis master 接受寫(xiě)查詢孕索。
但是,由于 Redis 使用異步復(fù)制搞旭,因此無(wú)法確保 slave 是否實(shí)際接收到給定的寫(xiě)命令,因此總會(huì)有一個(gè)數(shù)據(jù)丟失窗口选脊。
以下是該特性的工作原理:
- slave 每秒鐘都會(huì) ping master脸甘,確認(rèn)已處理的復(fù)制流的數(shù)量偏灿。
- master 會(huì)記得上一次從每個(gè) slave 都收到 ping 的時(shí)間。
- 用戶可以配置一個(gè)最小的 slave 數(shù)量翁垂,使得它滯后 <= 最大秒數(shù)。
如果至少有 N 個(gè) slave 沿猜,并且滯后小于 M 秒,則寫(xiě)入將被接受橄妆。
你可能認(rèn)為這是一個(gè)盡力而為的數(shù)據(jù)安全機(jī)制祈坠,對(duì)于給定的寫(xiě)入來(lái)說(shuō),不能保證一致性赦拘,但至少數(shù)據(jù)丟失的時(shí)間窗限制在給定的秒數(shù)內(nèi)。一般來(lái)說(shuō)阁猜,綁定的數(shù)據(jù)丟失比不綁定的更好。
如果條件不滿足剃袍,master 將會(huì)回復(fù)一個(gè) error 并且寫(xiě)入將不被接受。
這個(gè)特性有兩個(gè)配置參數(shù):
- min-slaves-to-write <slave 數(shù)量>
- min-slaves-max-lag <秒數(shù)>
10. 主從復(fù)制處理過(guò)期數(shù)據(jù)
Redis 的過(guò)期機(jī)制可以限制 key 的生存時(shí)間隘击。此功能取決于 Redis 實(shí)例計(jì)算時(shí)間的能力研铆,但是,即使使用 Lua 腳本更改了這些 key棵红,slaves 也能正確地復(fù)制具有過(guò)期時(shí)間的 key。
為了實(shí)現(xiàn)這樣的功能虱肄,Redis 不能依靠主從使用同步時(shí)鐘交煞,因?yàn)檫@是一個(gè)無(wú)法解決的并且會(huì)導(dǎo)致 race condition 和數(shù)據(jù)集不一致的問(wèn)題,所以 Redis 使用三種主要的技術(shù)使過(guò)期的 key 的復(fù)制能夠正確工作:
- slave 不會(huì)讓 key 過(guò)期素征,而是等待 master 讓 key 過(guò)期。當(dāng)一個(gè) master 讓一個(gè) key 到期(或由于 LRU 算法將之驅(qū)逐)時(shí)根欧,它會(huì)合成一個(gè) DEL 命令并傳輸?shù)剿械?slave。
- 但是凤粗,由于這是 master 驅(qū)動(dòng)的 key 過(guò)期行為今豆,master 無(wú)法及時(shí)提供 DEL 命令,所以有時(shí)候 slave 的內(nèi)存中仍然可能存在在邏輯上已經(jīng)過(guò)期的 key 晚凿。為了處理這個(gè)問(wèn)題,slave 使用它的邏輯時(shí)鐘以報(bào)告只有在不違反數(shù)據(jù)集的一致性的讀取操作(從主機(jī)的新命令到達(dá))中才存在 key应役。用這種方法,slave 避免報(bào)告邏輯過(guò)期的 key 仍然存在箩祥。在實(shí)際應(yīng)用中,使用 slave 程序進(jìn)行縮放的 HTML 碎片緩存袍祖,將避免返回已經(jīng)比期望的時(shí)間更早的數(shù)據(jù)項(xiàng)。
- 在Lua腳本執(zhí)行期間捐凭,不執(zhí)行任何 key 過(guò)期操作。當(dāng)一個(gè)Lua腳本運(yùn)行時(shí)茁肠,從概念上講缩举,master 中的時(shí)間是被凍結(jié)的,這樣腳本運(yùn)行的時(shí)候仅孩,一個(gè)給定的鍵要么存在要么不存在。這可以防止 key 在腳本中間過(guò)期辽慕,保證將相同的腳本發(fā)送到 slave ,從而在二者的數(shù)據(jù)集中產(chǎn)生相同的效果绞旅。
一旦一個(gè) slave 被提升為一個(gè) master 温艇,它將開(kāi)始獨(dú)立地過(guò)期 key,而不需要任何舊 master 的幫助堕汞。
如果主從復(fù)制中主節(jié)點(diǎn)和從節(jié)點(diǎn)處理過(guò)期數(shù)據(jù)不及時(shí),會(huì)造成==主節(jié)點(diǎn)與讀節(jié)點(diǎn)讀取數(shù)據(jù)不一致==的問(wèn)題琐鲁。
11. 主從復(fù)制信息查詢
有兩個(gè) Redis 命令可以提供有關(guān)主從實(shí)例當(dāng)前復(fù)制參數(shù)的很多信息人灼。一個(gè)是INFO
。如果使用復(fù)制參數(shù)像 INFO replication
調(diào)用該命令投放,,則只顯示與復(fù)制相關(guān)的信息涝桅。另一個(gè)更加 友好 的命令是 ROLE
拜姿,它提供 master 和 slave 的復(fù)制狀態(tài)以及它們的復(fù)制偏移量冯遂,連接的 slaves 列表等等。