群訊息這麼複雜,怎麼能做到不丟不重

2021-08-11 09:46:44 字數 3449 閱讀 1710

(2)離線的群友能在登陸後收到訊息

由於「訊息風暴擴散係數」的存在,群訊息的複雜度要遠高於單對單訊息。群訊息的實時性,可達性,離線訊息是今天將要討論的核心話題。

【常見的群訊息流程】

開始講群訊息投遞流程之前,先介紹兩個群業務的核心資料結構:

群成員表:用來描述乙個群裡有多少成員

t_group_users(group_id, user_id)

群離線訊息表:用來描述乙個群成員的離線訊息

t_offine_msgs(user_id, group_id, sender_id,time, msg_id, msg_detail)

業務場景舉例:

(1)乙個群中有x,a,b,c,d共5個成員,成員x發了乙個訊息

(3)成員c與d離線,期望未來拉取到離線訊息

系統架構簡介:

(1)客戶端:x,a,b,c,d共5個客戶端使用者

(2)服務端

(2.1)所有模組與服務抽象為server

(2.3)所有資料資訊,例如群成員、群離線訊息抽象儲存在db裡

典型群訊息投遞流程,如圖步驟1-4所述:

步驟1:群訊息傳送者x向server發出群訊息

步驟2:server去db中查詢群中有多少使用者(x,a,b,c,d)

步驟5:對於群中離線的使用者c與d,群訊息server進行離線儲存

典型的群離線訊息拉取流程,如圖步驟1-3所述:

步驟1:離線訊息拉取者c向server拉取群離線訊息

步驟2:server從db中拉取離線訊息並返回群使用者c

步驟3:server從db中刪除群使用者c的群離線訊息

存在的問題

上述流程是最容易想,也最容易理解的,存在的問題也最顯而易見:對於同乙份群訊息的內容,多個離線使用者儲存了很多份。假設群中有200個使用者離線,離線訊息則冗餘了200份,這極大的增加了資料庫的儲存壓力。

【群訊息優化1:減少儲存量】

為了減少離線訊息的冗餘度,增加乙個群訊息表,用來儲存所有群訊息的內容,離線訊息表只儲存使用者的群離線訊息msg_id,就能大大的降低資料庫的冗餘儲存量

群訊息表:用來儲存乙個群中所有的訊息內容

t_group_msgs(group_id, sender_id, time,msg_id, msg_detail)

群離線訊息表:優化後只儲存msg_id

t_offine_msgs(user_id, group_id, msg_id)

步驟6:每次儲存離線訊息時,只儲存msg_id,而不用為每個使用者儲存msg_detail

拉取離線訊息時也做了響應的修改:

步驟1:先拉取所有的離線訊息msg_id

步驟3:再根據msg_id拉取msg_detail

步驟5:刪除離線msg_id

存在的問題

如同單對單訊息的傳送一樣:

(2)離線訊息的拉取也可能出現訊息丟失,原因同上

需要和單對單訊息的可靠投遞一樣,加入應用層的ack,才能保證群訊息一定到達。

【群訊息優化2:應用層ack】

對應到群離線訊息的拉取也一樣:

步驟1:先拉取msg_id

步驟3:再拉取msg_detail

步驟5:最後應用層ack

步驟6:server收到應用層ack才能刪除離線訊息表裡的msg_id

存在的問題

(1)如果拉取了訊息,卻沒來得及應用層ack,會收到重複的訊息麼?

回答:會,可以在客戶端去重,對於重複的msg_id,對使用者不展現,從而不影響使用者體驗

(2)對於離線的每一條訊息,雖然只儲存了msg_id,但是每個使用者的每一條離線訊息都將在資料庫中儲存一條記錄,有沒有辦法減少離線訊息的記錄數呢?

【群訊息優化3:離線訊息表】

離線訊息表的優化

