天天看點

“id串行化”到底是怎麼實作的?

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

有朋友就要問了,如何保證一個群gid的消息落到同一個伺服器處理呢,“id串行化”具體是怎麼實作的呢,這個問題在年初的一篇文章中描述過,這裡再給有疑問的同學解答一下。

“id串行化”到底是怎麼實作的?

用戶端,反向代理層,接入層(此圖是http短連結接入,群聊消息的話是tcp長連接配接接入),服務層(處理群消息業務邏輯),存儲層(緩存cache存儲,固化db存儲),這是網際網路常見的高可用分層架構。

服務層的引入至關重要,群消息的投遞不能保證落在同一個接入層,但可以保證落在同一個服務層。

服務化的service一般由rpc-server架構實作,上遊應用是多線程程式(站點層http接入應用,或者長連接配接tcp接入應用)一般通過rpc-client通路service,而rpc-client内部又通過連接配接池connection-pool通路下遊的service(為了保證高可用,是一個service叢集)。

“id串行化”到底是怎麼實作的?

如上圖:

(1)上遊是業務應用(站點層http接入應用,或者長連接配接tcp接入應用)

(2)下遊是service叢集

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

(3.1)最上層是任務隊列【或許web-server例如tomcat幫你幹了這個事情了】

(3.2)中間是工作線程【或許web-server的工作線程或者cgi工作線程幫你幹了線程分派這個事情了】,每個工作線程完成實際的業務任務,典型的工作任務是通過服務連接配接池進行rpc調用

(3.3)最下層是服務連接配接池,所有的rpc調用都是通過服務連接配接池往下遊服務去發包執行的

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

隻要對服務連接配接池進行少量改動:

擷取service連接配接的cpool.getserviceconnection()【傳回任何一個可用service連接配接】改為

cpool.getserviceconnection(long id)【傳回id取模相關聯的service連接配接】

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

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

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

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

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

提問:id串行化通路service,同一個id通路同一個service,當service挂掉時,是否會影響service的可用性?

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

提問:取模通路service,是否會影響各連接配接上請求的負載均衡?

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

更新rpc-client内部的連接配接池,在service連接配接選取上做微小改動,就能夠實作“id串行化”,實作不同類型的業務gid/uid等的串行化、序列号需求(這下查找日志就友善了,一個群gid/使用者uid的日志隻需去一台機器grep啦)。

==【完】==

回【http】http如何像tcp一樣實時的收消息?

回【可靠】微信為什麼不丢消息?

回【狀态】qq狀态同步究竟是推還是拉?

回【群】群消息這麼複雜,怎麼能做到不丢不重?

回【qq】微信多點登入與qq消息漫遊架構

回【離線】微信為啥不丢“離線消息”?

【小遊戲:回大于10的數,随機返好文,猜猜怎麼實作的】

“id串行化”到底是怎麼實作的?