自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

救命!只有我還不明白R(shí)edis主從復(fù)制的原理嗎?

數(shù)據(jù)庫(kù) Redis
為了保證同步的效率,除了第一次需要?全量同步?以外,例如當(dāng)主從節(jié)點(diǎn)斷連后,則只需要?增量同步?,這是由主從庫(kù)的復(fù)制偏移量以及主庫(kù)的 ?repl_backlog_buffer? 復(fù)制積壓緩沖區(qū)來(lái)控制的。?

1. 引言

之前我們聊過 Redis 的數(shù)據(jù)結(jié)構(gòu)底層原理和持久化機(jī)制,這期我們來(lái)聊 Redis 的高可用主題。

時(shí)光穿梭機(jī):

  • Redis持久化都說(shuō)不明白?那今天先到這吧~
  • Redis數(shù)據(jù)結(jié)構(gòu)的底層原理

眾所周知,一個(gè)數(shù)據(jù)庫(kù)系統(tǒng)想要實(shí)現(xiàn)高可用,主要從以下兩個(gè)方面來(lái)考慮:

  1. 保證數(shù)據(jù)安全不丟失
  2. 系統(tǒng)可以正常提供服務(wù)

而 Redis 作為一個(gè)提供高效緩存服務(wù)的數(shù)據(jù)庫(kù),也不例外。

上期我們提到的 Redis 持久化策略,其實(shí)就是為了減少服務(wù)宕機(jī)后數(shù)據(jù)丟失,以及快速恢復(fù)數(shù)據(jù),也算是支持高可用的一種實(shí)現(xiàn)。

除此之外,Redis 還提供了其它幾種方式來(lái)保證系統(tǒng)高可用,業(yè)務(wù)中最常用的莫過于主從同步(也稱作主從復(fù)制)、Sentinel 哨兵機(jī)制以及 Cluster 集群。

同時(shí),這也是面試中出現(xiàn)頻率最高的幾個(gè)主題,這期我們先來(lái)講講 Redis 的主從復(fù)制。

2. 主從復(fù)制簡(jiǎn)介

Redis 同時(shí)支持主從復(fù)制和讀寫分離:一個(gè) Redis 實(shí)例作為主節(jié)點(diǎn) Master,負(fù)責(zé)寫操作。其它實(shí)例(可能有 1 或多個(gè))作為從節(jié)點(diǎn) Slave,負(fù)責(zé)復(fù)制主節(jié)點(diǎn)的數(shù)據(jù)。

2.1 架構(gòu)組件

圖片

主節(jié)點(diǎn)Master

數(shù)據(jù)更新:Master 負(fù)責(zé)處理所有的寫操作,包括寫入、更新和刪除等。

數(shù)據(jù)同步:寫操作在 Master 上執(zhí)行,然后 Master 將寫操作的結(jié)果同步到所有從節(jié)點(diǎn) Slave 上。

從節(jié)點(diǎn)Slave

數(shù)據(jù)讀?。篠lave 負(fù)責(zé)處理讀操作,例如獲取數(shù)據(jù)、查詢等。

數(shù)據(jù)同步:Slave 從 Master 復(fù)制數(shù)據(jù),并在本地保存一份與主節(jié)點(diǎn)相同的數(shù)據(jù)副本。

2.2 為什么要讀寫分離

1)防止并發(fā)

從上圖我們可以看出,數(shù)據(jù)是由主節(jié)點(diǎn)向從節(jié)點(diǎn)單向復(fù)制的,如果主、從節(jié)點(diǎn)都可以寫入數(shù)據(jù)的話,那么數(shù)據(jù)的一致性如何保證呢?

有聰明的小伙伴可能已經(jīng)想到了,那就是加鎖!

但是主、從節(jié)點(diǎn)分布在不同的服務(wù)器上,數(shù)據(jù)跨節(jié)點(diǎn)同步時(shí)又會(huì)出現(xiàn)分布式一致性的問題。而在高頻并發(fā)的場(chǎng)景下,解決加鎖后往往又會(huì)帶來(lái)其它的分布式問題,例如寫入效率低、吞吐量大幅下降等。

而對(duì)于 Redis 這樣一個(gè)高效緩存數(shù)據(jù)庫(kù)來(lái)說(shuō),性能降低是難以忍受的,所以加鎖不是一個(gè)優(yōu)秀的方案。

那如果不加鎖,使用最終一致性方式呢?

這樣 Redis 在主、從庫(kù)讀到的數(shù)據(jù)又可能會(huì)不一致,帶來(lái)業(yè)務(wù)上的挑戰(zhàn),用戶也是難以接受的。

業(yè)務(wù)為用戶服務(wù),技術(shù)為業(yè)務(wù)服務(wù)。

所以,為了權(quán)衡數(shù)據(jù)的并發(fā)問題和用戶體驗(yàn),我們只允許在主節(jié)點(diǎn)上寫入數(shù)據(jù),從節(jié)點(diǎn)上讀取數(shù)據(jù)。

不理解分布式一致性的同學(xué)可以看我之前的這篇文章:深入淺出:分布式、CAP和BASE理論

2)易于擴(kuò)展

我們都知道,大部分使用 Redis 的業(yè)務(wù)都是讀多寫少的。所以,我們可以根據(jù)業(yè)務(wù)量的規(guī)模來(lái)確定掛載幾個(gè)從節(jié)點(diǎn) Slave,當(dāng)緩存數(shù)據(jù)增大時(shí),我們可以很方便的擴(kuò)展從節(jié)點(diǎn)的數(shù)量,實(shí)現(xiàn)彈性擴(kuò)展。

同時(shí),讀寫分離還可以實(shí)現(xiàn)數(shù)據(jù)備份和負(fù)載均衡,從而提高可靠性和性能。

3)高可用保障

不僅如此,Redis 還可以手動(dòng)切換主從節(jié)點(diǎn),來(lái)做故障隔離和恢復(fù)。這樣,無(wú)論主節(jié)點(diǎn)或者從節(jié)點(diǎn)宕機(jī),其他節(jié)點(diǎn)依然可以保證服務(wù)的正常運(yùn)行。

3. 主從復(fù)制實(shí)現(xiàn)

3.1 開啟主從復(fù)制

要開啟主從復(fù)制,我們需要用到 replicaof 命令。

當(dāng)我們確定好主節(jié)點(diǎn)的 IP 地址和端口號(hào),在從庫(kù)執(zhí)行 replicaof <masterIP> <masterPort> 這個(gè)命令,就可以開啟主從復(fù)制。

注意,在 Redis5.0 之前,該命令為 slaveof

開啟主從復(fù)制后,應(yīng)用層采用讀寫分離,所有的寫操作在主節(jié)點(diǎn)進(jìn)行,所有讀操作在從節(jié)點(diǎn)進(jìn)行。

主從節(jié)點(diǎn)會(huì)保持?jǐn)?shù)據(jù)的最終一致性:主庫(kù)更新數(shù)據(jù)后,會(huì)同步給從庫(kù)。

3.2 主從復(fù)制過程

那主從庫(kù)同步什么時(shí)候開始和結(jié)束呢?

是一次性傳輸還是分批次寫入?Redis 主從節(jié)點(diǎn)在同步過程中網(wǎng)絡(luò)中斷了,沒傳輸完成的怎么辦?

帶著這些疑問我們來(lái)分析下,首先,Redis 第一次數(shù)據(jù)同步時(shí)分 3 個(gè)階段。

圖片

1)建立連接,請(qǐng)求數(shù)據(jù)同步

主從節(jié)點(diǎn)建立連接,從庫(kù)請(qǐng)求數(shù)據(jù)同步。

從服務(wù)器從 replicaof 配置項(xiàng)中獲取主節(jié)點(diǎn)的 IP 和 Port,然后進(jìn)行連接。

連接成功后,從服務(wù)器會(huì)向主服務(wù)器發(fā)送 PSYNC 命令,表示要進(jìn)行同步。同時(shí),命令中包含 runID 和 offset 兩個(gè)關(guān)鍵字段。

  • runID:每個(gè) Redis 實(shí)例的唯一標(biāo)識(shí),當(dāng)主從復(fù)制進(jìn)行時(shí),該值為 Redis 主節(jié)點(diǎn)實(shí)例的ID。由于首次同步時(shí)還不知道主庫(kù)的實(shí)例ID,所以該值第一次為 ?
  • offset:從庫(kù)數(shù)據(jù)同步的偏移量,當(dāng)?shù)谝淮螐?fù)制時(shí),該值為 -1,表示全量復(fù)制

