【原創】 Redis Cluster 的實現 - cluster 訊息的接收和分包

來源:互聯網
上載者:User

標籤:redis cluster

因為針對 READ 事件的 clusterReadHandler 處理器主要工作就是解析 cluster bus 上接收的資料並進行訊息分包,然後對訊息進行處理,而對於訊息的分包首先需要瞭解一下訊息結構,Redis Cluster 節點之間通訊的訊息結構定義如下:
 

typedef struct {    char sig[4];        /* Siganture "RCmb" (Redis Cluster message bus). */    uint32_t totlen;    /* Total length of this message */    uint16_t ver;       /* Protocol version, currently set to 0. */    uint16_t notused0;  /* 2 bytes not used. */        /* Message type,如:PING, PONG,定義參考宏定義 CLUSTERMSG_TYPE_* */    uint16_t type;        uint16_t count;     /* Only used for some kind of messages. */    uint64_t currentEpoch;  /* The epoch accordingly to the sending node. */    uint64_t configEpoch;   /* The config epoch if it‘s a master, or the last                               epoch advertised by its master if it is a                               slave. */    uint64_t offset;    /* Master replication offset if node is a master or                           processed replication offset if node is a slave. */                               // 節點發送方,為 NodeID 表示,如: 123ed65d59ff22370f2f09546f410d31207789f6    char sender[REDIS_CLUSTER_NAMELEN]; /* Name of the sender node */        // 本節點維護的 slots bits    unsigned char myslots[REDIS_CLUSTER_SLOTS/8];        // 如果本節點為 slave 節點,則 slaveof 記錄對應的 master 節點ID    char slaveof[REDIS_CLUSTER_NAMELEN];        char notused1[32];  /* 32 bytes reserved for future usage. */    uint16_t port;      /* Sender TCP base port */    uint16_t flags;     /* Sender node flags */        // cluster 狀態, 如:REDIS_CLUSTER_OK, REDIS_CLUSTER_FAIL ...    unsigned char state; /* Cluster state from the POV of the sender */    unsigned char mflags[3]; /* Message flags: CLUSTERMSG_FLAG[012]_... */        // 指向不同 訊息類型 的訊息體    // 參考 clusterMsgData 結構的說明    union clusterMsgData data;} clusterMsg;

 

從上面結構可以看到訊息分包,主要解析前 8 個位元組,分別為:
 
  - char sig[4];      // 訊息簽名,對於 cluster 訊息,固定為字元序列 RCmb
  - uint32_t totlen;  // 訊息總長度
 
其他結構成員都是在處理訊息時使用的,後續講解訊息處理流程時進行分析。

 

/* Read data. Try to read the first field of the header first to check the * full length of the packet. When a whole packet is in memory this function * will call the function to process the packet. And so forth. */void clusterReadHandler(aeEventLoop *el, int fd, void *privdata, int mask) {    char buf[sizeof(clusterMsg)];    ssize_t nread;    clusterMsg *hdr;    clusterLink *link = (clusterLink*) privdata;    int readlen, rcvbuflen;    REDIS_NOTUSED(el);    REDIS_NOTUSED(mask);    while(1) { /* Read as long as there is data to read. */        rcvbuflen = sdslen(link->rcvbuf);        if (rcvbuflen < 8) {            /* First, obtain the first 8 bytes to get the full message             * length. */            readlen = 8 - rcvbuflen;        } else {            // 已經知道了本條訊息的長度            // 本塊代碼主要計算剩餘還需讀入的位元組數(readlen)才是完整的訊息            /* Finally read the full message. */            hdr = (clusterMsg*) link->rcvbuf;            if (rcvbuflen == 8) {                /* Perform some sanity check on the message signature                 * and length. */                if (memcmp(hdr->sig,"RCmb",4) != 0 ||                    ntohl(hdr->totlen) < CLUSTERMSG_MIN_LEN)                {                    redisLog(REDIS_WARNING,                        "Bad message length or signature received "                        "from Cluster bus.");                    handleLinkIOError(link);                    return;                }            }            readlen = ntohl(hdr->totlen) - rcvbuflen;            if (readlen > sizeof(buf)) readlen = sizeof(buf);        }                // 讀入本條訊息記錄的剩餘 readlen 個位元組的資料        // 因為這裡的 fd 是非阻塞的,所以需要判斷 EAGAIN        nread = read(fd,buf,readlen);        if (nread == -1 && errno == EAGAIN) return; /* No more data ready. */        if (nread <= 0) {            /* I/O error... */            redisLog(REDIS_DEBUG,"I/O error reading from node link: %s",                (nread == 0) ? "connection closed" : strerror(errno));            handleLinkIOError(link);            return;        } else {            /* Read data and recast the pointer to the new buffer. */            link->rcvbuf = sdscatlen(link->rcvbuf,buf,nread);            hdr = (clusterMsg*) link->rcvbuf;            rcvbuflen += nread;        }        /* Total length obtained? Process this packet. */        if (rcvbuflen >= 8 && rcvbuflen == ntohl(hdr->totlen)) {            // 表明 link 上的 rcvbuf 已經是一個完整的 cluster 訊息            // 下面開始處理此訊息            if (clusterProcessPacket(link)) {                sdsfree(link->rcvbuf);                link->rcvbuf = sdsempty();            } else {                return; /* Link no longer valid. */            }        }    }}


本文出自 “安靜的瘋子” 部落格,請務必保留此出處http://quietmadman.blog.51cto.com/3269500/1558889

【原創】 Redis Cluster 的實現 - cluster 訊息的接收和分包

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.