redis學習筆記(四)主從數據同步

2021-02-20 碼雲大作戰

    在redis恢復數據時我們可以依賴於aof日誌或rdb日誌,但是redis在運行中該如何保證服務的可靠性,就需要依賴redis主從和哨兵集群。

    這一篇主要學習下如何通過redis的主從設計來保證服務的高可用。主從模式的思想就在於增加從副本,將一份數據同時保存在主從多個實例上,這樣即使有一個實例出現了故障,其他實例也可以繼續對外提供服務,不會影響業務的使用。

一、redis主從模式的讀寫分離

    redis通過多實例來保存數據,為了保證redis實例數據的一致性,因此在主從模式下,主從之間採用的是讀寫分離的方式。

    讀操作:主、從實例都可以接收命令操作讀請求。

    寫操作:只有主可以執行,主執行完畢後將寫操作同步給從庫。

    以上的方式來解決多實例的一致性,也是比較方便簡單的。因為如果主從實例都可以接受寫請求,並且假設對同一個key修改了多次,並且每次都是請求到不同的主從實例上,那麼最直觀的結果可能出現數據不一致的情況。

    如果需要強制保持數據一致,那麼肯定需要涉及到鎖的開銷,阻塞住其他讀寫請求。

    因此有了主從模式的讀寫分離,寫命令就只會在主實例中修改,客戶端就不用關心從實例,這條寫命令會由主實例異步同步給從庫。


二、主從模式的第一次數據同步

    主從之間通過slaveof命令來將執行該命令的實例變為從庫。

    比如,有實例1(172.168.19.1)和實例2(172.168.19.2),在實例2中執行命令 - slaveof 172.168.19.1 6379。

    接下來,實例2就變成了實例1的從庫,然後會從實例1中複製數據。

·  第一次同步數據時的步驟

(1)主從建立連接,準備進行全量複製。從庫發送psync請求告訴主庫,要開始同步數據,主庫確認回復後,主從庫開始同步數據。

(2)主庫將所有數據同步給從庫,從庫收到數據後在本地完成數據加載。在加載主庫的數據主要是通過主庫的rdb快照文件來直接加載數據,並且在加載前會先清空當前從庫中的數據。

(3)主從同步期間新的請求處理,主庫會在內存中生成一個緩衝區(replication buffer)來記錄主從同步期間的新的寫操作。

(4)從庫獲取主庫發送過來的replicatio buffer緩衝區,開始執行新的寫請求,同步數據。

    以上就是主從第一次同步數據時的過程。第一次同步數據主要依賴於主庫的rdb日誌文件,後續的數據同步主要依賴於replication buffer緩衝區。

    同步數據流程圖如下所示:

    以上就是第一次主從同步數據的總體流程,在圖中我們可看到主實例接受到psync請求後,會進行FULLRESYNC響應,該響應傳遞了兩個參數:

    {runID}:主庫的唯一標記。

    {offset}:複製進度,如果是-1表示第一次複製。


replication buffer注意點:

    主實例會為每一個從實例都分配一個複製緩衝區,並不是所有的從實例共用一個緩衝區。

    緩衝區的設置需要合理,因為這是一個複製緩衝區所以畢竟會有大小限制,複製緩衝區如果一旦因為寫入的命令過多導致溢出,那麼主實例會直接關閉和從實例的連接,導致主從同步失敗。

    出現複製緩衝區溢出情況,可能在於全量複製時,從庫中加載主庫的rdb文件較慢,同時主節點接收了大量的寫命令,導致寫命令積累大小超過了緩衝區大小出現溢出。

    解決方案:

    (1)控制主節點數據的大小,一般將主節點的數據量控制在2~4GB即可,可以讓從節點加載全量的rdb文件時執行的快些。

    (2)合理設置複製緩衝區大小,命令 - config set client-output-buffer-limit slave 512mb 128mb 60

    第一個參數512mb表示緩衝區大小的上限為512mb。

    第二個、第三個參數128mb和60表示如果連續60秒內的寫入量超過128mb也會造成緩衝區溢出。

    可以根據以上命令來推斷負載情況,來合理設置緩衝區大小。比如上述命令(假設每條命令大小是1kb):

    複製緩衝區可以接受512mb / 1kb * 1000 = 512K條寫命令。

    可接受的寫命令速率上限為128mb / 1kb * 1000 / 60s = 2000條/s。

    (3)避免出現規模太大的從節點集群。因為主節點上複製緩衝區的總內存開銷 = 所有從節點的緩衝區內存之和,從而減少主節點的使用內存。

