本文作者潘唐磊,騰訊WXG(微信事業(yè)群)開發(fā)工程師,畢業(yè)于中山大學(xué)。內(nèi)容有修訂。
1、內(nèi)容概述
本文總結(jié)了企業(yè)微信的IM消息系統(tǒng)架構(gòu)設(shè)計(jì),闡述了企業(yè)業(yè)務(wù)給IM架構(gòu)設(shè)計(jì)帶來的技術(shù)難點(diǎn)和挑戰(zhàn),以及技術(shù)方案的對(duì)比與分析。同時(shí)總結(jié)了IM后臺(tái)開發(fā)的一些常用手段,適用于IM消息系統(tǒng)。
* 推薦閱讀:企業(yè)微信團(tuán)隊(duì)分享的另一篇《企業(yè)微信客戶端中組織架構(gòu)數(shù)據(jù)的同步更新方案優(yōu)化實(shí)戰(zhàn)》也值得一讀。
學(xué)習(xí)交流:
(本文同步發(fā)布于:http://www.52im.net/thread-3631-1-1.html)
2、名詞解釋
以下是本文內(nèi)容中涉及到的技術(shù)名詞縮寫,具體意義如下:
- 1)seq:自增長(zhǎng)的序列號(hào),每條消息對(duì)應(yīng)一個(gè)(見:《微信的海量IM聊天消息序列號(hào)生成實(shí)踐》);
- 2)ImUnion:消息互通系統(tǒng),用于企業(yè)微信與微信的消息打通;
- 3)控制消息:即控制指令,屬不可見消息,是復(fù)用消息通道的一種可靠通知機(jī)制;
- 4)應(yīng)用消息:系統(tǒng)應(yīng)用下發(fā)的消息;
- 5)api 消息:第三方應(yīng)用下發(fā)的消息;
- 6)appinfo:每條消息對(duì)應(yīng)的唯一strid,全局唯一。同一條消息的appinfo在所有的接收方中是相同的。
3、技術(shù)背景
企業(yè)微信作為一款辦公協(xié)同的產(chǎn)品,聊天消息收發(fā)是最基礎(chǔ)的功能。消息系統(tǒng)的穩(wěn)定性、可靠性、安全性尤其重要。
消息系統(tǒng)的構(gòu)建與設(shè)計(jì)的過程中,面臨著較多的難點(diǎn)。而且針對(duì)toB場(chǎng)景的消息系統(tǒng),需要支持更為復(fù)雜的業(yè)務(wù)場(chǎng)景。
針對(duì)toB場(chǎng)景的特有業(yè)務(wù)有:
- 1)消息鑒權(quán):關(guān)系類型有群關(guān)系、同企業(yè)同事關(guān)系、好友關(guān)系、集團(tuán)企業(yè)關(guān)系、圈子企業(yè)關(guān)系。收發(fā)消息雙方需存在至少一種關(guān)系才允許發(fā)消息;
- 2)回執(zhí)消息:每條消息都需記錄已讀和未讀人員列表,涉及頻繁的狀態(tài)讀寫操作;
- 3)撤回消息:支持24小時(shí)的有效期撤回動(dòng)作;
- 4)消息存儲(chǔ):云端存儲(chǔ)時(shí)間跨度長(zhǎng),最長(zhǎng)可支持180天消息存儲(chǔ),數(shù)百TB用戶消息需優(yōu)化,減少機(jī)器成本;
- 5)萬人群聊:群人數(shù)上限可支持10000人,一條群消息就像一次小型的DDoS攻擊;
- 6)微信互通:兩個(gè)異構(gòu)的im系統(tǒng)直接打通,可靠性和一致性尤其重要。
4、整體架構(gòu)設(shè)計(jì)1:架構(gòu)分層
如上所示,整體架構(gòu)分層如下。
1)接入層:統(tǒng)一入口,接收客戶端的請(qǐng)求,根據(jù)類型轉(zhuǎn)發(fā)到對(duì)應(yīng)的CGI層。客戶端可以通過長(zhǎng)連或者短連連接wwproxy。活躍的客戶端,優(yōu)先用長(zhǎng)連接發(fā)起請(qǐng)求,如果長(zhǎng)連失敗,則選用短連重試。
2)CGI層:http服務(wù),接收wwproxy的數(shù)據(jù)包,校驗(yàn)用戶的session狀態(tài),并用后臺(tái)派發(fā)的秘鑰去解包,如解密失敗則拒絕請(qǐng)求。解密成功,則把明文包體轉(zhuǎn)發(fā)到后端邏輯層對(duì)應(yīng)的svr。
3)邏輯層:大量的微服務(wù)和異步處理服務(wù),使用自研的hikit rpc框架,svr之間使用tcp短連進(jìn)行通信。進(jìn)行數(shù)據(jù)整合和邏輯處理。和外部系統(tǒng)的通信,通過http協(xié)議,包括微信互通、手機(jī)廠商的推送平臺(tái)等。
4)存儲(chǔ)層:消息存儲(chǔ)是采用的是基于levelDB模型開發(fā)msgkv。SeqSvr是序列號(hào)生成器,保證派發(fā)的seq單調(diào)遞增不回退,用于消息的收發(fā)協(xié)議。
5、整體架構(gòu)設(shè)計(jì)2:消息收發(fā)模型
企業(yè)微信的消息收發(fā)模型采用了推拉方式,這種方式可靠性高,設(shè)計(jì)簡(jiǎn)單。
以下是消息推拉的時(shí)序圖:
PS:如上圖所示,發(fā)送方請(qǐng)求后臺(tái),把消息寫入到接收方的存儲(chǔ),然后push通知接收方。接受方收到push,主動(dòng)上來后臺(tái)收消息。
不重、不丟、及時(shí)觸達(dá),這三個(gè)是消息系統(tǒng)的核心指標(biāo):
- 1)實(shí)時(shí)觸達(dá):客戶端通過與后臺(tái)建立長(zhǎng)連接,保證消息push的實(shí)時(shí)觸達(dá);
- 2)及時(shí)通知:如果客戶端長(zhǎng)連接不在,進(jìn)程被kill了,利用手機(jī)廠商的推送平臺(tái),推送通知,或者直接拉起進(jìn)程進(jìn)行收消息;
- 3)消息可達(dá):假如遇到消息洪峰,后臺(tái)的push滯后,客戶端有輪訓(xùn)機(jī)制進(jìn)行兜底,保證消息可達(dá);
- 4)消息防丟:為了防止消息丟失,只要后臺(tái)邏輯層接收到請(qǐng)求,保證消息寫到接收方的存儲(chǔ),失敗則重試。如果請(qǐng)求在CGI層就失敗,則返回給客戶端出消息紅點(diǎn);
- 5)消息排重:客戶端在弱網(wǎng)絡(luò)的場(chǎng)景下,有可能請(qǐng)求已經(jīng)成功寫入存儲(chǔ),回包超時(shí),導(dǎo)致客戶端重試發(fā)起相同的消息,那么就造成消息重復(fù)。為了避免這種情況發(fā)生,每條消息都會(huì)生成唯一的appinfo,后臺(tái)通過建立索引進(jìn)行排重,相同的消息直接返回成功,保證存儲(chǔ)只有一條。
6、整體架構(gòu)設(shè)計(jì)3:消息擴(kuò)散寫
IM中消息分發(fā)的典型方式,一般有兩種:
6.1 擴(kuò)散讀
即:每條消息只存一份,群聊成員都讀取同一份數(shù)據(jù)。
優(yōu)點(diǎn):節(jié)省存儲(chǔ)容量。
缺點(diǎn):
- ① 每個(gè)用戶需存儲(chǔ)會(huì)話列表,通過會(huì)話id去拉取會(huì)話消息;
- ② 收消息的協(xié)議復(fù)雜,每個(gè)會(huì)話都需要增量同步消息,則每個(gè)會(huì)話都需要維護(hù)一個(gè)序列號(hào)。
6.2 擴(kuò)散寫
即:每條消息存多份,每個(gè)群聊成員在自己的存儲(chǔ)都有一份。
優(yōu)點(diǎn):
- ① 只需要通過一個(gè)序列號(hào)就可以增量同步所有消息,收消息協(xié)議簡(jiǎn)單;
- ② 讀取速度快,前端體驗(yàn)好;
- ③ 滿足更多ToB的業(yè)務(wù)場(chǎng)景:回執(zhí)消息、云端刪除。
同一條消息,在每個(gè)人的視角會(huì)有不同的表現(xiàn)。例如:回執(zhí)消息,發(fā)送方能看到已讀未讀列表,接受方只能看到是否已讀的狀態(tài)。云端刪除某條群消息,在自己的消息列表消失,其他人還是可見。
缺點(diǎn):存儲(chǔ)容量的增加。
企業(yè)微信采用了擴(kuò)散寫的方式,消息收發(fā)簡(jiǎn)單穩(wěn)定。存儲(chǔ)容量的增加,可以通過冷熱分離的方案解決,冷數(shù)據(jù)存到廉價(jià)的SATA盤,擴(kuò)散讀體驗(yàn)稍差,協(xié)議設(shè)計(jì)也相對(duì)復(fù)雜些。
下圖是擴(kuò)散寫的協(xié)議設(shè)計(jì):
如上圖所示:
- 1)每個(gè)用戶只有一條獨(dú)立的消息流。同一條消息多副本存在于每個(gè)用戶的消息流中;
- 2)每條消息有一個(gè)seq,在同個(gè)用戶的消息流中,seq是單調(diào)遞增的;
- 3)客戶端保存消息列表中最大seq,說明客戶端已經(jīng)擁有比該seq小的所有消息。若客戶端被push有新消息到達(dá),則用該seq向后臺(tái)請(qǐng)求增量數(shù)據(jù),后臺(tái)把比此seq大的消息數(shù)據(jù)返回。
7、系統(tǒng)穩(wěn)定性設(shè)計(jì)1:柔性策略
7.1 背景
企業(yè)微信作為一款to B場(chǎng)景的聊天im工具,用于工作場(chǎng)景的溝通,有著較為明顯的高峰效應(yīng)(如下圖所示)。
正如上圖所示:工作時(shí)間上午9:00~12:00、下午14:00~18:00,是聊天的高峰,消息量劇增。工作日和節(jié)假日也會(huì)形成明顯的對(duì)比。
高峰期系統(tǒng)壓力大,偶發(fā)的網(wǎng)絡(luò)波動(dòng)或者機(jī)器過載,都有可能導(dǎo)致大量的系統(tǒng)失敗。im系統(tǒng)對(duì)及時(shí)性要求比較高,沒辦法進(jìn)行削峰處理。那么引入一些柔性的策略,保證系統(tǒng)的穩(wěn)定性和可用性非常有必要。
具體的做法就是啟動(dòng)過載保護(hù)策略:當(dāng)svr已經(jīng)達(dá)到最大處理能力的時(shí)候,說明處于一個(gè)過載的狀態(tài),服務(wù)能力會(huì)隨著負(fù)載的增高而急劇下降。如果svr過載,則拒絕掉部分正常請(qǐng)求,防止機(jī)器被壓垮,依然能對(duì)外服務(wù)。通過統(tǒng)計(jì)svr的被調(diào)耗時(shí)情況、worker使用情況等,判定是否處于過載狀態(tài)。過載保護(hù)策略在請(qǐng)求高峰期間起到了保護(hù)系統(tǒng)的作用,防止雪崩效應(yīng)。
下圖就是因過載被拒絕掉的請(qǐng)求:
7.2 問題
上一小結(jié)中過載保護(hù)策略所帶來的問題就是:系統(tǒng)過載返回失敗,前端發(fā)消息顯示失敗,顯示紅點(diǎn),會(huì)嚴(yán)重影響產(chǎn)品體驗(yàn)。
發(fā)消息是im系統(tǒng)的最基礎(chǔ)的功能,可用性要求達(dá)到幾乎100%,所以這個(gè)策略肯定需要優(yōu)化。
7.3 解決方案
解決方案思路就是:盡管失敗,也返回前端成功,后臺(tái)保證最終成功。
為了保證消息系統(tǒng)的可用性,規(guī)避高峰期系統(tǒng)出現(xiàn)過載失敗導(dǎo)致前端出紅點(diǎn),做了很多優(yōu)化。
具體策略如下:
- 1)邏輯層hold住失敗請(qǐng)求,返回前端成功,不出紅點(diǎn),后端異步重試,直至成功;
- 2)為了防止在系統(tǒng)出現(xiàn)大面積故障的時(shí)候,重試請(qǐng)求壓滿隊(duì)列,只hold住半小時(shí)的失敗請(qǐng)求,半小時(shí)后新來的請(qǐng)求則直接返回前端失敗;
- 3)為了避免重試加劇系統(tǒng)過載,指數(shù)時(shí)間延遲重試;
- 4)復(fù)雜的消息鑒權(quán)(好友關(guān)系,企業(yè)關(guān)系,集團(tuán)關(guān)系,圈子關(guān)系),耗時(shí)嚴(yán)重,后臺(tái)波動(dòng)容易造成失敗。如果并非明確鑒權(quán)不通過,則冪等重試;
- 5)為了防止作惡請(qǐng)求,限制單個(gè)用戶和單個(gè)企業(yè)的請(qǐng)求并發(fā)數(shù)。例如,單個(gè)用戶的消耗worker數(shù)超過20%,則直接丟棄該用戶的請(qǐng)求,不重試。
優(yōu)化后,后臺(tái)的波動(dòng),前端基本沒有感知。
以下是優(yōu)化前后的流程對(duì)比:
8、系統(tǒng)穩(wěn)定性設(shè)計(jì)2:系統(tǒng)解耦
由于產(chǎn)品形態(tài)的原因,企業(yè)微信的消息系統(tǒng),會(huì)依賴很多外部模塊,甚至外部系統(tǒng)。
例如:與微信消息互通,發(fā)送消息的權(quán)限需要放到ImUnion去做判定,ImUnion是一個(gè)外部系統(tǒng),調(diào)用耗時(shí)較長(zhǎng)。
再如:金融版的消息審計(jì)功能,需要把消息同步到審計(jì)模塊,增加rpc調(diào)用。
再如:客戶服務(wù)的單聊群聊消息,需要把消息同步到crm模塊,增加rpc調(diào)用。為了避免外部系統(tǒng)或者外部模塊出現(xiàn)故障,拖累消息系統(tǒng),導(dǎo)致耗時(shí)增加,則需要系統(tǒng)解耦。
我們的方案:與外部系統(tǒng)的交互,全設(shè)計(jì)成異步化。
思考點(diǎn):需要同步返回結(jié)果的請(qǐng)求,如何設(shè)計(jì)成異步化?
例如:群聊互通消息需經(jīng)過ImUnion鑒權(quán)返回結(jié)果,前端用于展示消息是否成功發(fā)送。先讓客戶端成功,異步失敗,則回調(diào)客戶端使得出紅點(diǎn)。
如果是非主流程,則異步重試保證成功,主流程不受影響,如消息審計(jì)同步功能。那么,只需要保證內(nèi)部系統(tǒng)的穩(wěn)定,發(fā)消息的主流程就可以不受影響。
解耦效果圖:
9、系統(tǒng)穩(wěn)定性設(shè)計(jì)3:業(yè)務(wù)隔離
企業(yè)微信的消息類型有多種:
- 1)單聊群聊:基礎(chǔ)聊天,優(yōu)先級(jí)高;
- 2)api 消息:企業(yè)通過api接口下發(fā)的消息,有頻率限制,優(yōu)先級(jí)中;
- 3)應(yīng)用消息:系統(tǒng)應(yīng)用下發(fā)的消息,例如公告,有頻率限制,優(yōu)先級(jí)中;
- 4)控制消息:不可見的消息。例如群信息變更,會(huì)下發(fā)控制消息通知群成員,優(yōu)先級(jí)低。
群聊按群人數(shù),又分成3類:
- 1)普通群:小于100人的群,優(yōu)先級(jí)高;
- 2)大 群:小于2000人的群,優(yōu)先級(jí)中;
- 3)萬人群:優(yōu)先級(jí)低。
業(yè)務(wù)繁多:如果不加以隔離,那么其中一個(gè)業(yè)務(wù)的波動(dòng)有可能引起整個(gè)消息系統(tǒng)的癱瘓。
重中之重:需要保證核心鏈路的穩(wěn)定,就是企業(yè)內(nèi)部的單聊和100人以下群聊,因?yàn)檫@個(gè)業(yè)務(wù)是最基礎(chǔ)的,也是最敏感的,稍有問題,投訴量巨大。
其余的業(yè)務(wù):互相隔離,減少牽連。按照優(yōu)先級(jí)和重要程度進(jìn)行隔離,對(duì)應(yīng)的并發(fā)度也做了調(diào)整,盡量保證核心鏈路的穩(wěn)定性。
解耦和隔離的效果圖:
10、to B業(yè)務(wù)功能的設(shè)計(jì)與優(yōu)化1:萬人群
10.1 技術(shù)背景
企業(yè)微信的群人數(shù)上限是10000,只要群內(nèi)每個(gè)人都發(fā)一條消息,那么擴(kuò)散量就是10000 * 10000 = 1億次調(diào)用,非常巨大。
10000人投遞完成需要的耗時(shí)長(zhǎng),影響了消息的及時(shí)性。
10.2 問題分析
既然超大群擴(kuò)散寫量大、耗時(shí)長(zhǎng),那么自然會(huì)想到:超大群是否可以單獨(dú)拎出來做成擴(kuò)散讀呢。
下面分析一下超大群設(shè)計(jì)成單副本面臨的難點(diǎn):
- ① 一個(gè)超大群,一條消息流,群成員都同步這條流的消息;
- ② 假如用戶擁有多個(gè)超大群,則需要同步多條流,客戶端需維護(hù)每條流的seq;
- ③ 客戶端卸載重裝,并不知道擁有哪些消息流,后臺(tái)需存儲(chǔ)并告知;
- ④ 某個(gè)超大群來了新消息,需通知所有群成員,假如push沒觸達(dá),客戶端沒辦法感知有新消息,不可能去輪訓(xùn)所有的消息流。
綜上所述:單副本的方案代價(jià)太大。
以下將介紹我們針對(duì)萬人群聊擴(kuò)散寫的方案,做的一些優(yōu)化實(shí)踐。
10.3 優(yōu)化1:并發(fā)限制
萬人群的擴(kuò)散量大,為了是消息盡可能及時(shí)到達(dá),使用了多協(xié)程去分發(fā)消息。但是并不是無限制地加大并發(fā)度。
為了避免某個(gè)萬人群的高頻發(fā)消息,造成對(duì)整個(gè)消息系統(tǒng)的壓力,消息分發(fā)以群id為維度,限制了單個(gè)群的分發(fā)并發(fā)度。消息分發(fā)給一個(gè)人的耗時(shí)是8ms,那么萬人的總體耗時(shí)是80s,并發(fā)上限是5,那么消息分發(fā)完成需要16s。16s的耗時(shí),在產(chǎn)品角度來看還、是可以接受的,大群對(duì)及時(shí)性不敏感。同時(shí),并發(fā)度控制在合理范圍內(nèi)。
除了限制單個(gè)群id的并發(fā)度,還限制了萬人群的總體并發(fā)度。單臺(tái)機(jī),小群的worker數(shù)為250個(gè),萬人群的worker數(shù)為30。
萬人群的頻繁發(fā)消息,worker數(shù)用滿,導(dǎo)致隊(duì)列出現(xiàn)積壓:
由于并發(fā)限制,調(diào)用數(shù)被壓平,沒有請(qǐng)求無限上漲,系統(tǒng)穩(wěn)定:
10.4 優(yōu)化2:合并插入
工作場(chǎng)景的聊天,多數(shù)是在小群完成,大群用于管理員發(fā)通知或者老板發(fā)紅包。
大群消息有一個(gè)常見的規(guī)律:平時(shí)消息少,會(huì)突然活躍。例如:老板在群里發(fā)個(gè)大紅包,群成員起哄,此時(shí)就會(huì)產(chǎn)生大量的消息。
消息量上漲、并發(fā)度被限制、任務(wù)處理不過來,那么隊(duì)列自然就會(huì)積壓。積壓的任務(wù)中可能存在多條消息需要分發(fā)給同一個(gè)群的群成員。
此時(shí):可以將這些消息,合并成一個(gè)請(qǐng)求,寫入到消息存儲(chǔ),消息系統(tǒng)的吞吐量就可以成倍增加。
在日常的監(jiān)控中,可以捕獲到這種場(chǎng)景,高峰可以同時(shí)插入20條消息,對(duì)整個(gè)系統(tǒng)很友善。
10.5 優(yōu)化3:業(yè)務(wù)降級(jí)
比如:群人員變更、群名稱變動(dòng)、群設(shè)置變更,都會(huì)在群內(nèi)擴(kuò)散一條不可見的控制消息。群成員收到此控制消息,則向后臺(tái)請(qǐng)求同步新數(shù)據(jù)。
舉個(gè)例子:一個(gè)萬人群,由于消息過于頻繁,對(duì)群成員造成騷擾,部分群成員選擇退群來拒絕消息,假設(shè)有1000人選擇退群。那么擴(kuò)散的控制消息量就是1000w,用戶收到控制消息就向后臺(tái)請(qǐng)求數(shù)據(jù),則額外帶來1000w次的數(shù)據(jù)請(qǐng)求,造成系統(tǒng)的巨大壓力。
控制消息在小群是很有必要的,能讓群成員實(shí)時(shí)感知群信息的變更。
但是在大群:群信息的變更其實(shí)不那么實(shí)時(shí),用戶也感覺不到。所以結(jié)合業(yè)務(wù)場(chǎng)景,實(shí)施降級(jí)服務(wù),控制消息在大群可以直接丟棄、不分發(fā),減少對(duì)系統(tǒng)的調(diào)用。
11、to B業(yè)務(wù)功能的設(shè)計(jì)與優(yōu)化2:回執(zhí)消息
11.1 技術(shù)背景
回執(zhí)消息是辦公場(chǎng)景經(jīng)常用到的一個(gè)功能,能看到消息接受方的閱讀狀態(tài)。
一條回執(zhí)消息的閱讀狀態(tài)會(huì)被頻繁修改,群消息被修改的次數(shù)和群成員人數(shù)成正比。每天上億條消息,讀寫頻繁,請(qǐng)求量巨大,怎么保證每條消息在接受雙方的狀態(tài)是一致的是一個(gè)難點(diǎn)。
11.2 實(shí)現(xiàn)方案
消息的閱讀狀態(tài)的存儲(chǔ)方式兩個(gè)方案。
方案一:
思路:利用消息存儲(chǔ),插入一條新消息指向舊消息,此新消息有最新的閱讀狀態(tài)。客戶端收到新消息,則用新消息的內(nèi)容替換舊消息的內(nèi)容展示,以達(dá)到展示閱讀狀態(tài)的效果。
優(yōu)點(diǎn):復(fù)用消息通道,增量同步消息就可以獲取到回執(zhí)狀態(tài),復(fù)用通知機(jī)制和收發(fā)協(xié)議,前后端改造小。
缺點(diǎn):
- ① 存儲(chǔ)冗余,狀態(tài)變更多次,則需插入多條消息;
- ② 收發(fā)雙方都需要修改閱讀狀態(tài)(接收方需標(biāo)志消息為已讀狀態(tài)),存在收發(fā)雙方數(shù)據(jù)一致性問題。
方案二:
思路:獨(dú)立存儲(chǔ)每條消息的閱讀狀態(tài),消息發(fā)送者通過消息id去拉取數(shù)據(jù)。
優(yōu)點(diǎn):狀態(tài)一致。
缺點(diǎn):
- ① 構(gòu)建可靠的通知機(jī)制,通知客戶端某條消息屬性發(fā)生變更;
- ② 同步協(xié)議復(fù)雜,客戶端需要準(zhǔn)確知道哪條消息的狀態(tài)已變更;
- ③ 消息過期刪除,閱讀狀態(tài)數(shù)據(jù)也要自動(dòng)過期刪除。
企業(yè)微信采用了方案一去實(shí)現(xiàn),簡(jiǎn)單可靠、改動(dòng)較小:存儲(chǔ)冗余的問題可以通過LevelDB落盤的時(shí)候merge數(shù)據(jù),只保留最終狀態(tài)那條消息即可;一致性問題下面會(huì)介紹如何解決。
上圖是協(xié)議流程(referid:被指向的消息id,senderid:消息發(fā)送方的msgid):
- 1)每條消息都有一個(gè)唯一的msgid,只在單個(gè)用戶內(nèi)唯一,kv存儲(chǔ)自動(dòng)生成的;
- 2)接收方b已讀消息,客戶端帶上msgid=b1請(qǐng)求到后臺(tái);
- 3)在接受方b新增一條消息,msgid=b2,referid=b1,指向msgid=b1的消息。并把msgid=b2的消息內(nèi)容設(shè)置為消息已讀。msgid=b1的消息體,存有發(fā)送方的msgid,即senderid=a1;
- 4)發(fā)送方a,讀出msgid=a1的消息體,把b加入到已讀列表,把新的已讀列表保存到消息體中,生成新消息msgid=a2,referid=a1,追加寫入到a的消息流;
- 5)接收方c已讀同一條消息,在c的消息流走同樣的邏輯;
- 6)發(fā)送方a,讀出msgid=a1的消息體,把c加入到已讀列表,把新的已讀列表保存到消息體中,生成新消息msgid=a3,referid=a1,追加寫入到a的消息流。a3>a2,以msgid大的a3為最終狀態(tài)。
11.3 優(yōu)化1:異步化
接受方已讀消息,讓客戶端同步感知成功,但是發(fā)送方的狀態(tài)沒必要同步修改。因?yàn)榘l(fā)送方的狀態(tài)修改情況,接受方?jīng)]有感知不到。那么,可以采用異步化的策略,降低同步調(diào)用耗時(shí)。
具體做法是:
- 1)接受方的數(shù)據(jù)同步寫入,讓客戶端馬上感知消息已讀成功;
- 2)發(fā)送方的數(shù)據(jù)異步寫入,減少同步請(qǐng)求;
- 3)異步寫入通過重試來保證成功,達(dá)到狀態(tài)最終一致的目的。
11.4 優(yōu)化2:合并處理
客戶端收到大量消息,并不是一條一條消息已讀確認(rèn),而是多條消息一起已讀確認(rèn)。為了提高回執(zhí)消息的處理效率,可以對(duì)多條消息合并處理。
如上圖所示:
- 1)X>>A:表示X發(fā)了一條消息給A;
- 2)A合并確認(rèn)3條消息,B合并確認(rèn)3條消息。那么只需要處理2次,就能標(biāo)志6條消息已讀;
- 3)經(jīng)過mq分發(fā),相同的發(fā)送方也可以合并處理。在發(fā)送方,X合并處理2條消息,Y合并處理2條消息,Z合并處理2條消息,則合并處理3次就能標(biāo)志6條消息。
經(jīng)過合并處理,處理效率大大提高。下圖是采集了線上高峰時(shí)期的調(diào)用數(shù)據(jù)。可以看得出來,優(yōu)化后的效果一共節(jié)省了44%的寫入量。
11.5 讀寫覆蓋解決
發(fā)送方的消息處理方式是先把數(shù)據(jù)讀起來,修改后重新覆蓋寫入存儲(chǔ)。接收方有多個(gè),那么就會(huì)并發(fā)寫發(fā)送方數(shù)據(jù),避免不了出現(xiàn)覆蓋寫的問題。
流程如下:
- 1)發(fā)送方某條消息的已讀狀態(tài)是X;
- 2)接收方a確認(rèn)已讀,已讀狀態(tài)修改為X+a;
- 3)接收方b確認(rèn)已讀,已讀狀態(tài)修改為X+b;
- 4)接收方a的狀態(tài)先寫入,接受方b的狀態(tài)后寫入。這最終狀態(tài)為X+b;
- 5)其實(shí)正確的狀態(tài)是X+a+b。
處理這類問題,無非就一下幾種辦法。
方案一:因?yàn)椴l(fā)操作是分布式,那么可以采用分布式鎖的方式保證一致。操作存儲(chǔ)之前,先申請(qǐng)分布式鎖。這種方案太重,不適合這種高頻多賬號(hào)的場(chǎng)景。
方案二:帶版本號(hào)讀寫。一個(gè)賬號(hào)的消息流只有一個(gè)版本鎖,高頻寫入的場(chǎng)景,很容易產(chǎn)生版本沖突,導(dǎo)致寫入效率低下。
方案三:mq串行化處理。能避免覆蓋寫問題,關(guān)鍵是在合并場(chǎng)景起到很好的作用。同一個(gè)賬號(hào)的請(qǐng)求串行化,就算出現(xiàn)隊(duì)列積壓,合并的策略也能提高處理效率。
企業(yè)微信采用了方案三,相同id的用戶請(qǐng)求串行化處理,簡(jiǎn)單易行,邏輯改動(dòng)較少。
12、to B業(yè)務(wù)功能的設(shè)計(jì)與優(yōu)化3:撤回消息
12.1 技術(shù)難點(diǎn)
“撤回消息”相當(dāng)于更新原消息的狀態(tài),是不是也可以通過referid的方式去指向呢?
回執(zhí)消息分析過:通過referid指向,必須要知道原消息的msgid。
區(qū)別于回執(zhí)消息:撤回消息需要修改所有接收方的消息狀態(tài),而不僅僅是發(fā)送方和單個(gè)接收方的。消息擴(kuò)散寫到每個(gè)接收方的消息流,各自的消息流對(duì)應(yīng)的msgid是不相同的,如果沿用referid的方式,那就需要記錄所有接收方的msgid。
12.2 解決方案
分析:撤回消息比回執(zhí)消息簡(jiǎn)單的是,撤回消息只需要更新消息的狀態(tài),而不需要知道原消息的內(nèi)容。接收方的消息的appinfo都是相同的,可以通過appinfo去做指向。
協(xié)議流程:
- 1)用戶a、b、c,都存在同一條消息,appinfo=s,sendtime=t;
- 2)a撤回該消息,則在a的消息流插入一條撤回的控制消息,消息體包含{appinfo=s,sendtime=t};
- 3)客戶端sync到撤回的控制消息,獲取到消息體的appinfo與sendtime,把本地appinfo=s且sendtime=t的原消息顯示為撤回狀態(tài),并刪除原消息數(shù)據(jù)。之所以引入sendtime字段,是為了防止appinfo碰撞,加的雙重校驗(yàn);
- 4)接收方撤回流程和發(fā)送方一致,也是通過插入撤回的控制消息。
該方案的優(yōu)點(diǎn)明顯,可靠性高,協(xié)議簡(jiǎn)單。
撤回消息的邏輯示意圖:
13、思考與總結(jié)
企業(yè)微信的IM消息架構(gòu)與微信類似,但是在to B業(yè)務(wù)場(chǎng)景面臨了一些新的挑戰(zhàn)。結(jié)合產(chǎn)品形態(tài)、分析策略,通過優(yōu)化方案,來確保消息系統(tǒng)的可靠性、穩(wěn)定性、安全性。
企業(yè)微信的to B業(yè)務(wù)繁雜,有很多定制化的需求,消息系統(tǒng)的設(shè)計(jì)需要考慮通用性和擴(kuò)展性,以便支持各種需求。例如:撤回消息的方案,可以適用于消息任何屬性的更新,滿足更多場(chǎng)景。
附錄:更多精華文章
[1] 有關(guān)IM架構(gòu)設(shè)計(jì)的文章:
《淺談IM系統(tǒng)的架構(gòu)設(shè)計(jì)》
《簡(jiǎn)述移動(dòng)端IM開發(fā)的那些坑:架構(gòu)設(shè)計(jì)、通信協(xié)議和客戶端》
《一套海量在線用戶的移動(dòng)端IM架構(gòu)設(shè)計(jì)實(shí)踐分享(含詳細(xì)圖文)》
《一套原創(chuàng)分布式即時(shí)通訊(IM)系統(tǒng)理論架構(gòu)方案》
《從零到卓越:京東客服即時(shí)通訊系統(tǒng)的技術(shù)架構(gòu)演進(jìn)歷程》
《蘑菇街即時(shí)通訊/IM服務(wù)器開發(fā)之架構(gòu)選擇》
《騰訊QQ1.4億在線用戶的技術(shù)挑戰(zhàn)和架構(gòu)演進(jìn)之路PPT》
《微信后臺(tái)基于時(shí)間序的海量數(shù)據(jù)冷熱分級(jí)架構(gòu)設(shè)計(jì)實(shí)踐》
《微信技術(shù)總監(jiān)談架構(gòu):微信之道——大道至簡(jiǎn)(演講全文)》
《如何解讀《微信技術(shù)總監(jiān)談架構(gòu):微信之道——大道至簡(jiǎn)》》
《快速裂變:見證微信強(qiáng)大后臺(tái)架構(gòu)從0到1的演進(jìn)歷程(一)》
《17年的實(shí)踐:騰訊海量產(chǎn)品的技術(shù)方法論》
《移動(dòng)端IM中大規(guī)模群消息的推送如何保證效率、實(shí)時(shí)性?》
《現(xiàn)代IM系統(tǒng)中聊天消息的同步和存儲(chǔ)方案探討》
《微信朋友圈千億訪問量背后的技術(shù)挑戰(zhàn)和實(shí)踐總結(jié)》
《以微博類應(yīng)用場(chǎng)景為例,總結(jié)海量社交系統(tǒng)的架構(gòu)設(shè)計(jì)步驟》
《子彈短信光鮮的背后:網(wǎng)易云信首席架構(gòu)師分享億級(jí)IM平臺(tái)的技術(shù)實(shí)踐》
《IM開發(fā)基礎(chǔ)知識(shí)補(bǔ)課(五):通俗易懂,正確理解并用好MQ消息隊(duì)列》
《微信技術(shù)分享:微信的海量IM聊天消息序列號(hào)生成實(shí)踐(算法原理篇)》
《微信技術(shù)分享:微信的海量IM聊天消息序列號(hào)生成實(shí)踐(容災(zāi)方案篇)》
《新手入門:零基礎(chǔ)理解大型分布式架構(gòu)的演進(jìn)歷史、技術(shù)原理、最佳實(shí)踐》
《一套高可用、易伸縮、高并發(fā)的IM群聊、單聊架構(gòu)方案設(shè)計(jì)實(shí)踐》
《社交軟件紅包技術(shù)解密(一):全面解密QQ紅包技術(shù)方案——架構(gòu)、技術(shù)實(shí)現(xiàn)等》
《社交軟件紅包技術(shù)解密(二):解密微信搖一搖紅包從0到1的技術(shù)演進(jìn)》
《社交軟件紅包技術(shù)解密(三):微信搖一搖紅包雨背后的技術(shù)細(xì)節(jié)》
《社交軟件紅包技術(shù)解密(四):微信紅包系統(tǒng)是如何應(yīng)對(duì)高并發(fā)的》
《社交軟件紅包技術(shù)解密(五):微信紅包系統(tǒng)是如何實(shí)現(xiàn)高可用性的》
《社交軟件紅包技術(shù)解密(六):微信紅包系統(tǒng)的存儲(chǔ)層架構(gòu)演進(jìn)實(shí)踐》
《社交軟件紅包技術(shù)解密(七):支付寶紅包的海量高并發(fā)技術(shù)實(shí)踐》
《社交軟件紅包技術(shù)解密(八):全面解密微博紅包技術(shù)方案》
《社交軟件紅包技術(shù)解密(九):談?wù)勈諵紅包的功能邏輯、容災(zāi)、運(yùn)維、架構(gòu)等》
《社交軟件紅包技術(shù)解密(十):手Q客戶端針對(duì)2020年春節(jié)紅包的技術(shù)實(shí)踐》
《社交軟件紅包技術(shù)解密(十一):解密微信紅包隨機(jī)算法(含代碼實(shí)現(xiàn))》
《即時(shí)通訊新手入門:一文讀懂什么是Nginx?它能否實(shí)現(xiàn)IM的負(fù)載均衡?》
《從游擊隊(duì)到正規(guī)軍(一):馬蜂窩旅游網(wǎng)的IM系統(tǒng)架構(gòu)演進(jìn)之路》
《從游擊隊(duì)到正規(guī)軍(二):馬蜂窩旅游網(wǎng)的IM客戶端架構(gòu)演進(jìn)和實(shí)踐總結(jié)》
《從游擊隊(duì)到正規(guī)軍(三):基于Go的馬蜂窩旅游網(wǎng)分布式IM系統(tǒng)技術(shù)實(shí)踐》
《IM開發(fā)基礎(chǔ)知識(shí)補(bǔ)課(六):數(shù)據(jù)庫用NoSQL還是SQL?讀這篇就夠了!》
《瓜子IM智能客服系統(tǒng)的數(shù)據(jù)架構(gòu)設(shè)計(jì)(整理自現(xiàn)場(chǎng)演講,有配套PPT)》
《阿里釘釘技術(shù)分享:企業(yè)級(jí)IM王者——釘釘在后端架構(gòu)上的過人之處》
《微信后臺(tái)基于時(shí)間序的新一代海量數(shù)據(jù)存儲(chǔ)架構(gòu)的設(shè)計(jì)實(shí)踐》
《IM開發(fā)基礎(chǔ)知識(shí)補(bǔ)課(九):想開發(fā)IM集群?先搞懂什么是RPC!》
《阿里技術(shù)分享:電商IM消息平臺(tái),在群聊、直播場(chǎng)景下的技術(shù)實(shí)踐》
《一套億級(jí)用戶的IM架構(gòu)技術(shù)干貨(上篇):整體架構(gòu)、服務(wù)拆分等》
《一套億級(jí)用戶的IM架構(gòu)技術(shù)干貨(下篇):可靠性、有序性、弱網(wǎng)優(yōu)化等》
《從新手到專家:如何設(shè)計(jì)一套億級(jí)消息量的分布式IM系統(tǒng)》
[2] QQ、微信團(tuán)隊(duì)原創(chuàng)技術(shù)文章:
《微信朋友圈千億訪問量背后的技術(shù)挑戰(zhàn)和實(shí)踐總結(jié)》
《騰訊技術(shù)分享:騰訊是如何大幅降低帶寬和網(wǎng)絡(luò)流量的(圖片壓縮篇)》
《騰訊技術(shù)分享:騰訊是如何大幅降低帶寬和網(wǎng)絡(luò)流量的(音視頻技術(shù)篇)》
《微信團(tuán)隊(duì)分享:微信移動(dòng)端的全文檢索多音字問題解決方案》
《騰訊技術(shù)分享:Android版手機(jī)QQ的緩存監(jiān)控與優(yōu)化實(shí)踐》
《微信團(tuán)隊(duì)分享:iOS版微信的高性能通用key-value組件技術(shù)實(shí)踐》
《微信團(tuán)隊(duì)分享:iOS版微信是如何防止特殊字符導(dǎo)致的炸群、APP崩潰的?》
《騰訊技術(shù)分享:Android手Q的線程死鎖監(jiān)控系統(tǒng)技術(shù)實(shí)踐》
《微信團(tuán)隊(duì)原創(chuàng)分享:iOS版微信的內(nèi)存監(jiān)控系統(tǒng)技術(shù)實(shí)踐》
《讓互聯(lián)網(wǎng)更快:新一代QUIC協(xié)議在騰訊的技術(shù)實(shí)踐分享》
《iOS后臺(tái)喚醒實(shí)戰(zhàn):微信收款到賬語音提醒技術(shù)總結(jié)》
《騰訊技術(shù)分享:社交網(wǎng)絡(luò)圖片的帶寬壓縮技術(shù)演進(jìn)之路》
《微信團(tuán)隊(duì)分享:視頻圖像的超分辨率技術(shù)原理和應(yīng)用場(chǎng)景》
《微信團(tuán)隊(duì)分享:微信每日億次實(shí)時(shí)音視頻聊天背后的技術(shù)解密》
《QQ音樂團(tuán)隊(duì)分享:Android中的圖片壓縮技術(shù)詳解(上篇)》
《QQ音樂團(tuán)隊(duì)分享:Android中的圖片壓縮技術(shù)詳解(下篇)》
《騰訊團(tuán)隊(duì)分享:手機(jī)QQ中的人臉識(shí)別酷炫動(dòng)畫效果實(shí)現(xiàn)詳解》
《騰訊團(tuán)隊(duì)分享 :一次手Q聊天界面中圖片顯示bug的追蹤過程分享》
《微信團(tuán)隊(duì)分享:微信Android版小視頻編碼填過的那些坑》
《微信手機(jī)端的本地?cái)?shù)據(jù)全文檢索優(yōu)化之路》
《企業(yè)微信客戶端中組織架構(gòu)數(shù)據(jù)的同步更新方案優(yōu)化實(shí)戰(zhàn)》
《微信團(tuán)隊(duì)披露:微信界面卡死超級(jí)bug“15。。。。”的來龍去脈》
《QQ 18年:解密8億月活的QQ后臺(tái)服務(wù)接口隔離技術(shù)》
《月活8.89億的超級(jí)IM微信是如何進(jìn)行Android端兼容測(cè)試的》
《以手機(jī)QQ為例探討移動(dòng)端IM中的“輕應(yīng)用”》
《一篇文章get微信開源移動(dòng)端數(shù)據(jù)庫組件WCDB的一切!》
《微信客戶端團(tuán)隊(duì)負(fù)責(zé)人技術(shù)訪談:如何著手客戶端性能監(jiān)控和優(yōu)化》
《微信后臺(tái)基于時(shí)間序的海量數(shù)據(jù)冷熱分級(jí)架構(gòu)設(shè)計(jì)實(shí)踐》
《微信團(tuán)隊(duì)原創(chuàng)分享:Android版微信的臃腫之困與模塊化實(shí)踐之路》
《微信后臺(tái)團(tuán)隊(duì):微信后臺(tái)異步消息隊(duì)列的優(yōu)化升級(jí)實(shí)踐分享》
《微信團(tuán)隊(duì)原創(chuàng)分享:微信客戶端SQLite數(shù)據(jù)庫損壞修復(fù)實(shí)踐》
《騰訊原創(chuàng)分享(一):如何大幅提升移動(dòng)網(wǎng)絡(luò)下手機(jī)QQ的圖片傳輸速度和成功率》
《騰訊原創(chuàng)分享(二):如何大幅壓縮移動(dòng)網(wǎng)絡(luò)下APP的流量消耗(下篇)》
《騰訊原創(chuàng)分享(三):如何大幅壓縮移動(dòng)網(wǎng)絡(luò)下APP的流量消耗(上篇)》
《微信Mars:微信內(nèi)部正在使用的網(wǎng)絡(luò)層封裝庫,即將開源》
《如約而至:微信自用的移動(dòng)端IM網(wǎng)絡(luò)層跨平臺(tái)組件庫Mars已正式開源》
《開源libco庫:?jiǎn)螜C(jī)千萬連接、支撐微信8億用戶的后臺(tái)框架基石 [源碼下載]》
《微信新一代通信安全解決方案:基于TLS1.3的MMTLS詳解》
《微信團(tuán)隊(duì)原創(chuàng)分享:Android版微信后臺(tái)保活實(shí)戰(zhàn)分享(進(jìn)程保活篇)》
《微信團(tuán)隊(duì)原創(chuàng)分享:Android版微信后臺(tái)保活實(shí)戰(zhàn)分享(網(wǎng)絡(luò)保活篇)》
《Android版微信從300KB到30MB的技術(shù)演進(jìn)(PPT講稿) [附件下載]》
《微信團(tuán)隊(duì)原創(chuàng)分享:Android版微信從300KB到30MB的技術(shù)演進(jìn)》
《微信技術(shù)總監(jiān)談架構(gòu):微信之道——大道至簡(jiǎn)(演講全文)》
《微信技術(shù)總監(jiān)談架構(gòu):微信之道——大道至簡(jiǎn)(PPT講稿) [附件下載]》
《如何解讀《微信技術(shù)總監(jiān)談架構(gòu):微信之道——大道至簡(jiǎn)》》
《微信海量用戶背后的后臺(tái)系統(tǒng)存儲(chǔ)架構(gòu)(視頻+PPT) [附件下載]》
《微信異步化改造實(shí)踐:8億月活、單機(jī)千萬連接背后的后臺(tái)解決方案》
《微信朋友圈海量技術(shù)之道PPT [附件下載]》
《微信對(duì)網(wǎng)絡(luò)影響的技術(shù)試驗(yàn)及分析(論文全文)》
《一份微信后臺(tái)技術(shù)架構(gòu)的總結(jié)性筆記》
《架構(gòu)之道:3個(gè)程序員成就微信朋友圈日均10億發(fā)布量[有視頻]》
《快速裂變:見證微信強(qiáng)大后臺(tái)架構(gòu)從0到1的演進(jìn)歷程(一)》
《快速裂變:見證微信強(qiáng)大后臺(tái)架構(gòu)從0到1的演進(jìn)歷程(二)》
《微信團(tuán)隊(duì)原創(chuàng)分享:Android內(nèi)存泄漏監(jiān)控和優(yōu)化技巧總結(jié)》
《全面總結(jié)iOS版微信升級(jí)iOS9遇到的各種“坑”》
《微信團(tuán)隊(duì)原創(chuàng)資源混淆工具:讓你的APK立減1M》
《微信團(tuán)隊(duì)原創(chuàng)Android資源混淆工具:AndResGuard [有源碼]》
《Android版微信安裝包“減肥”實(shí)戰(zhàn)記錄》
《iOS版微信安裝包“減肥”實(shí)戰(zhàn)記錄》
《移動(dòng)端IM實(shí)踐:iOS版微信界面卡頓監(jiān)測(cè)方案》
《微信“紅包照片”背后的技術(shù)難題》
《移動(dòng)端IM實(shí)踐:iOS版微信小視頻功能技術(shù)方案實(shí)錄》
《移動(dòng)端IM實(shí)踐:Android版微信如何大幅提升交互性能(一)》
《移動(dòng)端IM實(shí)踐:Android版微信如何大幅提升交互性能(二)》
《移動(dòng)端IM實(shí)踐:實(shí)現(xiàn)Android版微信的智能心跳機(jī)制》
《移動(dòng)端IM實(shí)踐:WhatsApp、Line、微信的心跳策略分析》
《移動(dòng)端IM實(shí)踐:谷歌消息推送服務(wù)(GCM)研究(來自微信)》
《移動(dòng)端IM實(shí)踐:iOS版微信的多設(shè)備字體適配方案探討》
《信鴿團(tuán)隊(duì)原創(chuàng):一起走過 iOS10 上消息推送(APNS)的坑》
《騰訊信鴿技術(shù)分享:百億級(jí)實(shí)時(shí)消息推送的實(shí)戰(zhàn)經(jīng)驗(yàn)》
《IPv6技術(shù)詳解:基本概念、應(yīng)用現(xiàn)狀、技術(shù)實(shí)踐(上篇)》
《IPv6技術(shù)詳解:基本概念、應(yīng)用現(xiàn)狀、技術(shù)實(shí)踐(下篇)》
《騰訊TEG團(tuán)隊(duì)原創(chuàng):基于MySQL的分布式數(shù)據(jù)庫TDSQL十年鍛造經(jīng)驗(yàn)分享》
《微信多媒體團(tuán)隊(duì)訪談:音視頻開發(fā)的學(xué)習(xí)、微信的音視頻技術(shù)和挑戰(zhàn)等》
《了解iOS消息推送一文就夠:史上最全iOS Push技術(shù)詳解》
《騰訊技術(shù)分享:微信小程序音視頻技術(shù)背后的故事》
《騰訊資深架構(gòu)師干貨總結(jié):一文讀懂大型分布式系統(tǒng)設(shè)計(jì)的方方面面》
《微信多媒體團(tuán)隊(duì)梁俊斌訪談:聊一聊我所了解的音視頻技術(shù)》
《騰訊音視頻實(shí)驗(yàn)室:使用AI黑科技實(shí)現(xiàn)超低碼率的高清實(shí)時(shí)視頻聊天》
《騰訊技術(shù)分享:微信小程序音視頻與WebRTC互通的技術(shù)思路和實(shí)踐》
《手把手教你讀取Android版微信和手Q的聊天記錄(僅作技術(shù)研究學(xué)習(xí))》
《微信技術(shù)分享:微信的海量IM聊天消息序列號(hào)生成實(shí)踐(算法原理篇)》
《微信技術(shù)分享:微信的海量IM聊天消息序列號(hào)生成實(shí)踐(容災(zāi)方案篇)》
《騰訊技術(shù)分享:GIF動(dòng)圖技術(shù)詳解及手機(jī)QQ動(dòng)態(tài)表情壓縮技術(shù)實(shí)踐》
《微信團(tuán)隊(duì)分享:Kotlin漸被認(rèn)可,Android版微信的技術(shù)嘗鮮之旅》
《QQ設(shè)計(jì)團(tuán)隊(duì)分享:新版 QQ 8.0 語音消息改版背后的功能設(shè)計(jì)思路》
《微信團(tuán)隊(duì)分享:極致優(yōu)化,iOS版微信編譯速度3倍提升的實(shí)踐總結(jié)》
《IM“掃一掃”功能很好做?看看微信“掃一掃識(shí)物”的完整技術(shù)實(shí)現(xiàn)》
《微信團(tuán)隊(duì)分享:微信支付代碼重構(gòu)帶來的移動(dòng)端軟件架構(gòu)上的思考》
《IM開發(fā)寶典:史上最全,微信各種功能參數(shù)和邏輯規(guī)則資料匯總》
《微信團(tuán)隊(duì)分享:微信直播聊天室單房間1500萬在線的消息架構(gòu)演進(jìn)之路》
本文已同步發(fā)布于“即時(shí)通訊技術(shù)圈”公眾號(hào)。

▲ 本文在公眾號(hào)上的鏈接是:點(diǎn)此進(jìn)入。同步發(fā)布鏈接是:http://www.52im.net/thread-3631-1-1.html