部分同步的實(shí)現(xiàn)
部分重同步功能由以下三個(gè)部分構(gòu)成:
- 主服務(wù)器的 復(fù)制偏移量 (replication offset)和從服務(wù)器的復(fù)制偏移量;
- 主服務(wù)器的復(fù)制積壓緩沖區(qū) (replication backlog);
- 服務(wù)器的運(yùn)行ID (run ID)。
復(fù)制偏移量
執(zhí)行復(fù)制的雙方——主服務(wù)器和從服務(wù)器會(huì)分別維護(hù)一個(gè)復(fù)制偏移量:
- 主服務(wù)器每次向從服務(wù)器傳播N個(gè)字節(jié)的數(shù)據(jù)時(shí),就將自己的復(fù)制偏移量的值加上N;
- 從服務(wù)器每次收到主服務(wù)器傳播來(lái)的N個(gè)字節(jié)的數(shù)據(jù)時(shí),就將自己的復(fù)制偏移量的值加上N;
通過(guò)對(duì)比主從服務(wù)器的復(fù)制偏移量,程序可以很容易地知道主從服務(wù)器是否處于一致?tīng)顟B(tài):
- 如果主從服務(wù)器處于一致?tīng)顟B(tài),那么主從服務(wù)器兩者的偏移量總是相同的;
- 相反,如果主從服務(wù)器兩者的偏移量并不相同,那么說(shuō)明主從服務(wù)器并未處于一致?tīng)顟B(tài)。
如下面的情況:
假設(shè)從服務(wù)器A在斷線之后就立即重新連接主服務(wù)器,并且成功,那么接下來(lái), 從服務(wù)器將向主服務(wù)器發(fā)送PSYNC命令,報(bào)告從服務(wù)器A當(dāng)前的復(fù)制偏移量為10107 ,那么這時(shí),主服務(wù)器應(yīng)該對(duì)從服務(wù)器執(zhí)行完整重同步還是部分重同步呢?如果執(zhí)行部分重同步的話(huà),主服務(wù)器又如何補(bǔ)償從服務(wù)器A在斷線期間丟失的那部分?jǐn)?shù)據(jù)呢?以上問(wèn)題的答案都和復(fù)制積壓緩沖區(qū)有關(guān)。
復(fù)制積壓緩沖區(qū)
復(fù)制積壓緩沖區(qū)是由主服務(wù)器維護(hù)的一個(gè)固定長(zhǎng)度(fixed-size)先進(jìn)先出(FIFO)隊(duì)列,默認(rèn)大小為1MB。
和普通先進(jìn)先出隊(duì)列隨著元素的增加和減少而動(dòng)態(tài)調(diào)整長(zhǎng)度不同,固定長(zhǎng)度先進(jìn)先出隊(duì)列的長(zhǎng)度是固定的,當(dāng)入隊(duì)元素的數(shù)量大于隊(duì)列長(zhǎng)度時(shí),最先入隊(duì)的元素會(huì)被彈出,而新元素會(huì)被放入隊(duì)列。
當(dāng)主服務(wù)器進(jìn)行命令傳播時(shí),它不僅會(huì)將寫(xiě)命令發(fā)送給所有從服務(wù)器,還會(huì)將寫(xiě)命令入隊(duì)到復(fù)制積壓緩沖區(qū)里面,如圖所示。
因此,主服務(wù)器的復(fù)制積壓緩沖區(qū)里面會(huì)保存著一部分最近傳播的寫(xiě)命令,并且復(fù)制積壓緩沖區(qū)會(huì)為隊(duì)列中的每個(gè)字節(jié)記錄相應(yīng)的復(fù)制偏移量,就像下表所示的那樣:
當(dāng)從服務(wù)器重新連上主服務(wù)器時(shí),從服務(wù)器會(huì)通過(guò)PSYNC命令將自己的復(fù)制偏移量offset發(fā)送給主服務(wù)器,主服務(wù)器會(huì)根據(jù)這個(gè)復(fù)制偏移量來(lái)決定對(duì)從服務(wù)器執(zhí)行何種同步操作:
- 如果offset偏移量之后的數(shù)據(jù)(也即是偏移量offset+1開(kāi)始的數(shù)據(jù))仍然存在于復(fù)制積壓緩沖區(qū)里面,那么主服務(wù)器將對(duì)從服務(wù)器執(zhí)行部分重同步操作;
- 相反,如果offset偏移量之后的數(shù)據(jù)已經(jīng)不存在于復(fù)制積壓緩沖區(qū),那么主服務(wù)器將對(duì)從服務(wù)器執(zhí)行完整重同步操作。
根據(jù)需要調(diào)整復(fù)制積壓緩沖區(qū)的大小
Redis為復(fù)制積壓緩沖區(qū)設(shè)置的默認(rèn)大小為1MB,如果主服務(wù)器需要執(zhí)行大量寫(xiě)命令,又或者主從服務(wù)器斷線后重連接所需的時(shí)間比較長(zhǎng),那么這個(gè)大小也許并不合適。如果復(fù)制積壓緩沖區(qū)的大小設(shè)置得不恰當(dāng),那么PSYNC命令的復(fù)制重同步模式就不能正常發(fā)揮作用,因此,正確估算和設(shè)置復(fù)制積壓緩沖區(qū)的大小非常重要。
復(fù)制積壓緩沖區(qū)的最小大小可以根據(jù)公式 second * write_size_per_second來(lái)估算:
- 其中second為從服務(wù)器斷線后重新連接上主服務(wù)器所需的平均時(shí)間(以秒計(jì)算);
- 而write_size_per_second則是主服務(wù)器平均每秒產(chǎn)生的寫(xiě)命令數(shù)據(jù)量(協(xié)議格式(RESP協(xié)議)的寫(xiě)命令的長(zhǎng)度總和);
例如,如果主服務(wù)器平均每秒產(chǎn)生 1MB 的寫(xiě)數(shù)據(jù),而從服務(wù)器斷線之后平均要5秒才能重新連接上主服務(wù)器,那么復(fù)制積壓緩沖區(qū)的大小就不能低于5MB。
為了安全起見(jiàn),可以將 復(fù)制積壓緩沖區(qū)的大小 = 2 * second * write_size_per_second
,這樣可以保證絕大部分?jǐn)嗑€情況都能用部分同步來(lái)處理。
至于復(fù)制積壓緩沖區(qū)大小的修改方法,可以參考配置文件中關(guān)于 repl-backlog-size
選項(xiàng)的說(shuō)明。
服務(wù)器運(yùn)行ID
除了復(fù)制偏移量和復(fù)制積壓緩沖區(qū)之外,實(shí)現(xiàn)部分重同步還需要用到服務(wù)器運(yùn)行ID(run ID):
- 每個(gè)Redis服務(wù)器,不論主服務(wù)器還是從服務(wù),都會(huì)有自己的運(yùn)行ID;
- 運(yùn)行ID在服務(wù)器啟動(dòng)時(shí)自動(dòng)生成,由40個(gè)隨機(jī)的十六進(jìn)制字符組成,例如
53b9b28df8042fdc9ab5e3fcbbbabff1d5dce2b3
;
當(dāng)從服務(wù)器對(duì)主服務(wù)器進(jìn)行初次復(fù)制時(shí),主服務(wù)器會(huì)將自己的運(yùn)行ID傳送給從服務(wù)器,而從服務(wù)器則會(huì)將這個(gè)運(yùn)行ID保存起來(lái)(注意哦,是從服務(wù)器保存了主服務(wù)器的ID)。
當(dāng)從服務(wù)器斷線并重新連上一個(gè)主服務(wù)器時(shí),從服務(wù)器將向當(dāng)前連接的主服務(wù)器發(fā)送之前保存的運(yùn)行ID:
- 如果從服務(wù)器保存的運(yùn)行ID和當(dāng)前連接的主服務(wù)器的運(yùn)行ID相同,那么說(shuō)明從服務(wù)器斷線之前復(fù)制的就是當(dāng)前連接的這個(gè)主服務(wù)器,主服務(wù)器可以繼續(xù)嘗試執(zhí)行部分重同步操作;
- 相反地,如果從服務(wù)器保存的運(yùn)行ID和當(dāng)前連接的主服務(wù)器的運(yùn)行ID并不相同,那么說(shuō)明從服務(wù)器斷線之前復(fù)制的主服務(wù)器并不是當(dāng)前連接的這個(gè)主服務(wù)器,主服務(wù)器將對(duì)從服務(wù)器執(zhí)行完整重同步操作。
-
數(shù)據(jù)
+關(guān)注
關(guān)注
8文章
7104瀏覽量
89297 -
服務(wù)器
+關(guān)注
關(guān)注
12文章
9256瀏覽量
85763 -
數(shù)據(jù)庫(kù)
+關(guān)注
關(guān)注
7文章
3841瀏覽量
64545 -
Redis
+關(guān)注
關(guān)注
0文章
376瀏覽量
10898
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論