三、主從從模式的數據同步

    為什麼需要主從從模式?我們先來分析下,主從集群下會有什麼性能瓶頸。

    對於一個主從庫來說,需要完成兩個耗時操作,生成rdb文件和傳輸rdb文件。雖然rdb文件是異步生成的,但是還是得通過主線程來fork一個子進程來異步創建rdb文件,但是fork這個步驟會阻塞主線程,如果從實例很多的情況下,並每個從結點都需要進行全量複製,那麼這個fork就會變的很慢了。

    傳輸rdb文件在於主實例傳輸文件到從實例也會佔用主庫的網絡帶寬給主庫資源帶來壓力。

    所以使用了主從從模式來減少從實例過多帶給主實例的影響。

    主從從模式的工作圖:

    將部分從庫和其中一個從庫建立主從關係,並且那個從庫會和主庫建立主從關係。這樣全量複製時的壓力就會被分擔到那個有級聯主從關係的從庫中,減少了主庫的壓力。

四、增量複製緩衝區

    redis引入增量複製緩衝區的概念還是在2.8之前,因為之前如果redis出現了主從之間的網絡閃斷,那麼恢復後,從庫需要重新進行一遍全量複製來進行主從同步,增大開銷。

    有了增量複製緩衝區之後,如果主從之間檢測到網絡閃斷,從庫恢復後就通過增量複製緩衝區來找到未同步的位置,來繼續同步閃斷期間內的數據。

·  repl_backlog_buffer

    repl_backlog_buffer即增量複製緩衝區,他其實是一個環形的緩衝區,所以會有2個指針分別是主庫寫的位置和從庫讀的位置,還有一個偏移量,代表從庫還有多少數據沒用讀取完畢。

    剛開始主庫寫的位置和從庫讀的位置在同一位置,隨著寫命令的請求,主庫寫的位置就會不斷變大。每個從庫通過從庫的讀位置來判斷從庫閃斷前的位置,最終從庫在後續恢復後複製完寫操作命令後,他在緩衝區中的讀的位置應該與主庫寫的位置相等。

    如果出現從庫閃斷前的位置的數據被新一輪寫入的數據覆蓋 即環形緩衝區被主庫的寫命令所覆蓋了,那麼在從庫恢復後還是得重新做一次全量的數據主從同步。

    我們通常可以適當調大一些repl_backlog_size的參數。

    repl_backlog_size = 緩存空間大小 * 2。

    緩存空間大小 = 主庫寫入命令 * 操作大小 - 主從庫網絡傳輸命令速度 * 操作大小。

    比如,主庫每秒寫入2000個操作,每個操作大小為1KB,網絡每秒能傳輸1000個操作,那麼緩存空間大小 = 2000 * 1 - 1000 * 1 = 1000kb = 1mb。

所以為了應對突發的情況,需要設置repl_backlog_size 為2mb。

·  網絡閃斷恢復時主從數據同步工作流程

    主從庫恢復後,從庫首先會給主庫發送psync命令,並把自己當前的salve_repl_offset(從庫在增量複製緩衝區讀的位置)發給主庫,主庫會判斷master_repl_offset(主庫在增量複製緩衝區寫的位置)和salve_repl_offset之間的偏移量,然後把他們之間的命令操作通過複製緩衝區同步給從庫。


五、總結

    本文主要分析了redis在運行期間通過主從模式來保證高可用。而使用主從模式進行讀寫分離的好處:避免了加鎖的開銷。

    為了實現redis的高可用性,就會有多個redis實例,為了保證實例數據的最終一致性,主從數據同步中我們需要關心兩個緩衝區。

    (1)replication buffer:主實例和從實例數據同步時的複製緩衝區。

    (2)repl_backlog_buffer:從庫斷開之後,找到主從差異數據的環形緩衝區(增量複製緩衝區),減少主從閃斷恢復時全量恢復數據的開銷。

    不過單單的採用主從模式來保證高可用還是有很多弊端的,比如主實例故障的情況,因此redis的高可用性還需要哨兵集群來幫助,哨兵機制會在下一篇來進行分析。

問題一:那麼主從庫間的複製為什麼不使用aof文件

    假設要使用aof做全量同步,意味著必須打開aof功能,就要選擇aof刷盤策略,選擇不當會嚴重影響redis性能,而rdb只有在需要同步時才會觸發一次快照,對於一些redis數據不敏感的讀緩存模式的業務,其實不需要那麼依賴aof。

    所以在主從間複製使用aof文件,主要原因在於從庫恢復數據特別快,時間成本最低。

    另外aof日誌文件記錄的是每一次寫操作的命令,寫操作很多文件就會很大。而rdb文件內容是經過壓縮的二進位文件數據,文件很小,這也是aof文件在網絡傳輸時候的一個優勢。

