首頁  >  文章  >  資料庫  >  深入了解Redis中的主從同步機制

深入了解Redis中的主從同步機制

青灯夜游
青灯夜游轉載
2021-11-16 18:54:585924瀏覽

這篇文章帶大家了解一下Redis中的主從同步,介紹一下Redis主從的兩種結構模型、主從關係的建立、主從複製策略等,希望對大家有所幫助!

深入了解Redis中的主從同步機制

先前的文章中詳細分析了redis的特性和核心原理,從本篇開始將對redis的部署結構和運作模式進行分析解讀。真正生產環境當中我們基本上不會使用單節點的redis來提供服務,至少是主從結構的哨兵或叢集模式,以保障redis服務的可靠性。本篇就來詳細解讀下redis的主從同步機制。 【相關建議:Redis影片教學

一、Redis主從有兩種結構模型:

深入了解Redis中的主從同步機制

##1.1主從複製

一主N從的這種複製結構複製關係只有一級,也是使用最多的形式,通常搭建哨兵或者集群結構的redis都是採用的這種複製結構,能夠通過一級從節點的複製關係很好的保證服務的可用性,做到異常情況主從切換。

1.2 級聯複製

級聯複製結構的複製關係可以有多級,一個主節點的從節點可以是下屬從節點的主節點。級聯複製結構的應用相對比較少,這種結構能夠在有多個從節點的結構下一定程度上緩解主節點的複製壓力。

二、Redis主從關係的建立

redis的主從同步始於命令SLAVEOF host port,透過這個命令能夠建立主從關係,SLAVEOF 命令用於在Redis 運行時動態地修改複製功能的行為。透過執行 SLAVEOF host port 指令,可以將目前伺服器轉變為指定伺服器的從屬伺服器(slave server)。如果目前伺服器已經是某個主伺服器(master server)的從屬伺服器,那麼執行 SLAVEOF host port 將使目前伺服器停止對舊主伺服器的同步,丟棄舊資料集,轉而開始對新主伺服器進行同步。另外,對一個從屬伺服器執行指令 SLAVEOF NO ONE 將使得這個從屬伺服器關閉複製功能,並從屬伺服器轉變回主伺服器,原來同步所得的資料集不會被丟棄。利用 SLAVEOF NO ONE 不會丟棄同步所得資料集這個特性,在沒有搭建哨兵和叢集的情況下,可以在主伺服器失敗的時候,將從屬伺服器用作新的主伺服器,從而實現無間斷運作。

下圖為主從關係建立流程:

深入了解Redis中的主從同步機制

注意:

#根據上執行流程這裡有一個需要注意點,當我們對一個已有主從關係的節點執行slaveof命令時,會結束掉現有的主從關係並清空節點下的所以數據,在生成環境當中這是比較威脅的操作。有沒有更安全的方式了?上面介紹slavelof指令的時候提到可以傳遞NO ONE參數,也就是執行SLAVEOF NO ONE指令,這個指令是只會結束主從複製關係不會清空資料的,相對安全很多。

三、資料同步

建立好主從關係後就要進入主從資料同步的過程了,這裡主要分三種情況,剛建立主從關係後的資料全量同步;初始化同步完成後的命令傳播階段;主從關係異常中斷重連後的同步方式選擇,這裡會有全量和增量同步兩種場景。

3.1 全量同步

  • 當slave節點啟動後或斷開重連後(重連不滿足增量同步條件),會傳送SYNC指令。

  • master節點收到SYNC指令後會開始在背景儲存快照(即RDB持久化,當主從複製時,會無條件觸發RDB),並將儲存快照期間接收到的命令緩存起來。

  • master節點執行RDB持久化完成後,向所有slave節點發送快照RDB文件,並在發送快照期間繼續記錄被執行的寫入命令。

  • slave節點收到快照檔案後丟棄所有舊資料(會清空所有資料),載入收到的快照。

  • master節點快照傳送完畢、slave節點載入快照完畢後,master節點開始傳送緩衝區中的寫入指令到slave節點。

  • slave節點完成對快照的載入,開始接收命令請求,並執行來自主資料庫緩衝區的寫入命令。 (從資料庫初始化完成)

  • master節點每執行一個寫入指令就會傳送相同的寫入指令,slave節點接收並執行收到的寫入指令。 (指令傳播操作,slave節點初始化完成後的操作)

全量同步流程如下圖:

深入了解Redis中的主從同步機制

在redis2.8之前,從節點無論是初始化或斷線重連後都是採用全量同步的方式,在2.8之後版本,引入PSYNC指令,在從節點斷線重連後會判斷是否採用增量同步。

3.2 增量同步

PSYNC具備了資料全量重同步和增量同步模式。

  • 全量重同步:跟舊版複製基本上是一致的,可以理解為「全量」複製。

  • 部分重同步:salve斷開又重新連時,在指令傳播階段,只需要發送與master斷開這段時間執行的寫命給slave即可,可以理解為“增量”複製。

PSYNC執行過程中比較重要的概念有3個:runid、offset(複製偏移量)以及複製積壓緩衝區。

1.runid

每個Redis伺服器都會有一個表明自己身分的ID。在PSYNC中發送的這個ID是指之前連接的Master的ID,如果沒保存這個ID,PSYNC的命令會使用”PSYNC ? -1” 這種形式發送給Master,表示需要全量複製。 

2.offset(複製偏移量)

在主從複製的Master和Slave雙方都會各自維持一個offset。 Master成功發送N個位元組的指令後會將Master裡的offset加上N,Slave在接收到N個位元組指令後同樣會將Slave裡的offset增加N。 Master和Slave如果狀態是一致的那麼它的的offset也應該是一致的。

3.複製積壓緩衝區

複製積壓緩衝區是由Master維護的一個固定長度環形積壓佇列(FIFO佇列),它的作用是快取已經傳播出去的命令。當Master進行指令傳播時,不僅將指令傳送給所有Slave,也會將指令寫入到複製積壓緩衝區裡面。 PSYNC執行過程和SYNC的差別在於:salve連接時,判斷是否需要全量同步,全量同步的邏輯過程和SYNC一樣。 PSYNC執行步驟如下:

  • 客戶端向伺服器發送SLAVEOF指令,也就是salve向master發起連線請求時,slave會根據自己是否儲存Master runid來判斷是否是第一次連線。

  • 如果是第一次同步則向Master發送PSYNC ? -1 指令來進行完整同步;如果是重連接,會向Master發送PSYNC runid offset指令(runid是master的身份ID,offset是從節點同步指令的全域遷移量)。

  • Master接收到PSYNC 指令後,先判斷runid是否和本機的id一致,如果一致則會再次判斷offset偏移量和本機的偏移量相差有沒有超過複製積壓緩衝區大小,如果沒有那麼就給Slave發送CONTINUE,此時Slave只需要等待Master傳回失去連線期間遺失的指令。如果runid和本機id不一致或offset差距超過了複製積壓緩衝區大小,那麼就會傳回FULLRESYNC runid offset,Slave將runid保存起來,並進行全量同步。

主節點在命令傳播時,主資料庫會將每個寫入命令傳遞給從資料庫的同時,都會將寫入命令存放到積壓隊列,並記錄當前積壓隊列中存放指令的全域偏移量offset。當salve重連接時,master會根據從節點傳的offset在環形積壓佇列中找到斷開這段時間執行的指令,並同步給salve節點,達到增量同步結果。

PSYNC執行流程如下圖:

深入了解Redis中的主從同步機制

從以上PSYNC的執行流程可以看出當slave節點斷線重連以後判斷是否採用增量同步的核心是slave的offset偏移量和master的偏移量相差有沒有超過複製積壓緩衝區大小,那麼這個大小是由下列參數來配置的。複製積壓緩衝區本質上是一個固定長度的循環隊列,預設情況下積壓隊列的大小為1MB,可以透過設定檔設定隊列大小:設定複製積壓緩衝區大小,積壓隊列越大,允許主從資料庫斷線的時間就越長

repl-backlog-size 1mb

Redis同時也提供了當沒有slave需要同步的時候,多久可以釋放環形佇列,預設一小時,沒有salve連線時,多久釋放一次複製積壓緩衝區

repl-backlog-ttl 3600

四、主从复制策略

Redis采用了乐观复制的策略,也就是在一定程度内容忍主从数据库的内容不一致,但是保持主从数据库数据的最终一致性。具体来说,Redis在主从复制的过程中,本身就是异步的,在主从数据库执行完客户端请求后会立即将结果返回给客户端,并异步的将命令同步给从数据库,但是这里并不会等待从数据库完全同步之后,再返回客户端。这一特性虽然保证了主从复制期间性能不受影响,但是也会产生一个数据不一致的时间窗口,如果在这个时间窗口期间网络突然断开连接,就会导致两者数据不一致。如果不在配置文件中添加其他策略,那就默认会采用这种方式。为了防止主从不一致不可控,redis提供了以下两个参数来做约束:

min-slaves-to-write 3
min-slaves-max-lag 10

当slave数量小于min-slaves-to-write,且延迟小于等于min-slaves-max-lag时,master停止写入操作。

还有一个参数也会影响主从之间的延时:

repl-disable-tcp-nodelay:

设置成yes,则redis会合并小的TCP包从而节省带宽,但会增加同步延迟,造成master与slave数据不一致。设置成no,则redis master会立即发送同步数据,几乎没有延迟。

Redis的主从同步无论那种场景可以抽象为以下七个步骤:

深入了解Redis中的主從同步機制

1.建立socket连接

从服务器根据设置的套接字创建连向主服务器的套接字连接,主服务器接收从服务器的套接字连接之后,为该套接字创建响应的客户端状态,并将此时的从服务器看做是主服务器的客户端,也就是该从服务器同时具备服务器与客户端两个身份。

2.发送PING命令

PING命令主要有两种作用:虽然建立了套接字连接,但是还未使用过,通过发送PING命令检查套接字的读写状态是否正常;通过发送PING命令检查主服务器能否正常处理命令请求,能处理主服务器回复PONG。

3.身份验证

从服务器接收到主服务器返回的“PONG”回复,接下来就需要考虑身份验证的事。如果从服务器设置了masterauth选项,那么进行身份验证,如果从服务器没有设置masterauth选项,那么不进行身份验证。

4.发送端口信息

在身份验证步骤之后,从服务器将执行命令REPLCONF listening-port ,向主服务器发送从服务器的监听端口号。

5.数据同步

从服务器向主服务器发送SYNC命令、PSYNC命令,执行同步操作。

6.命令传播

主从服务器就会进入命令传播阶段,主服务器只要将自己执行的写命令发送给从服务器,而从服务器只要一直执行并接收主服务器发来的写命令。

五、告一段落

本篇详细介绍了redis主从同步机制,不同场景下同步策略的选择,这也是redis高可用的基石。在此基础上,下一篇将对redis高可用的实现来进行分析讲解。

更多编程相关知识,请访问:编程视频!!

以上是深入了解Redis中的主從同步機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除