1. 程式人生 > >redis的主從複製原理

redis的主從複製原理

1. 前言

        和MySQL主從複製的原因一樣,Redis雖然讀取寫入的速度都特別快,但是也會產生讀壓力特別大的情況。為了分擔讀壓力,Redis支援主從複製,Redis主從複製可以根據是否是全量分為全量同步和增量同步。

2. 舊版複製功能實現

redis複製功能分為同步和命令傳播兩種操作:

(1)同步操作負責將從資料庫的狀態更新為和主資料庫狀態一致

(2)命令傳播操作則用於當主伺服器狀態修改時,讓從伺服器狀態重新回到一致

2.1 同步

同步操作由sync操作完成:

(1)從伺服器向主伺服器傳送sync命令

(2)收到sync命令的主伺服器執行BGSAVE命令,生成RDB檔案,並使用一個緩衝區快取生成RDB期間所有的寫命令

(3)RDB生成完成時,傳送RDB給從伺服器,從伺服器載入RDB,狀態和主伺服器一致

(4)然後主伺服器將緩衝區中的寫命令全部傳給從伺服器,狀態一致

2.2 命令傳播

       同步操作完成後,主從狀態一致,但是每當客戶端向主伺服器執行寫命令時,主伺服器會修改,和從伺服器狀態不一致,為了讓主從狀態重新回到一致,主伺服器會發送寫命令給從伺服器,讓從伺服器回到和主伺服器一致的狀態。

2.3 舊版複製功能的不足之處

在redis2.8之前,主從伺服器的複製會分為兩種:

(1)初次複製:從伺服器以前從沒複製過其他主伺服器,或者從伺服器的主伺服器換了

(2)斷線後複製:處於命令傳播階段的主從伺服器,發生了斷線,重新連上後,從伺服器繼續複製主伺服器

為什麼說效率低呢?因為在舊版複製中,斷線重新連線後進行的複製,是通過sync命令實現的,而之前說了sync命令實現是主伺服器重新生成RDB檔案,傳送給從伺服器,重新生成RDB是很低效的,而且主伺服器生成RDB時是阻塞狀態的,所以舊版複製是低效率的。

3. 新版複製功能實現

為了解決舊版複製低效問題,新版複製採用了psync命令來代替sync命令,psync命令具有完全重同步和部分重同步:

(1)完全重同步:和上面的sync一樣

(2)部分重同步:專門用於負責處理斷線後重連,通過重連後只執行斷線期間的寫命令而不是全同步來達到高效

3.1 部分重同步實現

部分重同步實現由以下三部分構成:

(1)主伺服器的複製偏移量和從伺服器的複製偏移量

(2)主伺服器的複製積壓緩衝區

(3)伺服器執行ID

3.1.1 複製偏移量

主從伺服器都會維持一個複製偏移量:

  • 主伺服器每次向從伺服器傳送n個位元組的命令,就在自己複製偏移量加n
  • 從伺服器每次接收到n個位元組資料,就在自己複製偏移量加n

       例如,主從伺服器當前偏移是100,主向從伺服器傳送33個位元組命令,那麼主從此時的複製偏移量都是133,所以判斷主從當前狀態是否一致,可以通過複製偏移量來判斷:複製偏移量如果一樣,就代表狀態一致,否則不一致。如果斷線時,從伺服器因為收不到命令,而主伺服器一直髮送命令,這時的偏移量肯定不一樣,所以狀態不一致,那麼如果讓中間漏掉的命令重新傳給從伺服器呢,這和積壓緩衝區有關。

3.1.2 複製積壓緩衝區

複製積壓緩衝區是一個主伺服器維護的固定長度的先進先出佇列。每當主伺服器進行命令傳播時,它不僅將命令傳給從伺服器,還會將命令寫入到緩衝區:

              

如上圖所示,就是一個積壓緩衝區的現狀,當從伺服器重連後,向主伺服器傳送一個psycn命令,同時會將從伺服器當前的複製偏移量(offset)帶過去,主伺服器會根據從伺服器的offset,來決定是全同步還是部分同步:

(1)如果從伺服器的offset是10086,那麼此時要複製的偏移量應該是從10087開始,在緩衝區存在,將從10087開始往後所有資料都發送給從伺服器,所以執行的是部分重同步

(2)相反的,如果不存在,就需要進行全同步了!

如下圖:如果進行部分重同步,就向從伺服器傳送一個CONTINUE回覆。

                                  

3.1.3 伺服器執行ID

除了複製偏移量和複製積壓緩衝區之外,實現部分重同步還需要用到伺服器執行ID(run ID):

  • 每個Redis伺服器,不論主伺服器還是從服務,都會有自己的執行ID

       當從伺服器對主伺服器進行初次複製時,主伺服器會將自己的執行ID傳送給從伺服器,而從伺服器則會將這個執行ID儲存起來(注意哦,是從伺服器儲存了主伺服器的ID)。

當從伺服器斷線並重新連上一個主伺服器時,從伺服器將向當前連線的主伺服器傳送之前儲存的執行ID:

  • 如果從伺服器儲存的執行ID和當前連線的主伺服器的執行ID相同,那麼說明從伺服器斷線之前複製的就是當前連線的這個主伺服器,主伺服器可以繼續嘗試執行部分重同步操作;
  • 相反地,如果從伺服器儲存的執行ID和當前連線的主伺服器的執行ID並不相同,那麼說明從伺服器斷線之前複製的主伺服器並不是當前連線的這個主伺服器,主伺服器將對從伺服器執行完整重同步操作。