天天看點

“ID串行化”是如何保證消息順序性的?

在《消息順序性為何這麼難?》中,介紹了一種為了保證“所有群友展示的群消息時序都是一緻的”所使用的“ID串行化”的方法:讓同一個群gid的所有消息落在同一台伺服器上處理。

ID串行化是如何實作的呢?

網際網路高可用常見分層架構

“ID串行化”是如何保證消息順序性的?

用戶端,反向代理層,接入層,服務層,存儲層,這是網際網路常見的高可用分層架構。

這裡的“服務層”至關重要,ID串行化保證的是,同一個群gid的消息落在同一個服務上。

畫外音:服務叢集有很多節點,如果能落在同一個服務節點上,就可以利用這個服務節點做消息串行化。

服務層上下遊細節

服務一般由RPC架構實作,上遊調用方是多線程程式,通過RPC-client通路服務,而RPC-client内部又通過連接配接池connection-pool來通路的。

畫外音:為了保證高可用,連接配接池會對叢集中的每個服務都建立連接配接。

“ID串行化”是如何保證消息順序性的?

如上圖:

(1)上遊是業務應用;

(2)下遊是服務叢集;

(3)業務應用,它又分為了這麼幾個部分:

  • 上層是任務隊列(粉色);
  • 中間是工作線程(藍色),每個工作線程完成實際的業務任務,典型的工作任務是通過服務連接配接池進行RPC調用;
  • 下層是服務連接配接池(綠色),所有的RPC調用都是通過服務連接配接池往下遊服務發請求執行;

畫外音:橙色是連接配接池中的一條連接配接。

工作線程的典型工作流是這樣的:

void work_thread_routine(){

// 擷取任務

Task t = TaskQueue.pop(); 

// 任務邏輯處理,組成一個網絡包packet

Packet p = MakePacket(t);



// 從Service連接配接池擷取一個Service連接配接

ServiceConnection c = CPool.GetConnection();

// 通過Service連接配接發送封包執行RPC請求

c.Send(p); 

// 将Service連接配接放回Service連接配接池

CPool.PutConnection(c); 

}           

如何保證同一個群gid的消息落在同一個服務上呢?

對連接配接池進行少量改動,擷取連接配接時:

CPool.GetConnection()

畫外音:傳回任何一個可用服務連接配接。

更新為

CPool.GetConnection(long id)

畫外音:傳回id取模相關聯的服務連接配接。

隻要傳入群gid,就能夠保證同一個群的請求擷取到同一個連接配接,進而使請求落到同一個服務上。

需要注意的是,連接配接池不關心傳入的long id是什麼業務含義:

(1)傳入群gid,同gid的請求落在同一個服務上;

(2)傳入使用者uid,同uid的請求落在同一個服務上;

(3)傳入任何業務xid,同業務xid的請求落在同一個服務上;

ID串行化通路服務,同一個id通路同一個服務,當服務挂掉時,會不會受影響服務可用性?

不會,當有下遊服務挂掉的時候,連接配接池能夠檢測到連接配接的可用性,取模時要把不可用的服務連接配接排除掉。

取模通路服務,是否會影響各連接配接上請求的負載均衡?

不會,隻要資料通路id是均衡的,從全局來看,由id取模擷取各連接配接的機率也是均等的,即負載是均衡的。

擷取連接配接,ID取模,希望大家有收獲。

“ID串行化”是如何保證消息順序性的?

架構師之路-分享可落地的技術文章

繼續閱讀