問題二:replication buffer和repl_backlog_buffer的區別

    replication buffer是用在主從之間發送數據時或全量同步數據時的緩衝區,並且每個從庫都會生成一個複製緩衝區。

    repl_backlog_buffer是用來持續保持寫操作的一塊緩衝區,多個從庫共享一個增量緩衝區,在主庫啟動後就會創建出來。不同的從庫增量複製進度通過從庫讀取的指針和主庫寫的指針來控制。

    當出現主從閃斷,恢復後恢復數據時,如果出現從庫需要恢復的歷史數據在增量複製緩衝區中已經被覆蓋(因為是增量複製緩衝區是環形緩衝區),那麼就需要重新進行全量複製。

參考資料 - 《Redis核心技術與實戰》(數據同步:主從庫如何實現數據一致)

相關焦點

  • 如何實現redis主從複製?
    主從複製,主要優勢在於實現了數據備份(主機和從機數據同步一致)、讀寫分離(主機主要負責寫入數據,從機讀數據,在讀大於寫的項目中提高了性能)。最後也為後續集成哨兵機制和集群的實現提供了依據。單臺伺服器也可以實現主從複製,本質上是同時啟動幾個redis實例來實現。
  • 淺談Redis主從複製
    但Redis目前存在的一個問題是主從複製在遇到網絡不穩定的情況下,Slave和Master斷開(包括閃斷)會導致Master需要將內存中的數據全部重新生成rdb文件(快照文件),然後傳輸給Slave。Slave接收完Master傳遞過來的rdb文件以後會將自身的內存清空,把rdb文件重新加載到內存中。
  • Redis5.0:簡單的集群模式——主從模式詳解
    主從模式主從模式是最簡單的集群模式,其實就是複製基本只能解決讀寫分離問題, 主機伺服器一旦宕機基本完蛋,不具備高可用。幾乎所有的主從模式都是從伺服器只提供只讀不寫的功能,否則會出現數據不一致的情況,現在無論那種資料庫都不支持雙向同步。屁話少說,上配置代碼,主伺服器不需要配置,只需簡單一句代碼配置從伺服器即可,聲明主伺服器是誰,餘下的redis會自行交流。
  • Redis 單例、主從模式、sentinel 以及集群的配置方式及優缺點對比
    redis主從模式解決了數據備份和單例可能存在的性能問題,但是其也引入了新的問題。由於主從模式配置了三個redis實例,並且每個實例都使用不同的ip(如果在不同的機器上)和埠號。根據前面所述,主從模式下可以將讀寫操作分配給不同的實例進行從而達到提高系統吞吐量的目的,但也正是因為這種方式造成了使用上的不便,因為每個客戶端連接redis實例的時候都是指定了ip和埠號的,如果所連接的redis實例因為故障下線了,而主從模式也沒有提供一定的手段通知客戶端另外可連接的客戶端地址,因而需要手動更改客戶端配置重新連接。
  • 面試系列 - Redis 持久化和主從複製總結(二)
    save 300 10 # 300秒內改變10條數據,自動生成RDB文件 save 60 10000 dbfilename dump-${port}.rdb #區別不同redis的RDB文件 dir /bigdiskpath #指定RDB文件位置,建議bigdiskpath stop-writes-on-bgsave-error yes #異常時是否繼續dump,默認yes,建議yes rdbcompression
  • 主從哨兵集群終於給你說明白了
    Redis有三種集群模式,第一個就是主從模式,第二種「哨兵」模式,第三種是 Cluster 集群模式。今天就和大家細細聊聊這三種模式。主從複製當其中一臺伺服器更新之後,伺服器會自動的將這臺更新的數據同步到另外一臺伺服器上。通過持久化的功能,redis可以保證就算是服務宕機重啟了,也只有少量的數據會丟失。
  • 面試官:Redis 主從複製時網絡開小差了怎麼整?
    今天主要講的是主從複製數據一致性相關以及面對網絡中斷如何進行數據同步的問題。不 BB 了,直接上鍾吧!- 思維導圖 -主從模式配置對於 Redis 主從大家可能並不陌生,但是配置的話日常工作中並不會經常操作。在這裡簡單介紹下主從的相關配置。
  • Python | Python學習之Redis交互詳解
    前言最近在學習scrapy redis,順便複習了redis。本篇為redis篇,包含實例演示,主從服務配置,python交互等內容。log file /xx/xx/xx/redis-server.log 日誌文件位置slaveof ip port 主從複製的ip埠啟動redis:sudo server redis start停止redis:sudo server redis stop重啟redis:sudo server redis restart加載指定的redis
  • redis學習(四)鍵空間數據持久化
    上一篇文章學習了redis服務端的核心數據結構,其中就包含redisDB->dict 和redisDB->expire,本文學習持久化也是基於這兩個字典的
  • 三歪推薦:Redis常見的面試題
    如果不設置,默認選項將會是everysec,因為always來說雖然最安全(只會丟失一次事件循環的寫命令),但是性能較差,而everysec模式只不過會可能丟失1秒鐘的數據,而no模式的效率和everysec相仿,但是會丟失上次同步AOF文件之後的所有寫命令數據。
  • 5分鐘完全掌握 Redis
    如果不設置,默認選項將會是everysec,因為always來說雖然最安全(只會丟失一次事件循環的寫命令),但是性能較差,而everysec模式只不過會可能丟失1秒鐘的數據,而no模式的效率和everysec相仿,但是會丟失上次同步AOF文件之後的所有寫命令數據。
  • Redis的集群搭建,原來這麼簡單
    現在已經3月份了,正所謂金三銀四嘛,小夥伴們難道就沒有一些想法麼?昨天和一個朋友聊天,他給我說他剛拿到一個央企的offer,薪資差不多是平薪過去的,但是每個月有績效、補助,年終獎最低3個月起步。雖然整體來說薪資漲幅不大,但已經基本上達到大廠薪資的90%,還是可以的呀,重點人家是錢多活少還離家近,你說這氣人不氣人。他拿到這樣的offer證明肚子裡還是有點東西的哈。
  • 從零開始學習大數據系列(六十五) Redis入門及基礎實踐
    [redis等] 靈活的數據模型:NoSQL無需事先為要存儲的數據建立欄位,隨時可以存儲自定義的數據格式。而在關係資料庫裡,增刪欄位是一件非常麻煩的事情。如果是非常大數據量的表,增加欄位簡直就是一個噩夢。
  • redis基礎筆記
    這篇筆記記錄了redis的安裝、配置、操作數據類型等優勢和劣勢redis優勢 (remote dictionary server)Redis將其資料庫完全保存在內存中,僅將磁碟用於持久性每秒可以處理超過10萬次讀寫操作
  • 面試官:Redis有哪幾種集群方案?原理和優缺點是什麼?
    雖然現在各大雲平臺有提供緩存服務可以直接使用,但了解一下其背後的實現與原理總還是有些必要(比如面試), 本文就一起來學習一下Redis的幾種集群方案。主從複製模式主從複製模式中包含一個主資料庫實例(master)與一個或多個從資料庫實例(slave),如下圖
  • 46道Redis面試題,含參考答案!
    redis 主從複製如何實現的?redis 的集群模式如何實現?redis 的 key 是如何尋址的?主從複製實現:主節點將自己內存中的數據做一份快照,將快照發給從節點,從節點將數據恢復到內存中。之後再每次增加新數據的時候,主節點以類似於 mysql 的二進位日誌方式將語句發送給從節點,從節點拿到主節點發送過來的語句進行重放。
  • Redis作者攤上事兒了:多人要求修改Redis主從複製術語master/slave
    在未來的某個時刻,寫一個 INFO 的替代品,因為無論如何 INFO 不是 Redis 數據收集的未來. 它太有限,一次提供太多信息,客戶需要解析它。我們將設計一個新命令,在新命令中我們不會引用從屬,而是複製到副本。當我們打算破壞很多東西時,比如包含 RESPv3,也可以將 ROLE 命令更改為輸出副本而不是 slave。
  • 去pdd面試,redis把我面哭了【附面試答案】
    2、看你在項目中用了redis,我們先聊聊redis吧,常用的數據結構有哪幾種,在你的項目中用過哪幾種,以及在業務中使用的場景,redis的hash怎麼實現的,rehash過程講一下和JavaHashMap的rehash有什麼區別?redis cluster有沒有了解過,怎麼做到高可用的?3redis集群和哨兵機制有什麼區別?redis的持久化機制了解嗎?
  • Redis面試突擊專用
    Redis事務 Redis實現分布式鎖Redis 持久化機制Redis是一個支持持久化的內存資料庫,通過持久化機制把內存中的數據同步到硬碟文件來保證數據持久化。當Redis重啟後通過把硬碟文件重新加載到內存,就能達到恢復數據的目的。
  • Redis Sentinel-深入淺出原理和實戰
    ❞之前的文章聊到了Redis的主從複製,聊到了其相關的原理和缺點,具體的建議可以看看我之前寫的文章Redis的主從複製。總的來說,為了滿足Redis在真正複雜的生產環境的高可用,僅僅是用主從複製是明顯不夠的。