前面的集群成員維護服務為我們提供了集群內所有成員的地址端口等信息,可以通過MembershipService可以輕易從節點本地的成員列表獲取集群所有的成員信息,有了這些成員信息后就可以使用可靠的TCP/IP協議進行通信了。這節討論的正是實際中真正用于消息傳送通道的相關機制及實現細節。
如下圖,四個節點本地都擁有了一張集群成員的信息列表,這時節點1有這么一個需求:為了保證數據的安全可靠,在往自己的內存存放一份數據的同時還要同步到其他三個節點的內存中。節點1有一個專門負責發送的組件ChannelSender,首先從成員列表中獲取其他三個節點的通信地址和端口,再分別向此三個節點建立TCP/IP通道發送數據,其他節點有一個負責接收數據的服務,將數據更新到內存中。
?
最理想的狀態是發送給節點2、3、4都成功了,這樣從整體看來ChannelSender像是提供了一個多通道的平行發送方式,所以也稱為平行發送器。但現實中并不能保證同一批的消息往所有節點發送都成功,有可能發送到節點3時因為某種原因失敗了,而節點2、4都成功了,這時通常要采取一些策略來應對,例如重新發送。Tribes所使用的策略是優先進行若干次嘗試發送,若干次失敗后將向上拋出異常信息,異常信息包含哪些節點發送失敗及其原因,默認的嘗試次數是1次。
為確保數據確實被節點接收到,需要在應用層引入一個協議保證傳輸的可靠性,即是通知機制,發送者發送消息給接收者,接受者接收到后返回一個ACK表示自己已經接收成功。Tribes中詳細的協議報文定義如下:START_DATA(7bytes)+消息長度(4bytes)+消息長度(nbytes)+END_DATA(7bytes)。START_DATA為數據開始標識,為固定數組值70,76,84,50,48,48,50,END_DATA為數據結束標識,為固定數組值84,76,70,50,48,48,51,ACK_DATA表示通知報文,為固定數組值6,2,3。所以如果傳輸的是通知報文的話即為START_DATA+ACK_DATA的長度+ACK_DATA+END_DATA。所以整個集群的消息同步如下圖,節點1通過ChannelSender發送消息給節點2、3、4,發送成功的判定標準就是節點2、3、4返回給節點1一個ack標識,節點1接收到了則認為發送成功。
?
為提高通信效率這里默認使用了NIO模式而非BIO模式(也可設置為BIO模式),使用NIO模式能統一管理所有通信的channel,避免了等待一個通道發送完畢另一個通道才能發送,如果逐個通信將導致阻塞IO時間很長通信效率低下。另外平行發送的過程需要一個鎖保證消息的正確發送,例如有data1、data2、data3三個數據需要發送,應該是一個接一個數據包發送的而不能data1發一部分data2發一部分。
這節介紹了Tribes如何向集群其他成員發送數據,通過本地獲取其他成員節點的地址和端口,再通過平行消息發送通道發送給其他節點,其中有ack機制和重發機制保證數據成功接收。
喜歡java的同學可以交個朋友:
