自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

群聊比單聊,為什么復(fù)雜這么多?

開(kāi)發(fā) 開(kāi)發(fā)工具
群聊是多人社交的基本訴求,一個(gè)群友在群內(nèi)發(fā)了一條消息,期望做到在線的群友能第一時(shí)間收到消息,群消息的實(shí)時(shí)性、可達(dá)性、離線消息的復(fù)雜度,要遠(yuǎn)高于單對(duì)單消息。

群聊是多人社交的基本訴求,一個(gè)群友在群內(nèi)發(fā)了一條消息,期望做到:

  • 在線的群友能***時(shí)間收到消息;
  • 離線的群友能在登陸后收到消息;

群消息的實(shí)時(shí)性、可達(dá)性、離線消息的復(fù)雜度,要遠(yuǎn)高于單對(duì)單消息。

常見(jiàn)的群消息流程如何?

群業(yè)務(wù)的核心數(shù)據(jù)結(jié)構(gòu)有兩個(gè)。

群成員表:

  1. t_group_users(group_id, user_id) 

畫(huà)外音:用來(lái)描述一個(gè)群里有多少成員。

群離線消息表:

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

畫(huà)外音:用來(lái)描述一個(gè)群成員的離線消息。

業(yè)務(wù)場(chǎng)景舉例:

  • 假設(shè)一個(gè)群中有x,A,B,C,D共5個(gè)成員,成員x發(fā)了一個(gè)消息;
  • 成員A與B在線,期望實(shí)時(shí)收到消息;
  • 成員C與D離線,期望未來(lái)拉取到離線消息;

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

  • 步驟1:群消息發(fā)送者x向server發(fā)出群消息;
  • 步驟2:server去db中查詢?nèi)褐杏卸嗌儆脩?x,A,B,C,D);
  • 步驟3:server去cache中查詢這些用戶的在線狀態(tài);
  • 步驟4:對(duì)于群中在線的用戶A與B,群消息server進(jìn)行實(shí)時(shí)推送;
  • 步驟5:對(duì)于群中離線的用戶C與D,群消息server進(jìn)行離線存儲(chǔ);

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

  • 步驟1:離線消息拉取者C向server拉取群離線消息;
  • 步驟2:server從db中拉取離線消息并返回群用戶C;
  • 步驟3:server從db中刪除群用戶C的群離線消息;

那么,問(wèn)題來(lái)了!對(duì)于同一份群消息的內(nèi)容,多個(gè)離線用戶似乎要存儲(chǔ)很多份。假設(shè)群中有200個(gè)用戶離線,離線消息則冗余了200份,這極大的增加了數(shù)據(jù)庫(kù)的存儲(chǔ)壓力。

如何優(yōu)化,減少消息冗余量?

為了減少離線消息的冗余度,增加一個(gè)群消息表,用來(lái)存儲(chǔ)所有群消息的內(nèi)容,離線消息表只存儲(chǔ)用戶的群離線消息msg_id,就能大大的降低數(shù)據(jù)庫(kù)的冗余存儲(chǔ)量。

群消息表:

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

畫(huà)外音:用來(lái)存儲(chǔ)一個(gè)群中所有的消息內(nèi)容。

群離線消息表,需要進(jìn)行優(yōu)化:

  1. t_offine_msgs(user_id, group_id, msg_id) 

畫(huà)外音:優(yōu)化后只存儲(chǔ)msg_id。

這樣優(yōu)化后,群在線消息發(fā)送就做了一些修改:

  • 步驟3:每次發(fā)送在線群消息之前,要先存儲(chǔ)群消息的內(nèi)容;
  • 步驟6:每次存儲(chǔ)離線消息時(shí),只存儲(chǔ)msg_id,而不用為每個(gè)用戶存儲(chǔ)msg_detail;

拉取離線消息時(shí)也做了響應(yīng)的修改:

  • 步驟1:先拉取所有的離線消息msg_id;
  • 步驟3:再根據(jù)msg_id拉取msg_detail;
  • 步驟5:刪除離線msg_id;

優(yōu)化后的流程,能保證消息的可達(dá)性么?例如:

  • 在線消息的投遞可能出現(xiàn)消息丟失,例如服務(wù)器重啟,路由器丟包,客戶端crash;
  • 離線消息的拉取也可能出現(xiàn)消息丟失,原因同上;

畫(huà)外音:?jiǎn)螌?duì)單消息的可靠投遞一樣,是通過(guò)加入應(yīng)用層的ACK實(shí)現(xiàn)的,群消息呢?

群消息,如何通過(guò)應(yīng)用層ACK,保證消息的可靠投遞?

應(yīng)用層ACK優(yōu)化后,群在線消息發(fā)送又發(fā)生了一些變化:

  • 步驟3:在消息msg_detail存儲(chǔ)到群消息表后,不管用戶是否在線,都先將msg_id存儲(chǔ)到離線消息表里;
  • 步驟6:在線的用戶A和B收到群消息后,需要增加一個(gè)應(yīng)用層ACK,來(lái)標(biāo)識(shí)消息到達(dá);
  • 步驟7:在線的用戶A和B在應(yīng)用層ACK后,將他們的離線消息msg_id刪除掉;

對(duì)應(yīng)到群離線消息的拉取也一樣:

  • 步驟1:先拉取msg_id;
  • 步驟3:再拉取msg_detail;
  • 步驟5:***應(yīng)用層ACK;
  • 步驟6:server收到應(yīng)用層ACK才能刪除離線消息表里的msg_id;

如果拉取了消息,卻沒(méi)來(lái)得及應(yīng)用層ACK,會(huì)收到重復(fù)的消息么?

似乎會(huì),但可以在客戶端去重,對(duì)于重復(fù)的msg_id,對(duì)用戶不展現(xiàn),從而不影響用戶體驗(yàn)。

對(duì)于離線的每一條消息,雖然只存儲(chǔ)了msg_id,但是每個(gè)用戶的每一條離線消息都將在數(shù)據(jù)庫(kù)中保存一條記錄,有沒(méi)有辦法減少離線消息的記錄數(shù)呢?

對(duì)于一個(gè)群用戶,在ta登出后的離線期間內(nèi),肯定是所有的群消息都沒(méi)有收到的,完全不用對(duì)所有的每一條離線消息存儲(chǔ)一個(gè)離線msg_id,而只需要存儲(chǔ)最近一條拉取到的離線消息的time(或者msg_id),下次登錄時(shí)拉取在那之后的所有群消息即可,而完全沒(méi)有必要存儲(chǔ)每個(gè)人未拉取到的離線消息msg_id。

群成員表,增加一個(gè)屬性:

  1. t_group_users(group_id, user_id, last_ack_msg_id) 

畫(huà)外音:用來(lái)描述一個(gè)群里有多少成員,以及每個(gè)成員***一條ack的群消息的msg_id(或者time)。

群消息表,不變:

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

畫(huà)外音:還是用來(lái)存儲(chǔ)一個(gè)群中所有的消息內(nèi)容。

群離線消息表:不再需要。

離線消息表優(yōu)化后,群在線消息的投遞流程:

  • 步驟3:在消息msg_detail存儲(chǔ)到群消息表后,不再需要操作離線消息表(優(yōu)化前需要將msg_id插入離線消息表);
  • 步驟7:在線的用戶A和B在應(yīng)用層ACK后,將last_ack_msg_id更新即可(優(yōu)化前需要將msg_id從離線消息表刪除);

群離線消息的拉取流程也類(lèi)似:

  • 步驟1:拉取離線消息;
  • 步驟3:ACK離線消息;
  • 步驟4:更新last_ack_msg_id;

加入ACK機(jī)制,保證群消息的可靠投遞只會(huì),假設(shè)1個(gè)群有500個(gè)用戶,“每條”群消息都會(huì)變?yōu)?00個(gè)應(yīng)用層ACK,似乎會(huì)對(duì)服務(wù)器造成巨大的沖擊。有沒(méi)有辦法減少ACK請(qǐng)求量呢?

批量ACK,是一種常見(jiàn)的,降低請(qǐng)求量的方式。

如果每條群消息都ACK,確實(shí)會(huì)給服務(wù)器造成巨大的沖擊,為了減少ACK請(qǐng)求量,可以批量ACK,批量ACK的方式又有兩種方式:

  • 每收到N條群消息ACK一次,這樣請(qǐng)求量就降低為原來(lái)的1/N了;
  • 每隔時(shí)間間隔T進(jìn)行一次群消息ACK,也能達(dá)到類(lèi)似的效果;

批量ACK有可能導(dǎo)致新的問(wèn)題:如果還沒(méi)有來(lái)得及ACK群消息,用戶就退出了,這樣下次登錄似乎會(huì)拉取到重復(fù)的離線消息,怎么辦?

客戶端按照msg_id去重,不對(duì)用戶展現(xiàn),就保證良好的用戶體驗(yàn)。

群離線消息過(guò)多,拉取過(guò)慢,怎么辦?

分頁(yè)拉取(按需拉取),細(xì)節(jié)就不再展開(kāi)了,都是常見(jiàn)的優(yōu)化方案。

總結(jié)

群消息還是非常有意思的,做個(gè)簡(jiǎn)單總結(jié):

  • 不管是群在線消息,還是群離線消息,應(yīng)用層的ACK是可達(dá)性的保障;
  • 群消息只存一份,不用為每個(gè)用戶存儲(chǔ)離線群msg_id,只需存儲(chǔ)一個(gè)最近ack的群消息id/time;
  • 為了減少消息風(fēng)暴,可以批量ACK;
  • 如果收到重復(fù)消息,需要msg_id去重,讓用戶無(wú)感知;
  • 離線消息過(guò)多,可以分頁(yè)拉取(按需拉取)優(yōu)化;

【本文為51CTO專欄作者“58沈劍”原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)聯(lián)系原作者】

戳這里,看該作者更多好文

責(zé)任編輯:趙寧寧 來(lái)源: 51CTO專欄
相關(guān)推薦

2022-11-09 10:32:50

群業(yè)務(wù)群聊數(shù)據(jù)結(jié)構(gòu)

2017-12-21 19:38:50

潤(rùn)乾中間表

2022-07-26 23:43:29

編程語(yǔ)言開(kāi)發(fā)Java

2013-01-15 09:41:45

編程語(yǔ)言

2016-12-01 13:40:37

2018-12-21 09:36:31

OLAP蘇寧Druid

2022-08-04 23:32:38

比特幣以太坊代幣

2015-06-25 13:31:19

2022-01-12 20:04:09

網(wǎng)絡(luò)故障斷網(wǎng)事件網(wǎng)絡(luò)安全

2024-06-14 09:21:32

2021-05-31 22:26:20

5G技術(shù)通信

2024-02-04 10:29:58

線程通信

2015-01-14 14:27:18

Docker容器鏡像

2021-08-19 06:53:18

開(kāi)發(fā)語(yǔ)言Java

2024-03-01 17:01:15

GraphQL后端

2020-04-27 09:45:16

網(wǎng)絡(luò)工程師網(wǎng)絡(luò)技術(shù)網(wǎng)絡(luò)

2020-07-02 14:12:52

C++語(yǔ)言編程

2017-08-11 14:21:33

軟件開(kāi)發(fā)前端框架

2024-04-02 08:41:10

ArrayListSubList場(chǎng)景

2023-07-17 08:21:52

漏洞版本項(xiàng)目
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)