共計 3492 個字符,預計需要花費 9 分鐘才能閱讀完成。
Redis 中如何實現主從復制,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面丸趣 TV 小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
Redis 復制概論
數據庫復制指的是發生在不同數據庫實例之間,單向的信息傳播的行為,通常由被復制方和復制方組成,被復制方和復制方之間建立網絡連接,復制方式通常為被復制方主動將數據發送到復制方,復制方接收到數據存儲在當前實例,最終目的是為了保證雙方的數據一致、同步。
復制示意圖
Redis 復制方式
Redis 的復制方式有兩種,一種是主(master)- 從(slave)模式,一種是從(slave)- 從(slave)模式,因此 Redis 的復制拓撲圖會豐富一些,可以像星型拓撲,也可以像個有向無環:
Redis 集群復制結構圖
通過配置多個 Redis 實例獨立運行、定向復制,形成 Redis 集群,master 負責寫、slave 負責讀。
復制優點
通過配置多個 Redis 實例,數據備份在不同的實例上,主庫專注寫請求,從庫負責讀請求,這樣的好處主要體現在下面幾個方面:
1、高可用性
在一個 Redis 集群中,如果 master 宕機,slave 可以介入并取代 master 的位置,因此對于整個 Redis 服務來說不至于提供不了服務,這樣使得整個 Redis 服務足夠安全。
2、高性能
在一個 Redis 集群中,master 負責寫請求,slave 負責讀請求,這么做一方面通過將讀請求分散到其他機器從而大大減少了 master 服務器的壓力,另一方面 slave 專注于提供讀服務從而提高了響應和讀取速度。
3、水平擴展性
通過增加 slave 機器可以橫向(水平)擴展 Redis 服務的整個查詢服務的能力。
復制缺點
復制提供了高可用性的解決方案,但同時引入了分布式計算的復雜度問題,認為有兩個核心問題:
數據一致性問題,如何保證 master 服務器寫入的數據能夠及時同步到 slave 機器上。
編程復雜,如何在客戶端提供讀寫分離的實現方案,通過客戶端實現將讀寫請求分別路由到 master 和 slave 實例上。
上面兩個問題,尤其是第一個問題是 Redis 服務實現一直在演變,致力于解決的一個問題。
復制實時性和數據一致性矛盾
Redis 提供了提高數據一致性的解決方案,本文后面會進行介紹,一致性程度的增加雖然使得我能夠更信任數據,但是更好的一致性方案通常伴隨著性能的損失,從而減少了吞吐量和服務能力。然而我們希望系統的性能達到最優,則必須要犧牲一致性的程度,因此 Redis 的復制實時性和數據一致性是存在矛盾的。
Redis 復制原理及特性 slave 指向 master
舉個例子,我們有四臺 redis 實例,M1,R1、R2、R3,其中 M1 為 master,R1、R2、R3 分別為三臺 slave redis 實例。在 M1 啟動如下:
./redis-server ../redis8000.conf --port 8000
下面分別為 R1、R2、R3 的啟動命令:
./redis-server ../redis8001.conf --port 8001 --slaveof 127.0.0.1 8000 ./redis-server ../redis8002.conf --port 8002 --slaveof 127.0.0.1 8000 ./redis-server ../redis8003.conf --port 8003 --slaveof 127.0.0.1 8000
這樣,我們就成功的啟動了四臺 Redis 實例,master 實例的服務端口為 8000,R1、R2、R3 的服務端口分別為 8001、8002、8003,集群圖如下:
Redis 集群復制拓撲
上面的命令在 slave 啟動的時候就指定了 master 機器,我們也可以在 slave 運行的時候通過 slaveof 命令來指定 master 機器。
復制過程
Redis 復制主要由 SYNC 命令實現,復制過程如下圖:
Redis 復制過程
上圖為 Redis 復制工作過程:
slave 向 master 發送 sync 命令。
master 開啟子進程來講 dataset 寫入 rdb 文件,同時將子進程完成之前接收到的寫命令緩存起來。
子進程寫完,父進程得知,開始將 RDB 文件發送給 slave。
master 發送完 RDB 文件,將緩存的命令也發給 slave。
master 增量的把寫命令發給 slave。
值得注意的是,當 slave 跟 master 的連接斷開時,slave 可以自動的重新連接 master,在 redis2.8 版本之前,每當 slave 進程掛掉重新連接 master 的時候都會開始新的一輪全量復制。如果 master 同時接收到多個 slave 的同步請求,則 master 只需要備份一次 RDB 文件。
增量復制
上面復制過程介紹的最后提到,slave 和 master 斷開了、當 slave 和 master 重新連接上之后需要全量復制,這個策略是很不友好的,從 Redis2.8 開始,Redis 提供了增量復制的機制:
增量復制機制
master 除了備份 RDB 文件之外還會維護者一個環形隊列,以及環形隊列的寫索引和 slave 同步的全局 offset,環形隊列用于存儲最新的操作數據,當 slave 和 maste 斷開重連之后,會把 slave 維護的 offset,也就是上一次同步到哪里的這個值告訴 master,同時會告訴 master 上次和當前 slave 連接的 master 的 runid,滿足下面兩個條件,Redis 不會全量復制:
slave 傳遞的 run id 和 master 的 run id 一致。
master 在環形隊列上可以找到對呀 offset 的值。
滿足上面兩個條件,Redis 就不會全量復制,這樣的好處是大大的提高的性能,不做無效的功。
增量復制是由 psync 命令實現的,slave 可以通過 psync 命令來讓 Redis 進行增量復制,當然最終是否能夠增量復制取決于環形隊列的大小和 slave 的斷線時間長短和重連的這個 master 是否是之前的 master。
環形隊列大小配置參數:
repl-backlog-size 1mb
Redis 同時也提供了當沒有 slave 需要同步的時候,多久可以釋放環形隊列:
repl-backlog-ttl 3600
免持久化復制
免持久化機制官方叫做 Diskless Replication,前面基于 RDB 文件寫磁盤的方式可以看出,Redis 必須要先將 RDB 文件寫入磁盤,才進行網絡傳輸,那么為什么不能直接通過網絡把 RDB 文件傳送給 slave 呢?免持久化復制就是做這個事情的,而且在 Redis2.8.18 版本開始支持,當然目前還是實驗階段。
值得注意的是,一旦基于 Diskless Replication 的復制傳送開始,新的 slave 請求需要等待這次傳輸完畢才能夠得到服務。
是否開啟 Diskless Replication 的開關配置為:
repo-diskless-sync no
為了讓后續的 slave 能夠盡量趕上本次復制,Redis 提供了一個參數配置指定復制開始的時間延遲:
repl-diskless-sync-delay 5
slave 只讀模式
自從 Redis2.6 版本開始,支持對 slave 的只讀模式的配置,默認對 slave 的配置也是只讀。只讀模式的 slave 將會拒絕客戶端的寫請求,從而避免因為從 slave 寫入而導致的數據不一致問題。
半同步復制
和 MySQL 復制策略有點類似,Redis 復制本身是異步的,但也提供了半同步的復制策略,半同步復制策略在 Redis 復制中的語義是這樣的:
允許用戶給出這樣的配置:在 maste 接受寫操作的時候,只有當一定時間間隔內,至少有 N 臺 slave 在線,否則寫入無效。
上面功能的實現基于 Redis 下面特性:
Redis slaves 每秒鐘會 ping 一次 master,告訴 master 當前 slave 復制到哪里了。
Redis master 會記住每個 slave 復制到哪里了。
我們可以通過下面配置來指定時間間隔和 N 這個值:
min-slaves-to-write number of slaves min-slaves-max-lag number of seconds
當配置了上面兩個參數之后,一旦對于一個寫操作沒有滿足上面的兩個條件,則 master 會報錯,并且將本次寫操作視為無效。這有點像 CAP 理論中的“C”,即一致性實現,雖然半同步策略不能夠完全保證 master 和 slave 的數據一致性,但是相對減少了不一致性的窗口期。
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注丸趣 TV 行業資訊頻道,感謝您對丸趣 TV 的支持。