Redis學習二:Redis高併發之主從模式

申明

本文章首發自本人公衆號:壹枝花算不算浪漫,如若轉載請標明來源!java

感興趣的小夥伴可關注我的公衆號:壹枝花算不算浪漫node

22.jpg

前言

前面已經學習了Redis的持久化方式,接下來開始學習Redis主從架構的原理,來看看Redis如何利用主從架構來保證高併發的。redis

Redis如何支持高併發

單機的redis通常QPS不會超過超過10萬+,通常單機QPS都在幾萬左右,若是須要支撐高併發,咱們能夠將Redis作成主從架構來支持讀寫分離。數據庫

主從架構 -> 讀寫分離 -> 支撐10萬+讀QPS緩存

主從架構的核心原理

當啓動一個slave node的時候,它會發送一個PSYNC命令給master node網絡

若是這是salve node重複你給你鏈接master node,那麼master node僅僅會複製給slave部分缺失的數據;不然若是是slave node第一次鏈接master node,那麼會觸發一次full resynchronization架構

開始full resynchronization的時候,master會啓動一個後臺線程,開始生成一份RDB快照文件,同時還會將從客戶端收到的全部寫命令緩存在內存中。併發

RDB文件生成完畢以後,master將這個RDB發送給slave,salve會先寫入本地磁盤,而後再從本地磁盤加載到內存中。less

接着master會將內存中緩存的寫命令發送給slave,slave也會同步這些數據。異步

主從複製斷點續傳

slave node若是跟master node有網絡故障,斷開了鏈接,會自動重連。

從redis 2.8以後,就支持主從複製的斷點續傳,若是主從複製過程當中,網絡鏈接斷掉了,那麼能夠接着上次複製的地方,繼續複製下去,而不是從頭開始複製一份

master node會在內存中建立一個backlog,master和slave都會保存一個replica offset還有一個master id,offset就是保存在backlog中的。若是master和slave網絡鏈接斷掉了,slave會讓master從上次的replica offseet開始繼續複製

可是若是沒有找到對應的offset,那麼就會執行一次full resynchronization

無磁盤化複製

master在內存中直接建立rdb,而後發送給slave,不會在本身的本地落地磁盤了

// 默認不使用diskless同步方式,能夠改爲yes
repl-diskless-sync yes
// 無磁盤diskless方式在進行數據傳遞以前會有一個時間的延遲,以便slave端可以進行到待傳送的目標隊列中,這個時間默認是5秒
repl-diskless-sync-delay 5
複製代碼

過時key處理

slave不會過時key,只會等待master過時key。若是master過時了一個key,或者經過LRU淘汰了一個key,那麼會模擬一條del命令發送個slave。

以上的執行流程如圖:

image.jpg

複製的完整流程

  1. slave node在redis.conf中的slaveof配置master的host信息,slave node啓動,僅僅是保存了master node信息,此時複製流程並未開始
  2. slave node內部有個定時任務,每秒檢查是否有新的master node須要鏈接和複製,若是發現,就跟master node創建socket網絡鏈接
  3. slave node發送ping的命令給master node
  4. 口令認證,若是master設置了requiresspass,那麼slave node必須發送masterauth的口令過去認證
  5. master node第一次執行全量複製,將全部數據發送給slave node
  6. master node後續持續將寫命令,異步複製給slave node

具體流程以下:(如下內容參考自: blog.csdn.net/houjixin/ar…)

全量複製

全備份過程當中,在slave啓動時,會向其master發送一條SYNC消息,master收到slave的這條消息以後,將可能啓動後臺進程進行備份,備份完成以後就將備份的數據發送給slave,初始時的全同步機制是這樣的:

  1. slave啓動後向master發送同步指令SYNC,master接收到SYNC指令以後將調用該命令的處理函數syncCommand()進行同步處理;
  2. 在函數syncCommand中,將調用函數rdbSaveBackground啓動一個備份進程用於數據同步,若是已經有一個備份進程在運行了,就不會再從新啓動了。
  3. 備份進程將執行函數rdbSave()完成將redis的所有數據保存爲rdb文件。
  4. 在redis的時間事件函數serverCron(redis的時間處理函數是指它會定時被redis進行操做的函數)中,將對備份後的數據進行處理,在serverCron函數中將會檢查備份進程是否已經執行完畢,若是備份進程已經完成備份,則調用函數backgroundSaveDoneHandler完成後續處理。
  5. 在函數backgroundSaveDoneHandler中,首先更新master的各類狀態,例如,備份成功仍是失敗,備份的時間等等。而後調用函數updateSlavesWaitingBgsave,將備份的rdb數據發送給等待的slave。
  6. 在函數updateSlavesWaitingBgsave中,將遍歷全部的等待這次備份的slave,將備份的rdb文件發送給每個slave。另外,這裏並非當即就把數據發送過去,而是將爲每一個等待的slave註冊寫事件,並註冊寫事件的響應函數sendBulkToSlave,即當slave對應的socket可以發送數據時就調用函數sendBulkToSlave(),實際發送rdb文件的操做都在函數sendBulkToSlave中完成。
  7. sendBulkToSlave函數將把備份的rdb文件發送給slave。

