《Redis設計與實現》讀書筆記(三十一) ——Redis叢集訊息型別
《Redis設計與實現》讀書筆記(三十一) ——Redis叢集訊息型別
(原創內容,轉載請註明來源,謝謝)
1、傳送訊息型別
叢集中節點通過傳送與接收訊息進行通訊。
傳送訊息的節點稱為訊息傳送者,接收訊息節點稱為接收者。訊息傳送型別如下:
1)meet
當客戶端傳送clustermeet給節點,節點會發送meet訊息給接收者,請求接收者加入到傳送者當前的叢集中。
2)ping
每個節點每秒,預設會隨機從當前已知節點列表,挑選5個節點,並從中挑選最久未傳送過ping訊息的節點,對其傳送ping,檢測其是否線上。
另外,如果某個節點最後一次回覆pong的時間,距離當前時間,已經超過redis配置檔案中cluster-node-timeout設定的秒數的一半,則也會對該節點發送ping,防止多次沒有隨機到該節點,導致對該節點的狀態更新過慢。
3)pong
當節點收到meet或者ping,為了告知傳送者收到訊息,會回覆pong。
另外,完成一次故障轉移後,新的主節點會給向叢集廣播pong。
4)fail
當節點認為某個節點下線,會向叢集廣播關於該節點的fail狀態,其他節點接收到後,都會將該節點狀態置為下線。
5)publish
當節點收到publish命令,會執行該命令,並向叢集傳送publish,其他節點收到後也會執行該命令。
2、訊息頭
所有訊息都由訊息頭包裹,訊息頭可以認為是訊息的一部分。訊息頭由cluster.h/clusterMsg結構記錄,如下:
structclusterMsg{ uint32_t totlen;//訊息總長度,包括訊息頭長度和正文長度 uint16_t type;//訊息型別 uint16_t count;//訊息正文包含節點資訊數量,只有在meet、ping、pong這三種涉及到gossip協議的型別使用 uint64_t currentEpoch;//傳送者的配置紀元 uint64_t configEpoch;//該節點是主節點時,是傳送者的配置紀元;是從節點時,是對應正在複製的主節點的配置紀元 char sender[REDIS_CLUSTER_NAMELEN];//傳送者名字(ID) unsigned char myslots[REDIS_CLUSTER_SLOTS/8];//傳送者目前的槽資訊 char slaveof[REDIS_CLUSTER_NAMELEN];//主節點時記錄的是40位長的都是0的字串,從節點時記錄的是複製的主節點的名字 uint16_t port;//傳送者埠號 uint16_t flag;//傳送者標識值 unsigned char state;//傳送者所處的叢集狀態 union clusterMsgData data;//訊息的正文 }clusterMsg;
訊息的正文是一個聯合體,共有三種類型結構體,包括ping、fail、publish,其中pong、meet型別都和ping一樣。
3、meet、ping、pong
這三個的型別一樣,都是記錄在聯合體clusterMsgData中的結構體。因為這三種訊息有相同的正文,節點是通過訊息頭的type判斷是這三種的哪一種。
這三種訊息的型別是clusterMsgDataPublish,這是一個結構體,記錄節點名字、最後給該節點發送ping的時間戳、最後收到節點pong的時間戳、節點ip、埠號、標識等。
當節點接收到資訊時,如果不認識裡面的節點,則會與節點進行握手,如果認識則更新對應的資訊。
4、fail
由於使用gossip協議會有延遲,fail是用來表示該節點下線,需要儘快傳達,因此不用gossip協議,而是立即讓叢集中的全部節點知情。其正文就是下線節點的名字。
5、publish
客戶端向叢集傳送publish<channel> <message>,接收的頻道不僅會向頻道channel傳送message,還會向叢集廣播publish,其他節點也會執行該命令。
因此,向某個節點發送publish,會導致所有節點都執行該命令。
具體流程如下:
![](https://img.796t.com/res/2022/05-03/08/be0d185cae4912c78015c5b21947b611.jpeg)
publish用結構體clusterMsgDataPublish記錄,內容是包括頻道長度,訊息長度,以及具體內容。
其中,bulk_data的前channel_len位元組,記錄channel引數;剩餘位元組記錄message引數。
例如,傳送publish“news.it” “hello” 如下:
![](https://img.796t.com/res/2022/05-03/08/a238a850fcbc8cf025b7e159f035f8a1.jpeg)
其實也可以直接向叢集廣播publish命令,但是由於其不符合redis設計的各節點通過訊息傳送和接收來傳播訊息的做法,因此採用對某一節點進行訊息傳送。
——written by linhxx 2017.09.18