這篇文章將為大家詳細(xì)講解有關(guān)redis中主從架構(gòu)數(shù)據(jù)一致性同步原理的示例分析,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
成都創(chuàng)新互聯(lián)是一家朝氣蓬勃的網(wǎng)站建設(shè)公司。公司專(zhuān)注于為企業(yè)提供信息化建設(shè)解決方案。從事網(wǎng)站開(kāi)發(fā),網(wǎng)站制作,網(wǎng)站設(shè)計(jì),網(wǎng)站模板,微信公眾號(hào)開(kāi)發(fā),軟件開(kāi)發(fā),小程序設(shè)計(jì),十載建站對(duì)成都搬家公司等多個(gè)方面,擁有豐富設(shè)計(jì)經(jīng)驗(yàn)。
高可用有兩個(gè)含義:一是數(shù)據(jù)盡量不丟失,二是服務(wù)盡可能提供服務(wù)。AOF 和 RDB 保證了數(shù)據(jù)持久化盡量不丟失,而主從復(fù)制就是增加副本,一份數(shù)據(jù)保存到多個(gè)實(shí)例上。即使有一個(gè)實(shí)例宕機(jī),其他實(shí)例依然可以提供服務(wù)。
本篇主要帶大家全方位吃透 Redis 高可用技術(shù)解決方案之一主從復(fù)制架構(gòu)。
核心知識(shí)點(diǎn)
問(wèn)題 = 機(jī)會(huì)。遇到問(wèn)題的時(shí)候,內(nèi)心其實(shí)是開(kāi)心的,越大的問(wèn)題意味著越大的機(jī)會(huì)。
任何事情都是有代價(jià)的,有得必有失,有失必有得,所以不必計(jì)較很多東西,我們只要想清楚自己要做什么,并且想清楚自己愿意為之付出什么代價(jià),然后就放手去做吧!
65 哥:有了 RDB 和 AOF 再也不怕宕機(jī)丟失數(shù)據(jù)了,但是 Redis 實(shí)例宕機(jī)了怎么實(shí)現(xiàn)高可用呢?
既然一臺(tái)宕機(jī)了無(wú)法提供服務(wù),那多臺(tái)呢?是不是就可以解決了。Redis 提供了主從模式,通過(guò)主從復(fù)制,將數(shù)據(jù)冗余一份復(fù)制到其他 Redis 服務(wù)器。
前者稱(chēng)為主節(jié)點(diǎn) (master),后者稱(chēng)為從節(jié)點(diǎn) (slave);數(shù)據(jù)的復(fù)制是單向的,只能由主節(jié)點(diǎn)到從節(jié)點(diǎn)。
默認(rèn)情況下,每臺(tái) Redis 服務(wù)器都是主節(jié)點(diǎn);且一個(gè)主節(jié)點(diǎn)可以有多個(gè)從節(jié)點(diǎn) (或沒(méi)有從節(jié)點(diǎn)),但一個(gè)從節(jié)點(diǎn)只能有一個(gè)主節(jié)點(diǎn)。
65 哥:主從之間的數(shù)據(jù)如何保證一致性呢?
為了保證副本數(shù)據(jù)的一致性,主從架構(gòu)采用了讀寫(xiě)分離的方式。
讀操作:主、從庫(kù)都可以執(zhí)行;
寫(xiě)操作:主庫(kù)先執(zhí)行,之后將寫(xiě)操作同步到從庫(kù);
65 哥:為何要采用讀寫(xiě)分離的方式?
我們可以假設(shè)主從庫(kù)都可以執(zhí)行寫(xiě)指令,假如對(duì)同一份數(shù)據(jù)分別修改了多次,每次修改發(fā)送到不同的主從實(shí)例上,就導(dǎo)致是實(shí)例的副本數(shù)據(jù)不一致了。
如果為了保證數(shù)據(jù)一致,Redis 需要加鎖,協(xié)調(diào)多個(gè)實(shí)例的修改,Redis 自然不會(huì)這么干!
65 哥:主從復(fù)制還有其他作用么?
故障恢復(fù):當(dāng)主節(jié)點(diǎn)宕機(jī),其他節(jié)點(diǎn)依然可以提供服務(wù);
負(fù)載均衡:Master 節(jié)點(diǎn)提供寫(xiě)服務(wù),Slave 節(jié)點(diǎn)提供讀服務(wù),分擔(dān)壓力;
高可用基石:是哨兵和 cluster 實(shí)施的基礎(chǔ),是高可用的基石。
主從復(fù)制的開(kāi)啟,完全是在從節(jié)點(diǎn)發(fā)起的,不需要我們?cè)谥鞴?jié)點(diǎn)做任何事情。
65 哥:怎么搭建主從復(fù)制架構(gòu)呀?
可以通過(guò) replicaof(Redis 5.0 之前使用 slaveof)命令形成主庫(kù)和從庫(kù)的關(guān)系。
在從節(jié)點(diǎn)開(kāi)啟主從復(fù)制,有 3 種方式:
配置文件
在從服務(wù)器的配置文件中加入 replicaof <masterip> <masterport>
啟動(dòng)命令
redis-server 啟動(dòng)命令后面加入 --replicaof <masterip> <masterport>
客戶(hù)端命令
啟動(dòng)多個(gè) Redis 實(shí)例后,直接通過(guò)客戶(hù)端執(zhí)行命令:replicaof <masterip> <masterport>
,則該 Redis 實(shí)例成為從節(jié)點(diǎn)。
比如假設(shè)現(xiàn)在有實(shí)例 1(172.16.88.1)、實(shí)例 2(172.16.88.2)和實(shí)例 3 (172.16.88.3),在實(shí)例 2 和實(shí)例 3 上分別執(zhí)行以下命令,實(shí)例 2 和 實(shí)例 3 就成為了實(shí)例 1 的從庫(kù),實(shí)例 1 成為 Master。
replicaof 172.16.88.1 6379復(fù)制代碼
主從庫(kù)模式一旦采用了讀寫(xiě)分離,所有數(shù)據(jù)的寫(xiě)操作只會(huì)在主庫(kù)上進(jìn)行,不用協(xié)調(diào)三個(gè)實(shí)例。
主庫(kù)有了最新的數(shù)據(jù)后,會(huì)同步給從庫(kù),這樣,主從庫(kù)的數(shù)據(jù)就是一致的。
65 哥:主從庫(kù)同步是如何完成的呢?主庫(kù)數(shù)據(jù)是一次性傳給從庫(kù),還是分批同步?正常運(yùn)行中又怎么同步呢?要是主從庫(kù)間的網(wǎng)絡(luò)斷連了,重新連接后數(shù)據(jù)還能保持一致嗎?
65 哥你問(wèn)題咋這么多,同步分為三種情況:
第一次主從庫(kù)全量復(fù)制;
主從正常運(yùn)行期間的同步;
主從庫(kù)間網(wǎng)絡(luò)斷開(kāi)重連同步。
65 哥:我好暈啊,先從主從庫(kù)間第一次同步說(shuō)起吧。
主從庫(kù)第一次復(fù)制過(guò)程大體可以分為 3 個(gè)階段:連接建立階段(即準(zhǔn)備階段)、主庫(kù)同步數(shù)據(jù)到從庫(kù)階段、發(fā)送同步期間新寫(xiě)命令到從庫(kù)階段;
直接上圖,從整體上有一個(gè)全局觀(guān)的感知,后面具體介紹。
該階段的主要作用是在主從節(jié)點(diǎn)之間建立連接,為數(shù)據(jù)全量同步做好準(zhǔn)備。從庫(kù)會(huì)和主庫(kù)建立連接,從庫(kù)執(zhí)行 replicaof 并發(fā)送 psync 命令并告訴主庫(kù)即將進(jìn)行同步,主庫(kù)確認(rèn)回復(fù)后,主從庫(kù)間就開(kāi)始同步了。
65 哥:從庫(kù)怎么知道主庫(kù)信息并建立連接的呢?
在從節(jié)點(diǎn)的配置文件中的 replicaof 配置項(xiàng)中配置了主節(jié)點(diǎn)的 IP 和 port 后,從節(jié)點(diǎn)就知道自己要和那個(gè)主節(jié)點(diǎn)進(jìn)行連接了。
從節(jié)點(diǎn)內(nèi)部維護(hù)了兩個(gè)字段,masterhost 和 masterport,用于存儲(chǔ)主節(jié)點(diǎn)的 IP 和 port 信息。
從庫(kù)執(zhí)行 replicaof
并發(fā)送 psync
命令,表示要執(zhí)行數(shù)據(jù)同步,主庫(kù)收到命令后根據(jù)參數(shù)啟動(dòng)復(fù)制。命令包含了主庫(kù)的 runID和 復(fù)制進(jìn)度 offset兩個(gè)參數(shù)。
runID:每個(gè) Redis 實(shí)例啟動(dòng)都會(huì)自動(dòng)生成一個(gè) 唯一標(biāo)識(shí) ID,第一次主從復(fù)制,還不知道主庫(kù) runID,參數(shù)設(shè)置為 「?」。
offset:第一次復(fù)制設(shè)置為 -1,表示第一次復(fù)制,記錄復(fù)制進(jìn)度偏移量。
主庫(kù)收到 psync 命令后,會(huì)用 FULLRESYNC 響應(yīng)命令帶上兩個(gè)參數(shù):主庫(kù) runID 和主庫(kù)目前的復(fù)制進(jìn)度 offset,返回給從庫(kù)。從庫(kù)收到響應(yīng)后,會(huì)記錄下這兩個(gè)參數(shù)。
FULLRESYNC 響應(yīng)表示第一次復(fù)制采用的全量復(fù)制,也就是說(shuō),主庫(kù)會(huì)把當(dāng)前所有的數(shù)據(jù)都復(fù)制給從庫(kù)。
第二階段
master 執(zhí)行 bgsave
命令生成 RDB 文件,并將文件發(fā)送給從庫(kù),同時(shí)主庫(kù)為每一個(gè) slave 開(kāi)辟一塊 replication buffer 緩沖區(qū)記錄從生成 RDB 文件開(kāi)始收到的所有寫(xiě)命令。
從庫(kù)收到 RDB 文件后保存到磁盤(pán),并清空當(dāng)前數(shù)據(jù)庫(kù)的數(shù)據(jù),再加載 RDB 文件數(shù)據(jù)到內(nèi)存中。
第三階段
從節(jié)點(diǎn)加載 RDB 完成后,主節(jié)點(diǎn)將 replication buffer 緩沖區(qū)的數(shù)據(jù)發(fā)送到從節(jié)點(diǎn),Slave 接收并執(zhí)行,從節(jié)點(diǎn)同步至主節(jié)點(diǎn)相同的狀態(tài)。
65 哥:主庫(kù)將數(shù)據(jù)同步到從庫(kù)過(guò)程中,可以正常接受請(qǐng)求么?
主庫(kù)不會(huì)被阻塞,Redis 作為唯快不破的男人,怎么會(huì)動(dòng)不動(dòng)就阻塞呢。
在生成 RDB 文件之后的寫(xiě)操作并沒(méi)有記錄到剛剛的 RDB 文件中,為了保證主從庫(kù)數(shù)據(jù)的一致性,所以主庫(kù)會(huì)在內(nèi)存中使用一個(gè)叫 replication buffer 記錄 RDB 文件生成后的所有寫(xiě)操作。
65 哥:為啥從庫(kù)收到 RDB 文件后要清空當(dāng)前數(shù)據(jù)庫(kù)?
因?yàn)閺膸?kù)在通過(guò) replcaof
命令開(kāi)始和主庫(kù)同步前可能保存了其他數(shù)據(jù),防止主從數(shù)據(jù)之間的影響。
replication buffer 到底是什么玩意?
一個(gè)在 master 端上創(chuàng)建的緩沖區(qū),存放的數(shù)據(jù)是下面三個(gè)時(shí)間內(nèi)所有的 master 數(shù)據(jù)寫(xiě)操作。
1)master 執(zhí)行 bgsave 產(chǎn)生 RDB 的期間的寫(xiě)操作;
2)master 發(fā)送 rdb 到 slave 網(wǎng)絡(luò)傳輸期間的寫(xiě)操作;
3)slave load rdb 文件把數(shù)據(jù)恢復(fù)到內(nèi)存的期間的寫(xiě)操作。
Redis 和客戶(hù)端通信也好,和從庫(kù)通信也好,Redis 都分配一個(gè)內(nèi)存 buffer 進(jìn)行數(shù)據(jù)交互,客戶(hù)端就是一個(gè) client,從庫(kù)也是一個(gè) client,我們每個(gè) client 連上 Redis 后,Redis 都會(huì)分配一個(gè)專(zhuān)有 client buffer,所有數(shù)據(jù)交互都是通過(guò)這個(gè) buffer 進(jìn)行的。
Master 先把數(shù)據(jù)寫(xiě)到這個(gè) buffer 中,然后再通過(guò)網(wǎng)絡(luò)發(fā)送出去,這樣就完成了數(shù)據(jù)交互。
不管是主從在增量同步還是全量同步時(shí),master 會(huì)為其分配一個(gè) buffer ,只不過(guò)這個(gè) buffer 專(zhuān)門(mén)用來(lái)傳播寫(xiě)命令到從庫(kù),保證主從數(shù)據(jù)一致,我們通常把它叫做 replication buffer。
replication buffer 太小會(huì)引發(fā)的問(wèn)題:
replication buffer 由 client-output-buffer-limit slave 設(shè)置,當(dāng)這個(gè)值太小會(huì)導(dǎo)致主從復(fù)制連接斷開(kāi)。
1)當(dāng) master-slave 復(fù)制連接斷開(kāi),master 會(huì)釋放連接相關(guān)的數(shù)據(jù)。replication buffer 中的數(shù)據(jù)也就丟失了,此時(shí)主從之間重新開(kāi)始復(fù)制過(guò)程。
2)還有個(gè)更嚴(yán)重的問(wèn)題,主從復(fù)制連接斷開(kāi),導(dǎo)致主從上出現(xiàn)重新執(zhí)行 bgsave 和 rdb 重傳操作無(wú)限循環(huán)。
當(dāng)主節(jié)點(diǎn)數(shù)據(jù)量較大,或者主從節(jié)點(diǎn)之間網(wǎng)絡(luò)延遲較大時(shí),可能導(dǎo)致該緩沖區(qū)的大小超過(guò)了限制,此時(shí)主節(jié)點(diǎn)會(huì)斷開(kāi)與從節(jié)點(diǎn)之間的連接;
這種情況可能引起全量復(fù)制 -> replication buffer 溢出導(dǎo)致連接中斷 -> 重連 -> 全量復(fù)制 -> replication buffer 緩沖區(qū)溢出導(dǎo)致連接中斷……的循環(huán)。
具體詳情:[top redis headaches for devops – replication buffer] 因而推薦把 replication buffer 的 hard/soft limit 設(shè)置成 512M。
config set client-output-buffer-limit "slave 536870912 536870912 0"復(fù)制代碼
65 哥:主從庫(kù)復(fù)制為何不使用 AOF 呢?相比 RDB 來(lái)說(shuō),丟失的數(shù)據(jù)更少。
這個(gè)問(wèn)題問(wèn)的好,原因如下:
RDB 文件是二進(jìn)制文件,網(wǎng)絡(luò)傳輸 RDB 和寫(xiě)入磁盤(pán)的 IO 效率都要比 AOF 高。
從庫(kù)進(jìn)行數(shù)據(jù)恢復(fù)的時(shí)候,RDB 的恢復(fù)效率也要高于 AOF。
65 哥:主從庫(kù)間的網(wǎng)絡(luò)斷了咋辦?斷開(kāi)后要重新全量復(fù)制么?
在 Redis 2.8 之前,如果主從庫(kù)在命令傳播時(shí)出現(xiàn)了網(wǎng)絡(luò)閃斷,那么,從庫(kù)就會(huì)和主庫(kù)重新進(jìn)行一次全量復(fù)制,開(kāi)銷(xiāo)非常大。
從 Redis 2.8 開(kāi)始,網(wǎng)絡(luò)斷了之后,主從庫(kù)會(huì)采用增量復(fù)制的方式繼續(xù)同步。
增量復(fù)制:用于網(wǎng)絡(luò)中斷等情況后的復(fù)制,只將中斷期間主節(jié)點(diǎn)執(zhí)行的寫(xiě)命令發(fā)送給從節(jié)點(diǎn),與全量復(fù)制相比更加高效。
repl_backlog_buffer
斷開(kāi)重連增量復(fù)制的實(shí)現(xiàn)奧秘就是 repl_backlog_buffer
緩沖區(qū),不管在什么時(shí)候 master 都會(huì)將寫(xiě)指令操作記錄在 repl_backlog_buffer
中,因?yàn)閮?nèi)存有限, repl_backlog_buffer
是一個(gè)定長(zhǎng)的環(huán)形數(shù)組,如果數(shù)組內(nèi)容滿(mǎn)了,就會(huì)從頭開(kāi)始覆蓋前面的內(nèi)容。
master 使用 master_repl_offset
記錄自己寫(xiě)到的位置偏移量,slave 則使用 slave_repl_offset
記錄已經(jīng)讀取到的偏移量。
master 收到寫(xiě)操作,偏移量則會(huì)增加。從庫(kù)持續(xù)執(zhí)行同步的寫(xiě)指令后,在 repl_backlog_buffer
的已復(fù)制的偏移量 slave_repl_offset 也在不斷增加。
正常情況下,這兩個(gè)偏移量基本相等。在網(wǎng)絡(luò)斷連階段,主庫(kù)可能會(huì)收到新的寫(xiě)操作命令,所以 master_repl_offset
會(huì)大于 slave_repl_offset
。
當(dāng)主從斷開(kāi)重連后,slave 會(huì)先發(fā)送 psync 命令給 master,同時(shí)將自己的 runID
,slave_repl_offset
發(fā)送給 master。
master 只需要把 master_repl_offset
與 slave_repl_offset
之間的命令同步給從庫(kù)即可。
增量復(fù)制執(zhí)行流程如下圖:
65 哥:repl_backlog_buffer 太小的話(huà)從庫(kù)還沒(méi)讀取到就被 Master 的新寫(xiě)操作覆蓋了咋辦?
我們要想辦法避免這個(gè)情況,一旦被覆蓋就會(huì)執(zhí)行全量復(fù)制。我們可以調(diào)整 repl_backlog_size 這個(gè)參數(shù)用于控制緩沖區(qū)大小。計(jì)算公式:
repl_backlog_buffer = second * write_size_per_second復(fù)制代碼
second:從服務(wù)器斷開(kāi)重連主服務(wù)器所需的平均時(shí)間;
write_size_per_second:master 平均每秒產(chǎn)生的命令數(shù)據(jù)量大小(寫(xiě)命令和數(shù)據(jù)大小總和);
例如,如果主服務(wù)器平均每秒產(chǎn)生 1 MB 的寫(xiě)數(shù)據(jù),而從服務(wù)器斷線(xiàn)之后平均要 5 秒才能重新連接上主服務(wù)器,那么復(fù)制積壓緩沖區(qū)的大小就不能低于 5 MB。
為了安全起見(jiàn),可以將復(fù)制積壓緩沖區(qū)的大小設(shè)為2 * second * write_size_per_second
,這樣可以保證絕大部分?jǐn)嗑€(xiàn)情況都能用部分重同步來(lái)處理。
65 哥:完成全量同步后,正常運(yùn)行過(guò)程如何同步呢?
當(dāng)主從庫(kù)完成了全量復(fù)制,它們之間就會(huì)一直維護(hù)一個(gè)網(wǎng)絡(luò)連接,主庫(kù)會(huì)通過(guò)這個(gè)連接將后續(xù)陸續(xù)收到的命令操作再同步給從庫(kù),這個(gè)過(guò)程也稱(chēng)為基于長(zhǎng)連接的命令傳播,使用長(zhǎng)連接的目的就是避免頻繁建立連接導(dǎo)致的開(kāi)銷(xiāo)。
在命令傳播階段,除了發(fā)送寫(xiě)命令,主從節(jié)點(diǎn)還維持著心跳機(jī)制:PING 和 REPLCONF ACK。
每隔指定的時(shí)間,主節(jié)點(diǎn)會(huì)向從節(jié)點(diǎn)發(fā)送 PING 命令,這個(gè) PING 命令的作用,主要是為了讓從節(jié)點(diǎn)進(jìn)行超時(shí)判斷。
在命令傳播階段,從服務(wù)器默認(rèn)會(huì)以每秒一次的頻率,向主服務(wù)器發(fā)送命令:
REPLCONF ACK <replication_offset>復(fù)制代碼
其中 replication_offset 是從服務(wù)器當(dāng)前的復(fù)制偏移量。發(fā)送 REPLCONF ACK 命令對(duì)于主從服務(wù)器有三個(gè)作用:
檢測(cè)主從服務(wù)器的網(wǎng)絡(luò)連接狀態(tài)。
輔助實(shí)現(xiàn) min-slaves 選項(xiàng)。
檢測(cè)命令丟失, 從節(jié)點(diǎn)發(fā)送了自身的 slave_replication_offset,主節(jié)點(diǎn)會(huì)用自己的 master_replication_offset 對(duì)比,如果從節(jié)點(diǎn)數(shù)據(jù)缺失,主節(jié)點(diǎn)會(huì)從 repl_backlog_buffer
緩沖區(qū)中找到并推送缺失的數(shù)據(jù)。注意,offset 和 repl_backlog_buffer 緩沖區(qū),不僅可以用于部分復(fù)制,也可以用于處理命令丟失等情形;區(qū)別在于前者是在斷線(xiàn)重連后進(jìn)行的,而后者是在主從節(jié)點(diǎn)沒(méi)有斷線(xiàn)的情況下進(jìn)行的。
在 Redis 2.8 及以后,從節(jié)點(diǎn)可以發(fā)送 psync 命令請(qǐng)求同步數(shù)據(jù),此時(shí)根據(jù)主從節(jié)點(diǎn)當(dāng)前狀態(tài)的不同,同步方式可能是全量復(fù)制或部分復(fù)制。本文以 Redis 2.8 及之后的版本為例。
關(guān)鍵就是 psync
的執(zhí)行:
從節(jié)點(diǎn)根據(jù)當(dāng)前狀態(tài),發(fā)送 psync
命令給 master:
如果從節(jié)點(diǎn)從未執(zhí)行過(guò) replicaof
,則從節(jié)點(diǎn)發(fā)送 psync ? -1
,向主節(jié)點(diǎn)發(fā)送全量復(fù)制請(qǐng)求;
如果從節(jié)點(diǎn)之前執(zhí)行過(guò) replicaof
則發(fā)送 psync <runID> <offset>
, runID 是上次復(fù)制保存的主節(jié)點(diǎn) runID,offset 是上次復(fù)制截至?xí)r從節(jié)點(diǎn)保存的復(fù)制偏移量。
主節(jié)點(diǎn)根據(jù)接受到的psync
命令和當(dāng)前服務(wù)器狀態(tài),決定執(zhí)行全量復(fù)制還是部分復(fù)制:
runID 與從節(jié)點(diǎn)發(fā)送的 runID 相同,且從節(jié)點(diǎn)發(fā)送的 slave_repl_offset
之后的數(shù)據(jù)在 repl_backlog_buffer
緩沖區(qū)中都存在,則回復(fù) CONTINUE
,表示將進(jìn)行部分復(fù)制,從節(jié)點(diǎn)等待主節(jié)點(diǎn)發(fā)送其缺少的數(shù)據(jù)即可;
runID 與從節(jié)點(diǎn)發(fā)送的 runID 不同,或者從節(jié)點(diǎn)發(fā)送的 slave_repl_offset 之后的數(shù)據(jù)已不在主節(jié)點(diǎn)的 repl_backlog_buffer
緩沖區(qū)中 (在隊(duì)列中被擠出了),則回復(fù)從節(jié)點(diǎn) FULLRESYNC <runid> <offset>
,表示要進(jìn)行全量復(fù)制,其中 runID 表示主節(jié)點(diǎn)當(dāng)前的 runID,offset 表示主節(jié)點(diǎn)當(dāng)前的 offset,從節(jié)點(diǎn)保存這兩個(gè)值,以備使用。
一個(gè)從庫(kù)如果和主庫(kù)斷連時(shí)間過(guò)長(zhǎng),造成它在主庫(kù) repl_backlog_buffer
的 slave_repl_offset 位置上的數(shù)據(jù)已經(jīng)被覆蓋掉了,此時(shí)從庫(kù)和主庫(kù)間將進(jìn)行全量復(fù)制。
總結(jié)下
每個(gè)從庫(kù)會(huì)記錄自己的 slave_repl_offset
,每個(gè)從庫(kù)的復(fù)制進(jìn)度也不一定相同。
在和主庫(kù)重連進(jìn)行恢復(fù)時(shí),從庫(kù)會(huì)通過(guò) psync 命令把自己記錄的 slave_repl_offset
發(fā)給主庫(kù),主庫(kù)會(huì)根據(jù)從庫(kù)各自的復(fù)制進(jìn)度,來(lái)決定這個(gè)從庫(kù)可以進(jìn)行增量復(fù)制,還是全量復(fù)制。
replication buffer 和 repl_backlog
replication buffer 對(duì)應(yīng)于每個(gè) slave,通過(guò) config set client-output-buffer-limit slave
設(shè)置。
repl_backlog_buffer
是一個(gè)環(huán)形緩沖區(qū),整個(gè) master 進(jìn)程中只會(huì)存在一個(gè),所有的 slave 公用。repl_backlog 的大小通過(guò) repl-backlog-size 參數(shù)設(shè)置,默認(rèn)大小是 1M,其大小可以根據(jù)每秒產(chǎn)生的命令、(master 執(zhí)行 rdb bgsave) +( master 發(fā)送 rdb 到 slave) + (slave load rdb 文件)時(shí)間之和來(lái)估算積壓緩沖區(qū)的大小,repl-backlog-size 值不小于這兩者的乘積。
總的來(lái)說(shuō),replication buffer
是主從庫(kù)在進(jìn)行全量復(fù)制時(shí),主庫(kù)上用于和從庫(kù)連接的客戶(hù)端的 buffer,而 repl_backlog_buffer
是為了支持從庫(kù)增量復(fù)制,主庫(kù)上用于持續(xù)保存寫(xiě)操作的一塊專(zhuān)用 buffer。
repl_backlog_buffer
是一塊專(zhuān)用 buffer,在 Redis 服務(wù)器啟動(dòng)后,開(kāi)始一直接收寫(xiě)操作命令,這是所有從庫(kù)共享的。主庫(kù)和從庫(kù)會(huì)各自記錄自己的復(fù)制進(jìn)度,所以,不同的從庫(kù)在進(jìn)行恢復(fù)時(shí),會(huì)把自己的復(fù)制進(jìn)度(slave_repl_offset
)發(fā)給主庫(kù),主庫(kù)就可以和它獨(dú)立同步。
如圖所示:
數(shù)據(jù)過(guò)期問(wèn)題
65 哥:主從復(fù)制的場(chǎng)景下,從節(jié)點(diǎn)會(huì)刪除過(guò)期數(shù)據(jù)么?
這個(gè)問(wèn)題問(wèn)得好,為了主從節(jié)點(diǎn)的數(shù)據(jù)一致性,從節(jié)點(diǎn)不會(huì)主動(dòng)刪除數(shù)據(jù)。我們知道 Redis 有兩種刪除策略:
惰性刪除:當(dāng)客戶(hù)端查詢(xún)對(duì)應(yīng)的數(shù)據(jù)時(shí),Redis 判斷該數(shù)據(jù)是否過(guò)期,過(guò)期則刪除。
定期刪除:Redis 通過(guò)定時(shí)任務(wù)刪除過(guò)期數(shù)據(jù)。
65 哥:那客戶(hù)端通過(guò)從節(jié)點(diǎn)讀取數(shù)據(jù)會(huì)不會(huì)讀取到過(guò)期數(shù)據(jù)?
Redis 3.2 開(kāi)始,通過(guò)從節(jié)點(diǎn)讀取數(shù)據(jù)時(shí),先判斷數(shù)據(jù)是否已過(guò)期。如果過(guò)期則不返回客戶(hù)端,并且刪除數(shù)據(jù)。
如果 Redis 單機(jī)內(nèi)存達(dá)到 10GB,一個(gè)從節(jié)點(diǎn)的同步時(shí)間在幾分鐘的級(jí)別;如果從節(jié)點(diǎn)較多,恢復(fù)的速度會(huì)更慢。如果系統(tǒng)的讀負(fù)載很高,而這段時(shí)間從節(jié)點(diǎn)無(wú)法提供服務(wù),會(huì)對(duì)系統(tǒng)造成很大的壓力。
如果數(shù)據(jù)量過(guò)大,全量復(fù)制階段主節(jié)點(diǎn) fork + 保存 RDB 文件耗時(shí)過(guò)大,從節(jié)點(diǎn)長(zhǎng)時(shí)間接收不到數(shù)據(jù)觸發(fā)超時(shí),主從節(jié)點(diǎn)的數(shù)據(jù)同步同樣可能陷入全量復(fù)制->超時(shí)導(dǎo)致復(fù)制中斷->重連->全量復(fù)制->超時(shí)導(dǎo)致復(fù)制中斷……的循環(huán)。
此外,主節(jié)點(diǎn)單機(jī)內(nèi)存除了絕對(duì)量不能太大,其占用主機(jī)內(nèi)存的比例也不應(yīng)過(guò)大:最好只使用 50% - 65% 的內(nèi)存,留下 30%-45% 的內(nèi)存用于執(zhí)行 bgsave 命令和創(chuàng)建復(fù)制緩沖區(qū)等。
關(guān)于“Redis中主從架構(gòu)數(shù)據(jù)一致性同步原理的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
網(wǎng)頁(yè)名稱(chēng):Redis中主從架構(gòu)數(shù)據(jù)一致性同步原理的示例分析
鏈接URL:http://jinyejixie.com/article42/gcehhc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供域名注冊(cè)、小程序開(kāi)發(fā)、網(wǎng)站制作、云服務(wù)器、關(guān)鍵詞優(yōu)化、面包屑導(dǎo)航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)