<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Redis 主從握手流程

          共 6630字,需瀏覽 14分鐘

           ·

          2021-08-29 00:39

          在下方公眾號后臺回復:面試手冊,可獲取杰哥匯總的 3 份面試 PDF 手冊。

          Redis是開源的key-value存儲系統(tǒng),可作為數(shù)據(jù)庫、緩存、消息組件。

          Redis的作者是Salvatore Sanfilippo(網(wǎng)名為antirez),他在2009年開發(fā)完成并開源了Redis。

          Redis由于性能極高、功能強大,迅速在業(yè)界流行,現(xiàn)已成為高并發(fā)系統(tǒng)中最常用的組件之一。

          Redis提供了多種類型的數(shù)據(jù)結(jié)構(gòu),如字符串(String)、散列(Hash)、列表(List)、集合(Set)、有序集合(Sorted Set)等。

          Redis還是分布式系統(tǒng),主從集群可以實現(xiàn)數(shù)據(jù)熱備份,哨兵(Sentinel)機制可以保證主從集群高可用,Cluster集群則提供了水平擴展的能力。

          Redis還提供了持久化、Lua腳本、Module模塊、Stream消息流、Tracking機制等一系統(tǒng)強大功能,適用于各種業(yè)務(wù)場景。

          Redis是一個典型的“小而美”的程序。

          Redis實現(xiàn)簡單,源碼非常優(yōu)雅簡潔,閱讀起來并不吃力,而且Redis功能齊全,涵蓋了數(shù)據(jù)存儲、分布式、消息流等眾多特性,非常值得深入學習。

          Redis中的一個重要概念就是主從復制機制。

          下面詳細分析Redis主從復制機制中主從握手的過程。

          Redis主從復制機制中有兩個角色:主節(jié)點與從節(jié)點。

          主節(jié)點處理用戶請求,并將數(shù)據(jù)復制給從節(jié)點。

          主從復制機制主要有以下作用:

          • 數(shù)據(jù)冗余,將數(shù)據(jù)熱備份到從節(jié)點,即使主節(jié)點由于磁盤損壞丟失數(shù)據(jù),從節(jié)點依然保留數(shù)據(jù)副本。

          • 讀/寫分離,可以由主節(jié)點提供寫服務(wù),從節(jié)點提供讀服務(wù),提高Redis服務(wù)整體吞吐量。

          • 故障恢復,主節(jié)點故障下線后,可以手動將從節(jié)點切換為主節(jié)點,繼續(xù)提供服務(wù)。

          • 高可用基礎(chǔ),主從復制機制是Sentinel和Cluster機制的基礎(chǔ),Sentinel和Cluster都實現(xiàn)了故障轉(zhuǎn)移,即主節(jié)點故障停止后,Redis負責選擇一個從節(jié)點切換為主節(jié)點,繼續(xù)提供服務(wù)。

          下面將主從復制流程分為三個階段。

          • 握手階段:主從連接成功后,從節(jié)點需要將自身信息(如IP地址、端口等)發(fā)送給主節(jié)點,以便主節(jié)點能認識自己。

          • 同步階段:從節(jié)點連接主節(jié)點后,需要先同步數(shù)據(jù),數(shù)據(jù)達到一致(或者只有最新的變更不一致)后才進入復制階段。

          Redis支持兩種同步機制:

          全量同步:從節(jié)點發(fā)送命令PSYNC ? -1,要求進行全量同步,主節(jié)點返回響應(yīng)+FULLRESYNC,表明同意全量同步。隨后,主節(jié)點生成RDB數(shù)據(jù)并發(fā)送給從節(jié)點。這種方式常用于新的從節(jié)點首次同步數(shù)據(jù)。

          部分同步:從節(jié)點發(fā)送命令PSYNC replid offset,要求進行部分同步,主節(jié)點響應(yīng)+CONTINUE,表明同意部分同步。主節(jié)點只需要把復制積壓區(qū)中offset偏移量之后的命令發(fā)送給從節(jié)點即可(主節(jié)點會將執(zhí)行的寫命令都寫入復制積壓區(qū))。這種方式常用于主從連接斷開重連時同步數(shù)據(jù)。如果offset不在復制積壓區(qū)中,那么主節(jié)點也會返回+FULLRESYNC,要求進行全量同步。

          • 復制階段:主節(jié)點在運行期間,將執(zhí)行的寫命令傳播給從節(jié)點,從節(jié)點接收并執(zhí)行這些命令,從而達到復制數(shù)據(jù)的效果。Redis使用的是異步復制,主節(jié)點傳播命令后,并不會等待從節(jié)點返回ACK確認。異步復制的優(yōu)點是低延遲和高性能,缺點是可能在短期內(nèi)主從節(jié)點數(shù)據(jù)不一致。

          本文中指的命令,包含命令名及執(zhí)行命令的參數(shù)。

          PSYNC命令涉及以下屬性:

          • server.master_repl_offset:記錄當前服務(wù)器已執(zhí)行命令的偏移量。

          • server.replid:40位十六進制的隨機字符串,在主節(jié)點中是自身ID,在從節(jié)點中記錄的是主節(jié)點ID。

          • server.replid2:用于主節(jié)點,存放上一個主節(jié)點ID。

          • server.repl_backlog:復制積壓區(qū),主節(jié)點將最近執(zhí)行的寫命令寫入復制積壓區(qū),用于實現(xiàn)部分同步。

          下面介紹一下Redis主從握手流程。

          主從復制的機制是由從節(jié)點發(fā)起流程,我們可以發(fā)送REPLICAOF命令到某個服務(wù)器,要求它成為指定服務(wù)器的從節(jié)點:

          REPLICAOF <masterip> <masterport>

          或者在配置文件中添加配置REPLICAOF,這樣Redis服務(wù)器啟動后將成為指定服務(wù)器的從節(jié)點。

          提示:從Redis 5開始為SLAVEOF命令提供別名REPLICAOF,這兩個命令的作用一樣。

          下面以從節(jié)點的視角,分析主從握手的過程。

          從節(jié)點握手階段涉及以下屬性。

          server.repl_state:用于從節(jié)點,標志從節(jié)點當前復制狀態(tài)。有如下值:

          • REPL_STATE_NONE:無主從復制關(guān)系。

          • REPL_STATE_CONNECT:待連接。

          • REPL_STATE_CONNECTING:正在連接。

          • …(部分握手狀態(tài)并沒有列出)

          • REPL_STATE_TRANSFER:從節(jié)點正在接收RDB數(shù)據(jù)。

          • REPL_STATE_CONNECTED:已連接,主從同步完成。

          從節(jié)點使用replicaofCommand函數(shù)處理REPLICAOF命令。

          該函數(shù)執(zhí)行如下邏輯:

          (1)如果處理的命令是REPLICAOF NO ONE,則將當前服務(wù)器轉(zhuǎn)換為主節(jié)點,取消原來的主從復制關(guān)系,退出函數(shù)。

          (2)調(diào)用replicationSetMaster函數(shù),與給定服務(wù)器建立主從復制關(guān)系。

          另外,我們在配置文件中配置REPLICAOF,Redis加載該配置,也會將server.repl_state設(shè)置為REPL_STATE_CONNECT狀態(tài)(config.c)。

          從節(jié)點server.repl_state進入REPL_STATE_CONNECT狀態(tài)后,主從復制流程已經(jīng)開始。

          serverCron時間事件負責對REPL_STATE_CONNECT狀態(tài)進行處理:

          int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData{
              ...
              if (server.repl_state == REPL_STATE_CONNECT) {
                  if (connectWithMaster() == C_OK) {
                      serverLog(LL_NOTICE,"MASTER <-> REPLICA sync started");
                  }
              }
          }

          調(diào)用connectWithMaster函數(shù)進行處理,該函數(shù)負責建立主從網(wǎng)絡(luò)連接:

          int connectWithMaster(void) {
              // [1]
              server.repl_transfer_s = server.tls_replication ? connCreateTLS() : connCreateSocket();
              // [2]
              if (connConnect(server.repl_transfer_s, server.masterhost, server.masterport,
                          NET_FIRST_BIND_ADDR, syncWithMaster) == C_ERR) {
                  ...
                  return C_ERR;
              }


              // [3]
              server.repl_transfer_lastio = server.unixtime;
              server.repl_state = REPL_STATE_CONNECTING;
              return C_OK;
          }

          【1】創(chuàng)建一個Socket套接字。connCreateTLS函數(shù)創(chuàng)建TLS連接,connCreateSocket函數(shù)創(chuàng)建TCP連接,它們都返回套接字文件描述符。該連接是主從節(jié)點網(wǎng)絡(luò)通信的連接,本書稱之為主從連接。

          【2】connConnect函數(shù)負責連接到主節(jié)點,并且在連接成功后調(diào)用syncWithMaster函數(shù)。

          【3】從節(jié)點server.repl_state進入REPL_STATE_CONNECTING狀態(tài)。

          網(wǎng)絡(luò)連接成功后,從節(jié)點調(diào)用syncWithMaster函數(shù),進入握手階段:

          void syncWithMaster(connection *conn) {
              char tmpfile[256], *err = NULL;
              int dfd = -1, maxtries = 5;
              int psync_result;
              ...
              // [1]
              if (server.repl_state == REPL_STATE_CONNECTING) {
                  connSetReadHandler(conn, syncWithMaster);
                  connSetWriteHandler(conn, NULL);
                  server.repl_state = REPL_STATE_RECEIVE_PONG;
                  err = sendSynchronousCommand(SYNC_CMD_WRITE,conn,"PING",NULL);
                  if (err) goto write_error;
                  return;
              }
              ...
              // [2]
              if (server.repl_state != REPL_STATE_RECEIVE_PSYNC) {
                  goto error;
              }


              // more
          }

          【1】根據(jù)server.repl_state狀態(tài),執(zhí)行對應(yīng)操作。

          從節(jié)點發(fā)送給主節(jié)點的信息,主節(jié)點會記錄在從節(jié)點客戶端,并在INFO命令中輸出這些信息。另外,Sentinel模塊需要從主節(jié)點INFO命令響應(yīng)中獲取這些從節(jié)點信息。

          【2】執(zhí)行到這里,主從握手階段已經(jīng)完成。server.repl_state必須處于REPL_STATE_ RECEIVE_PSYNC狀態(tài),否則報錯。

          下面使用Linux tcpdump工具抓取主從連接報文,分析主從節(jié)點握手階段的通信內(nèi)容(主節(jié)點端口為6000):

          tcpdump tcp  -i lo  -nn   port  6000 -T RESP

          tcpdump支持RESP協(xié)議,最后一個選項-T RESP要求tcpdump以RESP協(xié)議格式解析報文。

          其中6000端口為主節(jié)點端口,60374端口為從節(jié)點通信端口。從tcpdump的輸出可以清晰地看到主從節(jié)點在握手階段的通信內(nèi)容。

          提示:tcpdump解析后的RESP內(nèi)容并不會展示數(shù)據(jù)類型的標志符,如主節(jié)點對從節(jié)點PING命令的響應(yīng)實際上是“-NOAUTH Authentication required.”,請讀者閱讀源碼時注意。

          以主節(jié)點視角分析握手階段,主節(jié)點不斷處理來自從節(jié)點的命令(包括PING、AUTH、REPLCONF),感興趣的讀者可自行閱讀代碼。

          Redis主從握手流程到此就分析完畢了。

          本書深入地分析了Redis核心功能的內(nèi)部機制與實現(xiàn)方式,大部分內(nèi)容源自對Redis源碼的分析,并從中總結(jié)出實現(xiàn)原理。通過閱讀本書,讀者可以快速、輕松地了解Redis的內(nèi)部運行機制。

          贈書規(guī)則:為本文「點贊」+ 「在看」 +「留言」且與文章內(nèi)容相關(guān)的優(yōu)質(zhì)留言即可上墻并從所有留言中選出3位點贊最高的讀者留言將各獲得一本。

          截止時間:2021年8月31日,晚 20:00

          領(lǐng)書須知:提供點贊、在看的截圖

          注意事項:最終獲贈者請在24小時以內(nèi)添加我的微信,備注:贈書??

          推薦閱讀

          一口氣說出 Redis 16 個常見使用場景

          Redis 主從復制、哨兵模式、集群

          這 40 道 Redis 面試題讓你不再慌(附答案)

          萬字總結(jié),Redis 性能問題排查解決手冊!

          面試官最愛的 21 道 Redis 高頻面試題集合

          大廠面試!我和面試官之間關(guān)于Redis的一場對弈!

          Redis是什么?看這一篇就夠了!

          學 Redis,至少要看看這篇!7000 字小結(jié)

          2020 年最新版 68 道Redis面試題,20000 字干貨,趕緊收藏起來備用!

          瀏覽 184
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  自拍偷拍视频区 | 99无码视频。 | 三级片在线观看视频网址 | 日韩精品一区二区三区四虎影视 | 国语对白视频 |