其實,對於乙個群使用者,在ta登出後的離線期間內,肯定是所有的群訊息都沒有收到的,完全不用對所有的每一條離線訊息儲存乙個離線msg_id,而只需要儲存最近一條拉取到的離線訊息的time(或者msg_id),下次登入時拉取在那之後的所有群訊息即可,而完全沒有必要儲存每個人未拉取到的離線訊息msg_id

群成員表:用來描述乙個群裡有多少成員,以及每個成員最後一條ack的群訊息的msg_id(或者time)

t_group_users(group_id, user_id, last_ack_msg_id(last_ack_msg_time))

群訊息表:用來儲存乙個群中所有的訊息內容,不變

t_group_msgs(group_id, sender_id, time,msg_id, msg_detail)

群離線訊息表:不再需要了

步驟3:在訊息msg_detail儲存到群訊息表後,不再需要操作離線訊息表(優化前需要將msg_id插入離線訊息表)

群離線訊息的拉取流程也類似:

步驟1:拉取離線訊息

步驟3:ack離線訊息

步驟4:更新last_ack_msg_id

存在的問題

由於「訊息風暴擴散係數」的存在,假設1個群有500個使用者,「每條」群訊息都會變為500個應用層ack,將對伺服器造成巨大的衝擊,有沒有辦法減少ack請求量呢?

【群訊息優化4:批量ack】

由於「訊息風暴擴散係數」的存在,如果每條群訊息都ack,會給伺服器造成巨大的衝擊,為了減少ack請求量,很容易想到的方法是批量ack。

批量ack的方式又有兩種:

(1)每收到n條群訊息ack一次,這樣請求量就降低為原來的1/n了

(2)每隔時間間隔t進行一次群訊息ack,也能達到類似的效果

新的問題

批量ack有可能導致:還沒有來得及ack群訊息,使用者就退出了,這樣下次登入會拉取到重複的離線訊息

解決方案

msg_id去重,不對使用者展現,保證良好的使用者體驗

還可能存在的問題

群離線訊息過多:拉取過慢

【總結】

群訊息還是非常有意思的,可達性、實時性、離線訊息、訊息風暴擴散等等等等,做個總結:

(2)群訊息只存乙份,不用為每個使用者儲存脫機群msg_id,只需儲存乙個最近ack的群訊息id/time

(3)為了減少訊息風暴,可以批量ack

(4)如果收到重複訊息,需要msg_id去重,讓使用者無感知

(5)離線訊息過多,可以分頁拉取(按需拉取)優化

超時待解決 PTA 群群群訊息

煩人奧,用樹做的仍然超時,暫時做個記錄。如果看到這篇的朋友有思路麻煩大力踢我!謝謝!思想就是建樹,遞迴,挖到底,返回。眾所周知,yooq是圖論之神,lc是數論之神。yooq正在看xx群裡的訊息。由於群裡面的訊息太多了,而且參差不齊,讓yooq看的很難受。不過,yooq在群裡有乙個特殊許可權,每一次操...

冷群怎麼運營成活群

的相同屬性越強烈,目標也就越精準,社群所產生的裂變價值也就越大。乙個社群必須具備三個要素 1 使用者群體必須有相同屬性 2 使用者群體必須有相同目標 3 社群必須有自群體運營制度 做社群的目的就是一群人通過相互協作達成某種目標,實現某種價值。做社群要注意的也是這一點,很多人做社群是為了達成自己某種目...

生活,原來就是這麼累,這麼複雜

從什麼時候開始,我對上海這個地方沒有了一絲的眷戀,自以為生活了 六 七年的地方,就算沒有深厚的感情,也應該多少有一些眷戀吧。至少人家是國際大都市,是眾人蜂擁而至的地方,每年大批大批人的湧入,節節攀公升的房價足以顯示這裡的人氣。可是,我現在卻發現這裡是如此的陌生,至少我沒有永遠在這裡帶下去的信心.我怎...