主服務(wù)器收到 PSYNC 命令后,會(huì)創(chuàng)建一個(gè)專門用于復(fù)制的后臺(tái)線程(replication thread),然后記錄從節(jié)點(diǎn)的 offset 參數(shù)并開始進(jìn)行 RDB 同步。

2)RDB 同步

主庫(kù)生成 RDB 文件,同步給從庫(kù)。

當(dāng)從服務(wù)器連接到主服務(wù)器后,主服務(wù)器會(huì)將自己的數(shù)據(jù)發(fā)送給從服務(wù)器,這個(gè)過程叫做全量復(fù)制。主服務(wù)器會(huì)執(zhí)行 bgsave 命令,然后 fork 出一個(gè)子進(jìn)程來(lái)遍歷自己的數(shù)據(jù)集并生成一個(gè) RDB 文件,將這個(gè)文件發(fā)送給從服務(wù)器。

在這期間,為了保證 Redis 的高性能,主節(jié)點(diǎn)的主進(jìn)程不會(huì)被阻塞,依舊對(duì)外提供服務(wù)并接收數(shù)據(jù)寫入緩沖區(qū)中。

從服務(wù)器接收到 RDB 文件后,會(huì)清空自身數(shù)據(jù),然后加載這個(gè)文件,將自己的數(shù)據(jù)集替換成主服務(wù)器的數(shù)據(jù)集。

3)命令同步

在第一次同步過程中,由于是全量同步,所以用時(shí)可能比較長(zhǎng),這期間主庫(kù)依舊會(huì)寫入新數(shù)據(jù)。

但是,在數(shù)據(jù)同步一開始就生成的 RDB 文件中顯然是沒有這部分新增數(shù)據(jù)的,所以第一次數(shù)據(jù)同步后需要再發(fā)送一次這部分新增數(shù)據(jù)。

這樣,主服務(wù)器需要在發(fā)送完 RDB 文件后,將期間的寫操作重新發(fā)送給從服務(wù)器,以保證從服務(wù)器的數(shù)據(jù)集與主服務(wù)器保持一致。

3.3 增量同步

1)命令傳播

在完成全量復(fù)制后,主從服務(wù)器之間會(huì)保持一個(gè) TCP 連接,主服務(wù)器會(huì)將自己的寫操作發(fā)送給從服務(wù)器,從服務(wù)器執(zhí)行這些寫操作,從而保持?jǐn)?shù)據(jù)一致性,這個(gè)過程也稱為基于長(zhǎng)連接的命令傳播(command propagation)。

增量復(fù)制的數(shù)據(jù)是異步復(fù)制的,但通過記錄寫操作,主從服務(wù)器之間的數(shù)據(jù)最終會(huì)達(dá)到一致狀態(tài)。

2)網(wǎng)絡(luò)斷開后數(shù)據(jù)同步

命令傳播的過程中,由于網(wǎng)絡(luò)抖動(dòng)或故障導(dǎo)致連接斷開,此時(shí)主節(jié)點(diǎn)上新的寫命令將無(wú)法同步到從庫(kù)。

即便是抖動(dòng)瞬間又恢復(fù)網(wǎng)絡(luò)連接,但 TCP 連接已經(jīng)斷開,所以數(shù)據(jù)需要重新同步。

從 Redis 2.8 開始,從庫(kù)已支持增量同步,只會(huì)把斷開的時(shí)候沒有發(fā)生的寫命令,同步給從庫(kù)。

圖片

詳細(xì)過程如下:

  1. 網(wǎng)絡(luò)恢復(fù)后,從庫(kù)攜帶之前主庫(kù)返回的 runid,還有復(fù)制的偏移量 offset 發(fā)送 psync runid offset 命令給主庫(kù),請(qǐng)求數(shù)據(jù)同步;
  2. 主庫(kù)收到命令后,核查 runid 和 offset,確認(rèn)沒問題將響應(yīng) continue 命令;
  3. 主庫(kù)發(fā)送網(wǎng)絡(luò)斷開期間的寫命令,從庫(kù)接收命令并執(zhí)行。

這時(shí),有細(xì)心的小伙伴可能要問了,網(wǎng)絡(luò)斷開后,主庫(kù)怎么知道哪些數(shù)據(jù)是新寫入的呢?

這是個(gè)好問題,接下來(lái)我們?cè)敿?xì)說(shuō)明一下。

3)增量復(fù)制的關(guān)鍵

Master 在執(zhí)行寫操作時(shí),會(huì)將這些命令記錄在 repl_backlog_buffer (復(fù)制積壓緩沖區(qū))里面,并使用 master_repl_offset 記錄寫入的位置偏移量。

而從庫(kù)在執(zhí)行同步的寫命令后,也會(huì)用 slave_repl_offset 記錄寫入的位置偏移量。正常情況下,從庫(kù)會(huì)和主庫(kù)的偏移量保持一致。

但是,當(dāng)網(wǎng)絡(luò)斷開后,主庫(kù)繼續(xù)寫入,而從庫(kù)沒有收到新的同步命令,所以偏移量就停止了。所以,master_repl_offset 會(huì)大于 slave_repl_offset。

注意:主從庫(kù)實(shí)現(xiàn)增量復(fù)制時(shí),都是在 repl_backlog_buffer 緩沖區(qū)上進(jìn)行。

網(wǎng)絡(luò)斷開前后,主從庫(kù)的同步圖如下:

圖片

repl_backlog_buffer 復(fù)制積壓緩沖區(qū)是一個(gè)環(huán)形緩沖區(qū),如果緩沖區(qū)慢了(比如超過 1024),則會(huì)從頭覆蓋掉前面的內(nèi)容。

所以,當(dāng)網(wǎng)絡(luò)恢復(fù)以后,主節(jié)點(diǎn)只需將 master_repl_offset 和 slave_repl_offset 之間的內(nèi)容同步給從庫(kù)即可(圖中 256~512 這部分?jǐn)?shù)據(jù))。

需要注意的是,主庫(kù)的積壓緩沖區(qū)默認(rèn)為 1M,如果從庫(kù)網(wǎng)絡(luò)斷開太久,緩沖區(qū)之前的內(nèi)容已經(jīng)被覆蓋,這時(shí)主從的數(shù)據(jù)復(fù)制就只能采取全量同步了。

所以我們需要根據(jù)業(yè)務(wù)量和實(shí)際情況來(lái)設(shè)置 repl_backlog_buffer 的值。

4. 小結(jié)

面讓架構(gòu)易于擴(kuò)展,另一方面防止單體故障:當(dāng)主庫(kù)掛了,可以立即拉起從庫(kù),不至于讓業(yè)務(wù)停滯太久。

而首次主從復(fù)制包括建立連接,RDB 同步和命令同步三個(gè)階段。

為了保證同步的效率,除了第一次需要全量同步以外,例如當(dāng)主從節(jié)點(diǎn)斷連后,則只需要增量同步,這是由主從庫(kù)的復(fù)制偏移量以及主庫(kù)的 repl_backlog_buffer 復(fù)制積壓緩沖區(qū)來(lái)控制的。

責(zé)任編輯:武曉燕 來(lái)源: xin猿意碼
相關(guān)推薦

2020-04-14 16:26:22

MySQL線程同步

2025-03-25 08:50:00

2023-12-25 08:02:09

2025-03-24 00:00:15

2023-09-24 14:32:15

2024-07-04 08:00:24

2018-05-14 11:31:02

2018-05-14 17:36:59

2025-01-15 15:47:36

2017-09-05 16:00:49

MySQL主從復(fù)制備份

2015-12-23 11:32:50

2022-11-25 07:59:43

JavaIOGuava

2021-01-12 09:03:17

MySQL復(fù)制半同步

2023-03-19 22:38:12

邏輯復(fù)制PostgreSQL

2023-03-19 11:53:27

2023-03-15 08:30:37

2009-04-23 08:31:23

微軟鮑爾默收購(gòu)

2025-02-28 00:00:00

2021-05-28 11:54:29

MySQL數(shù)據(jù)庫(kù)主從復(fù)制

2024-07-04 17:22:23

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)