一、什么是主從同步桅狠?
主從同步讼载,就是將數(shù)據(jù)冗余備份,主庫(kù)(Master)將自己庫(kù)中的數(shù)據(jù)中跌,同步給從庫(kù)(Slave)咨堤。
從庫(kù)可以一個(gè),也可以多個(gè)漩符,如圖所示:
二一喘、為什么需要主從同步?
Redis 雖然有 RDB 和 AOF 持久化技術(shù)嗜暴,可以在服務(wù)器重啟的情況下保證內(nèi)存中的數(shù)據(jù)不會(huì)丟失(但不意味著數(shù)據(jù)不丟凸克,重啟的時(shí)候還是會(huì)有不可用的情況)。
但是如果服務(wù)器關(guān)閉后闷沥,再也起不來(lái)了(比如硬件故障)萎战,那意味著數(shù)據(jù)是完全丟失的!會(huì)對(duì)業(yè)務(wù)產(chǎn)生重大影響舆逃。
所以蚂维,主從同步的必要性,在于數(shù)據(jù)的高可用路狮。它可以保證機(jī)器故障時(shí)虫啥,還有其他的服務(wù)器可以進(jìn)行故障轉(zhuǎn)移。
問(wèn)題來(lái)了奄妨,多臺(tái)服務(wù)器冗余同一份數(shù)據(jù)涂籽,Redis 是如何保證數(shù)據(jù)的一致性的?
三展蒂、Redis 是如何做到主從同步的又活?
簡(jiǎn)單概括,有兩點(diǎn):
- 一切修改只在主庫(kù)進(jìn)行:即主庫(kù)可讀可寫(xiě)锰悼,從庫(kù)只讀不可寫(xiě)柳骄;
- 寫(xiě)操作從主庫(kù)同步到從庫(kù):全量同步、增量同步箕般。
(一)全量同步
1. 建立連接 協(xié)商同步
1.1 使用客戶(hù)端 redis-cli 連接從庫(kù)耐薯,執(zhí)行 replicaof
命令,指定主庫(kù) IP 和端口丝里;
1.2 從庫(kù)響應(yīng)后曲初,執(zhí)行 psync 命令,它包含 主庫(kù) runid 和 復(fù)制偏移量 offset 兩個(gè)參數(shù):
- runid:?jiǎn)?dòng)時(shí)自動(dòng)生成隨機(jī)唯一 ID杯聚。首次同步時(shí)臼婆,主庫(kù) runid 未知,所以為
?
幌绍; - offset:表示復(fù)制的進(jìn)度颁褂,第一次同步時(shí),其值為
-1
傀广。
1.3 主庫(kù)收到 psync 命令后颁独,使用 FULLRESYNC
命令響應(yīng)從庫(kù),同時(shí)也包含 主庫(kù) runid 和 復(fù)制偏移量 offset 兩個(gè)參數(shù)伪冰,從庫(kù)會(huì)記錄這兩個(gè)參數(shù)誓酒。
注:replicaof 命令等同于 slaveof 命令,Redis 5.0 之前使用 slaveof 命令贮聂。
2. RDB 同步
2.1 主庫(kù)執(zhí)行 bgsave
命令靠柑,此時(shí)將 fork
出子進(jìn)程生成 RDB 文件,新命令會(huì)寫(xiě)入到緩沖區(qū)寂汇;
2.2 發(fā)送 RDB 文件到從庫(kù)病往;
2.3 從庫(kù)清空數(shù)據(jù)后,載入 RDB 文件骄瓣。
注一:為保證數(shù)據(jù)一致性停巷,
bgsave
執(zhí)行后,主庫(kù)會(huì)持續(xù)寫(xiě)入新命令到緩沖區(qū)榕栏,直到從庫(kù)加載 RDB 完成畔勤;注二:bgsave 創(chuàng)建了子進(jìn)程,子進(jìn)程獨(dú)立負(fù)責(zé) RDB 生成的工作扒磁,生成 RDB 的過(guò)程中庆揪,不會(huì)阻塞 Redis 主庫(kù),主庫(kù)依然可以正常處理命令妨托。
3. 命令同步
3.1 完成 RDB 載入后缸榛,從庫(kù)會(huì)回復(fù)確認(rèn)消息給主庫(kù)吝羞,主庫(kù)會(huì)將緩沖區(qū)的寫(xiě)命令發(fā)送給從庫(kù);
3.2 從庫(kù)接收主庫(kù)的寫(xiě)命令并執(zhí)行内颗,使得主從數(shù)據(jù)一致钧排。
注:命令執(zhí)行后,長(zhǎng)連接會(huì)一直保持均澳,寫(xiě)操作命令也會(huì)一直同步恨溜,保證主從數(shù)據(jù)的一致性;
這個(gè)過(guò)程也稱(chēng)為「基于長(zhǎng)連接的命令傳播」找前。
(二)增量同步
命令傳播的過(guò)程中糟袁,如果出現(xiàn) 網(wǎng)絡(luò)故障 導(dǎo)致連接斷開(kāi),此時(shí)新的寫(xiě)命令將無(wú)法同步到從庫(kù)躺盛。
即便是抖動(dòng)后斷開(kāi)又恢復(fù)網(wǎng)絡(luò)連接项戴,但此時(shí) TCP 連接已經(jīng)斷開(kāi),數(shù)據(jù)肯定是需要重新同步了槽惫。
- 在 Redis 2.8 之前肯尺,從庫(kù)只能和主庫(kù)重新發(fā)起全量同步,對(duì)于較大的 RDB 文件躯枢,網(wǎng)絡(luò)恢復(fù)時(shí)間較長(zhǎng)则吟;
- 從 Redis 2.8 開(kāi)始,從庫(kù)已支持增量同步锄蹂,只會(huì)把斷開(kāi)的時(shí)候沒(méi)有發(fā)生的寫(xiě)命令氓仲,同步給從庫(kù)。
詳細(xì)過(guò)程如下:
- 網(wǎng)絡(luò)恢復(fù)后得糜,從庫(kù)發(fā)生 psync 命令給主庫(kù)敬扛,并攜帶之前主庫(kù)返回的 runid,還有復(fù)制的偏移量 offset朝抖;
- 主庫(kù)收到命令后啥箭,核查 runid 和 offset,確認(rèn)沒(méi)問(wèn)題將響應(yīng)
CONTINUE
命令治宣; - 主庫(kù)發(fā)送網(wǎng)絡(luò)斷開(kāi)期間的寫(xiě)命令急侥,從庫(kù)接收命令并執(zhí)行。
實(shí)際上侮邀,主庫(kù)在進(jìn)行命令傳播的過(guò)程中坏怪,做了兩個(gè)事情:
- 發(fā)送寫(xiě)命令給從庫(kù);
- 寫(xiě)命令寫(xiě)入
repl_backlog_buffer
復(fù)制積壓緩沖區(qū)绊茧,保存最近傳播的寫(xiě)命令铝宵。
復(fù)制積壓緩沖區(qū),是一個(gè)環(huán)形緩沖區(qū)华畏。主庫(kù)除了擁有 repl_backlog_buffer鹏秋,還存在復(fù)制點(diǎn)位 master_repl_offset尊蚁;
同理,從庫(kù)侣夷,也有復(fù)制點(diǎn)位 slave_repl_offset枝誊;
如果從庫(kù)的 psync 命令指定的 offset,數(shù)據(jù)還存在 repl_backlog_buffer 緩沖區(qū)里惜纸,也就是:
master_repl_offset - size < slave_repl_offset,即主庫(kù)最小的偏移量绝骚,小于從庫(kù)的偏移量耐版,說(shuō)明數(shù)據(jù)還在環(huán)形緩沖區(qū)里。
所以压汪,只要主庫(kù)的緩沖區(qū)足夠大粪牲,足以容納最近的寫(xiě)命令(Redis 協(xié)議),就可以在網(wǎng)絡(luò)中斷后使用增量同步了止剖。
默認(rèn) repl_backlog_buffer = 1M腺阳,如果寫(xiě)入數(shù)據(jù)量較大,比如 1M/s穿香,顯然亭引,網(wǎng)絡(luò)故障 1秒后,復(fù)制積壓緩沖區(qū)數(shù)據(jù)無(wú)效皮获,所以應(yīng)該增大它的值焙蚓。
具體大小,需要根據(jù)實(shí)際情況確定洒宝。建議設(shè)置 10M 以上购公,大概就是 10s 以?xún)?nèi)的中斷,因?yàn)?Redis 服務(wù)器啟動(dòng)也需要一定時(shí)間雁歌。
文章來(lái)源于本人博客宏浩,發(fā)布于 2022-05-28,原文鏈接:https://imlht.com/archives/259/