上述函數調用過程以下圖1所示:

image.png

數據修改操做的同步

Redis的正常部署中通常都是一個master用於寫操做,若干個slave用於讀操做,另外按期的數據備份操做也是單獨選址一個slave完成,這樣能夠最大程度發揮出redis的性能。在部署完成,各master\slave程序啓動以後,首先進行第一階段初始化時的全同步操做,全同步操做完成以後,後續全部寫操做都是在master上進行,全部讀操做都是在slave上進行,所以用戶的寫操做須要及時擴散到全部的slave以便保持數據最大程度上的同步。Redis的master-slave進程在正常運行期間更新操做(包括寫、刪除、更改操做)的同步方式以下:

  1. master接收到一條用戶的操做後,將調用函數call函數來執行具體的操做函數(此過程可參考另外一文檔《redis命令執行流程分析》),在該函數中首先經過proc執行操做函數,而後將判斷操做是否須要擴散到各slave,若是須要則調用函數propagate()來完成此操做。

  2. propagate()函數完成將一個操做記錄到aof文件中或者擴散到其餘slave中;在該函數中經過調用feedAppendOnlyFile()將操做記錄到aof中,經過調用replicationFeedSlaves()將操做擴散到各slave中。

  3. 函數feedAppendOnlyFile()中主要保存操做到aof文件,在該函數中首先將操做轉換成redis內部的協議格式,並以字符串的形式存儲,而後將字符串存儲的操做追加到aof文件後。

  4. 函數replicationFeedSlaves()主要將操做擴散到每個slave中;在該函數中將遍歷本身下面掛的每個slave,以此對每一個slave進行以下兩步的處理:將slave的數據庫切換到本操做所對應的數據庫(若是slave的數據庫id與當前操做的數據id不一致時才進行此操做);將命令和參數按照redis的協議格式寫入到slave的回覆緩存中。寫入切換數據庫的命令時將調用addReply,寫入命令和參數時將調用addReplyMultiBulkLen和addReplyBulk,函數addReplyMultiBulkLen和addReplyBulk最終也將調用函數addReply。

  5. 在函數addReply中將調用prepareClientToWrite()設置slave的socket寫入事件處理函數sendReplyToClient(經過函數aeCreateFileEvent進行設置),這樣一旦slave對應的socket發送緩存中有空間寫入數據,即調用sendReplyToClient進行處理。

  6. 函數sendReplyToClient()的主要功能是將slave中要發送的數據經過socket發出去。

image.png

數據同步相關核心機制

第一次slave鏈接master的時候,執行的是全量複製,這個過程當中有些細節的機制

  1. master和slave都會維護一個offset

    master會在自身不斷累加offset,slave也會在自身不斷累加offset。slave每秒都會上報本身的offset給master,同時master也會保存每一個slave的offset。

    offset並非只用在全量複製中,主要是master和slave都要知道各自的數據offset,才能知道互相之間數據不一致的狀況

  2. backlog機制

    master node有一個backlog,默認大小是1M,master node給slave node複製數據時,也會將數據backlog中同步寫一份,backlog主要是用來作全量複製中斷時候的增量複製

  3. master run id

    在redis中執行info server命令,能夠看到master run id,若是根據host+ip定位master node,是不許確的,若是master node重啓或者數據出現了變化,那麼slave node應該根據不一樣的run id區分,run id不一樣就作全量複製。 若是須要不更改run id重啓redis,可使用redis-cli debug reload命令

  4. psync命令

    從節點使用psync從master node進行復制,psync runid offset,master node會根據自身的狀況返回響應信息,多是FULLRESYNC runid offset觸發全量複製,多是CONTINUE觸發增量複製

  5. heatbeat機制

    主從節點互相都會發送heartbeat信息,master默認每隔10秒發送一次heartbeat,slave node每隔1秒發送一個heartbeat

相關文章
相關標籤/搜索