跟著源碼學(xué)IM(十):基于Netty,搭建高性能IM集群(含技術(shù)思路+源碼)
Posted on 2022-01-18 16:45 Jack Jiang 閱讀(248) 評(píng)論(0) 編輯 收藏本文原題“搭建高性能的IM系統(tǒng)”,作者“劉蒞”,內(nèi)容有修訂和改動(dòng)。為了尊重原創(chuàng),如需轉(zhuǎn)載,請(qǐng)聯(lián)系作者獲得授權(quán)。
1、引言
相信很多朋友對(duì)微信、QQ等聊天軟件的實(shí)現(xiàn)原理都非常感興趣,筆者同樣對(duì)這些軟件有著深厚的興趣。而且筆者在公司也是做IM的,公司的IM每天承載著上億條消息的發(fā)送!
正好有這樣的技術(shù)資源和條件,所以前段時(shí)間,筆者利用業(yè)余時(shí)間,基于Netty開(kāi)發(fā)了一套基本功能比較完善的IM系統(tǒng)。該系統(tǒng)支持私聊、群聊、會(huì)話管理、心跳檢測(cè),支持服務(wù)注冊(cè)、負(fù)載均衡,支持任意節(jié)點(diǎn)水平擴(kuò)容。
這段時(shí)間,網(wǎng)上的一些讀者,也希望筆者分享一些Netty或者IM相關(guān)的知識(shí),所以今天筆者把開(kāi)發(fā)的這套IM系統(tǒng)分享給大家。
本文將根據(jù)筆者這次的業(yè)余技術(shù)實(shí)踐,為你講述如何基于Netty+Zk+Redis來(lái)搭建一套高性能IM集群,包括本次實(shí)現(xiàn)IM集群的技術(shù)原理和實(shí)例代碼,希望能帶給你啟發(fā)。

學(xué)習(xí)交流:
- 移動(dòng)端IM開(kāi)發(fā)入門(mén)文章:《新手入門(mén)一篇就夠:從零開(kāi)發(fā)移動(dòng)端IM》
- 開(kāi)源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK
(本文已同步發(fā)布于:http://www.52im.net/thread-3816-1-1.html )
2、本文源碼
源碼的目錄結(jié)構(gòu),如下圖所示:

3、知識(shí)準(zhǔn)備
* 重要提示:本文不是一篇即時(shí)通訊理論文章,文章內(nèi)容來(lái)自代碼實(shí)戰(zhàn),如果你對(duì)即時(shí)通訊(IM)技術(shù)理論了解的太少,建議先詳細(xì)閱讀:《新手入門(mén)一篇就夠:從零開(kāi)發(fā)移動(dòng)端IM》。
可能有人不知道 Netty 是什么,這里簡(jiǎn)單介紹下:
Netty 是一個(gè) Java 開(kāi)源框架。Netty 提供異步的、事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用程序框架和工具,用以快速開(kāi)發(fā)高性能、高可靠性的網(wǎng)絡(luò)服務(wù)器和客戶端程序。
也就是說(shuō),Netty 是一個(gè)基于 NIO 的客戶、服務(wù)器端編程框架,使用Netty 可以確保你快速和簡(jiǎn)單的開(kāi)發(fā)出一個(gè)網(wǎng)絡(luò)應(yīng)用,例如實(shí)現(xiàn)了某種協(xié)議的客戶,服務(wù)端應(yīng)用。
Netty 相當(dāng)簡(jiǎn)化和流線化了網(wǎng)絡(luò)應(yīng)用的編程開(kāi)發(fā)過(guò)程,例如,TCP 和 UDP 的 Socket 服務(wù)開(kāi)發(fā)。
以下是有關(guān)Netty的入門(mén)文章:
- 1)新手入門(mén):目前為止最透徹的的Netty高性能原理和框架架構(gòu)解析
- 2)寫(xiě)給初學(xué)者:Java高性能NIO框架Netty的學(xué)習(xí)方法和進(jìn)階策略
- 3)史上最通俗Netty框架入門(mén)長(zhǎng)文:基本介紹、環(huán)境搭建、動(dòng)手實(shí)戰(zhàn)
如果你連Java的NIO都不知道是什么,下面的文章建議優(yōu)先讀:
- 1)少啰嗦!一分鐘帶你讀懂Java的NIO和經(jīng)典IO的區(qū)別
- 2)史上最強(qiáng)Java NIO入門(mén):擔(dān)心從入門(mén)到放棄的,請(qǐng)讀這篇!
- 3)Java的BIO和NIO很難懂?用代碼實(shí)踐給你看,再不懂我轉(zhuǎn)行!
Netty源碼和API的在線查閱地址:
4、系統(tǒng)架構(gòu)

系統(tǒng)的架構(gòu)如上圖所示:整個(gè)系統(tǒng)是一個(gè)C/S系統(tǒng),客戶端沒(méi)有做復(fù)雜的圖形化界面而是用Java終端開(kāi)發(fā)的(黑窗口),服務(wù)端IM實(shí)例是Netty寫(xiě)的socket服務(wù)。
ZK作為服務(wù)注冊(cè)中心,Redis用來(lái)做分布式會(huì)話的緩存,并保存用戶信息和輕量級(jí)的消息隊(duì)列。
對(duì)于整個(gè)系統(tǒng)架構(gòu)中各部分的工作原理,我們將在接下來(lái)的各章節(jié)中一一介紹。
5、服務(wù)端的工作原理
在上述架構(gòu)中:NettyServer啟動(dòng),每啟動(dòng)一臺(tái)Server節(jié)點(diǎn),都會(huì)把自身的節(jié)點(diǎn)信息,如:ip、port等信息注冊(cè)到ZK上(臨時(shí)節(jié)點(diǎn))。
正如上節(jié)架構(gòu)圖上啟動(dòng)了兩臺(tái)NettyServer,所以ZK上會(huì)保存兩個(gè)Server的信息。
同時(shí)ZK將監(jiān)聽(tīng)每臺(tái)Server節(jié)點(diǎn),如果Server宕機(jī)ZK就會(huì)刪除當(dāng)前機(jī)器所注冊(cè)的信息(把臨時(shí)節(jié)點(diǎn)刪除),這樣就完成了簡(jiǎn)單的服務(wù)注冊(cè)的功能。
6、客戶端的工作原理
Client啟動(dòng)時(shí),會(huì)先從ZK上隨機(jī)選擇一個(gè)可用的NettyServer(隨機(jī)表示可以實(shí)現(xiàn)負(fù)載均衡),拿到NettyServer的信息(IP和port)后與NettyServer建立鏈接。
鏈接建立起來(lái)后,NettyServer端會(huì)生成一個(gè)Session(即會(huì)話),用來(lái)把當(dāng)前客戶端的Channel等信息組裝成一個(gè)Session對(duì)象,保存在一個(gè)SessionMap里,同時(shí)也會(huì)把這個(gè)Session保存在Redis中。
這個(gè)會(huì)話特別重要,通過(guò)會(huì)話,我們能獲取當(dāng)前Client和NettyServer的Channel等信息。
7、Session的作用
我們啟動(dòng)多個(gè)Client,由于每個(gè)Client啟動(dòng),都會(huì)先從ZK上隨機(jī)獲取NettyServer的的信息,所以如果啟動(dòng)多個(gè)Client,就會(huì)連接到不同的NettyServer上。
熟悉Netty的朋友都知道,Client與Server建立接連后會(huì)產(chǎn)生一個(gè)Channel,通過(guò)Channel,Client和Server才能進(jìn)行正常的網(wǎng)絡(luò)數(shù)據(jù)傳輸。
如果Client1和Client2連接在同一個(gè)Server上:那么Server通過(guò)SessionMap分別拿到Client1和Client2的會(huì)話,會(huì)話中包含Channel信息,有了兩個(gè)Client的Channel,Client1和Client2便可完成消息通信。
如果Client1和Client2連接到不同的NettyServer上:Client1和Client2要進(jìn)行通信,該怎么辦?這個(gè)問(wèn)題放在后面解答。
8、高效的數(shù)據(jù)傳輸
無(wú)論是IM系統(tǒng),還是分布式的RPC框架,高效的網(wǎng)絡(luò)數(shù)據(jù)傳輸,無(wú)疑會(huì)極大的提升系統(tǒng)的性能。
數(shù)據(jù)通過(guò)網(wǎng)絡(luò)傳輸時(shí),一般把對(duì)象通序列化成二進(jìn)制字節(jié)流數(shù)組,然后將數(shù)據(jù)通過(guò)socket傳給對(duì)方服務(wù)器,對(duì)方服務(wù)器拿到二進(jìn)制字節(jié)流后再反序列化成對(duì)象,達(dá)到遠(yuǎn)程通信的目的。
在Java領(lǐng)域,Java序列化對(duì)象的方式有嚴(yán)重的性能問(wèn)題,業(yè)界常用谷歌的protobuf來(lái)實(shí)現(xiàn)序列化反序列化(見(jiàn)《Protobuf通信協(xié)議詳解:代碼演示、詳細(xì)原理介紹等》)。

protobuf支持不同的編程語(yǔ)言,可以實(shí)現(xiàn)跨語(yǔ)言的系統(tǒng)調(diào)用,并且有著極高的序列化反序列化性能,本系統(tǒng)也采用protobuf來(lái)做數(shù)據(jù)的序列化。
關(guān)于Protobuf的基本認(rèn)之,下面這幾篇可以深入讀一讀:
- 《強(qiáng)列建議將Protobuf作為你的即時(shí)通訊應(yīng)用數(shù)據(jù)傳輸格式》
- 《全方位評(píng)測(cè):Protobuf性能到底有沒(méi)有比JSON快5倍?》
- 《金蝶隨手記團(tuán)隊(duì)分享:還在用JSON? Protobuf讓數(shù)據(jù)傳輸更省更快(原理篇)》
另外:《一套海量在線用戶的移動(dòng)端IM架構(gòu)設(shè)計(jì)實(shí)踐分享(含詳細(xì)圖文)》一文中,“3、協(xié)議設(shè)計(jì)”這一節(jié)有關(guān)于protobuf在IM中的實(shí)戰(zhàn)設(shè)計(jì)和使用,可以一并學(xué)習(xí)一下。
9、聊天協(xié)議定義
我們?cè)谑褂酶鞣N聊天APP時(shí),會(huì)發(fā)各種各樣的消息,每種消息都會(huì)對(duì)應(yīng)不同的消息格式(即“聊天協(xié)議”)。
聊天協(xié)議中主要包含幾種重要的信息:
- 1)消息類(lèi)型;
- 2)發(fā)送時(shí)間;
- 3)消息的收發(fā)人;
- 4)聊天類(lèi)型(群聊或私聊)。
我的這套IM系統(tǒng)中,聊天協(xié)議定義如下:
syntax = "proto3";
option java_package = "model.chat";
option java_outer_classname = "RpcMsg";
message Msg{
string msg_id = 1;
int64 from_uid = 2;
int64 to_uid = 3;
int32 format = 4;
int32 msg_type = 5;
int32 chat_type = 6;
int64 timestamp = 7;
string body = 8;
repeated int64 to_uid_list = 9;
}
如上面的protobuf代碼,字段的具體含義如下:
- 1)msg_id:表示消息的唯一id,可以用UUID表示;
- 2)from_uid:消息發(fā)送者的uid;
- 3)to_uid:消息接收者的uid;
- 4)format:消息格式,我們使用各種聊天軟件時(shí),會(huì)發(fā)送文字消息,語(yǔ)音消息,圖片消息等等等等,每種消息有不同的消息格式,我們用format來(lái)表示(由于本系統(tǒng)是java終端,format字段沒(méi)有太大含義,可有可無(wú));
- 5)msg_type:消息類(lèi)型,比如登錄消息、聊天消息、ack消息、ping、pong消息;
- 6)chat_type:聊天類(lèi)型,如群聊、私聊;
- 7)timestamp:發(fā)送消息的時(shí)間戳;
- 8)body:消息的具體內(nèi)容,載體;
- 9)to_uid_list:這個(gè)字段用戶群聊消息提高群聊消息的性能,具體作用會(huì)在群聊原理部分詳細(xì)解釋。
10、私聊消息發(fā)送原理
Client1給Client2發(fā)消息時(shí),我們需要構(gòu)建上節(jié)中的消息體。
具體就是:from_uid是Client1的uid、to_uid是Client2的uid。
NettyServer收到消息后的處理邏輯是:
- 1)解析到to_uid字段;
- 2)從SessionMap或者Redis中保存的Session集合中獲取to_uid即Client2的Session;
- 3)從Session中取出Client2的Channel;
- 4)然后將消息通過(guò)Client2的Channel發(fā)給Client2。
11、群聊消息發(fā)送原理
群聊消息的分發(fā)通常有兩種技術(shù)實(shí)現(xiàn)方式,我們一一來(lái)看看。
方式一:假設(shè)一個(gè)群有100人,如果Client1給一個(gè)群的所有人發(fā)消息,其實(shí)相當(dāng)于Client1分別給其余99人分別發(fā)一條消息。我們可以直接在Client端,通過(guò)循環(huán),分別給群里的99人發(fā)消息即可,相當(dāng)于Client發(fā)送給NettyServer發(fā)送了99次相同的消息(除了to_uid不同)。
上述方案有很?chē)?yán)重的性能問(wèn)題:Client1通過(guò)循環(huán)99次,分別把消息發(fā)給NettyServer,NettyServer收到這99條消息后,分別將消息發(fā)給群內(nèi)其余的用戶。先拋開(kāi)移動(dòng)端的特殊性(比如循環(huán)還沒(méi)完成手機(jī)就有可能退到后臺(tái)被系統(tǒng)掛起),顯然Client1到NettyServer的99次循環(huán)存在明顯不合理地方。
方式二:上節(jié)的消息體中to_uid_list字段就是為了解決這個(gè)方式一的性能問(wèn)題的。Client1把群內(nèi)其余99個(gè)Client的uid保存在to_uid_list中,然后NettyServer只發(fā)一條消息,NettyServer收到這一條消息后,通過(guò)to_uid_list字段解析群內(nèi)其余99的Client的uid,再通過(guò)循環(huán)把消息分別發(fā)送給群內(nèi)其余的Client。
可以看到:方式二的群聊時(shí),Client1與NettyServer只進(jìn)行1次消息傳輸,相比于方式一,效率提高了50%。
11、技術(shù)關(guān)鍵點(diǎn)1:客戶端分別連接在不同IM實(shí)例時(shí)如何通信?
針對(duì)本文中的架構(gòu),如果多個(gè)Client分別連接在不同的Server上,Client之間應(yīng)該如何通信呢?
為了回答這個(gè)問(wèn)題,我們首先要明白Session的作用。
我們做過(guò)JavaWeb開(kāi)發(fā)的朋友都知道,Session用來(lái)保存用戶的登錄信息。
在IM系統(tǒng)中也是如此:Session中保存用戶的Channel信息。當(dāng)Client與Server建立鏈接成功后,會(huì)產(chǎn)生一個(gè)Channel,Client和Server是通過(guò)Channel,實(shí)現(xiàn)數(shù)據(jù)傳輸。當(dāng)兩端鏈接建立起來(lái)后,Server會(huì)構(gòu)建出一個(gè)Session對(duì)象,保存uid和Channel等信息,并把這個(gè)Session保存在一個(gè)SessionMap里(NettyServer的內(nèi)存里),uid為key,我們可以通過(guò)uid就可以找到這個(gè)uid對(duì)應(yīng)的Session。
但只有SessionMap還不夠:我們需要利用Redis,它的作用是保存整個(gè)NettyServer集群全部鏈接成功的用戶,這也是一種Session,但這種Session沒(méi)有保存uid和Channel的對(duì)應(yīng)關(guān)系,而是保存Client鏈接到NettyServer的信息,如Client鏈接到的這個(gè)NettyServer的ip、port等。通過(guò)uid,我們同樣可以從Redis中拿到當(dāng)前Client鏈接到的NettyServer的信息。正是有了這個(gè)信息,我們才能做到,NettyServer集群任意節(jié)點(diǎn)水平擴(kuò)容。
當(dāng)用戶量少的時(shí)候:我們只需要一臺(tái)NettyServer節(jié)點(diǎn)便可以扛住流量,所有的Client鏈接到同一個(gè)NettyServer上,并在NettyServer的SessionMap中保存每個(gè)Client的會(huì)話。Client1與Client2通信時(shí),Client1把消息發(fā)給NettyServer,NettyServer從SessionMap中取出Client2的Session和Channel,將消息發(fā)給Client2。
隨著用戶量不斷增多:一臺(tái)NettyServer不夠,我們?cè)黾恿藥着_(tái)NettyServer,這時(shí)Client1鏈接到NettyServer1上并在SessionMap和Redis中保存了會(huì)話和Client1的鏈接信息,Client2鏈接到NettyServer2上并在SessionMap和Redis中保存了會(huì)話和Client2的鏈接信息。Client1給Client2發(fā)消息時(shí),通過(guò)NettyServer1的SessionMap找不到Client2的會(huì)話,消息無(wú)法發(fā)送,于是便從Redis中獲取Client2鏈接在哪臺(tái)NettyServer上。獲取到Client2所鏈接的NettyServer信息后,我們可以把消息轉(zhuǎn)發(fā)給NettyServer2,NettyServer2收到消息后,從NettyServer2的SessionMap中獲取Client2的Session和Channel,然后將消息發(fā)送給Client2。
那么:NettyServer1的消息如何轉(zhuǎn)發(fā)給NettyServer2呢?答案是通過(guò)消息隊(duì)列,如Redis中的list數(shù)據(jù)結(jié)構(gòu)。每臺(tái)NettyServer啟動(dòng)后都需要監(jiān)聽(tīng)一個(gè)自己的Redis中的消息隊(duì)列,這個(gè)隊(duì)列用戶接收其他NettyServer轉(zhuǎn)發(fā)給當(dāng)前NettyServer的消息。
* Jack Jiang點(diǎn)評(píng):上述集群方案中,Redis既作為在線用戶列表存儲(chǔ)中心,又作為集群中不同IM長(zhǎng)連接實(shí)例的消息中轉(zhuǎn)服務(wù)(此時(shí)的Redis作用相當(dāng)于MQ),那Redis不就成為了整個(gè)分布式集群的單點(diǎn)瓶頸了嗎?
12、技術(shù)關(guān)鍵點(diǎn)2:鏈接斷開(kāi),如何處理?
如果Client與NettyServer,由于某種原因(客戶端退出、服務(wù)端重啟、網(wǎng)絡(luò)因素等)斷開(kāi)鏈接,我們必須要從SessionMap刪除會(huì)話和Redis中保留的數(shù)據(jù)。
如果不清除這兩類(lèi)數(shù)據(jù)的話,很有可能Client1發(fā)送給Client2的消息,可能會(huì)發(fā)給其他用戶,或者就算Client2處于登錄狀態(tài),Client2也收到不到消息。
我們可以在Netty框架中的channelInactive方法里,處理鏈接斷開(kāi)后的會(huì)話清除操作。
13、技術(shù)關(guān)鍵點(diǎn)3:ping、pong的作用
當(dāng)Client與NettyServer建立鏈接后,由于雙端網(wǎng)絡(luò)較差,Client與NettyServer斷開(kāi)鏈接后,如果NettyServer沒(méi)有感知到,也就沒(méi)有清除SessionMap和Redis中的數(shù)據(jù),這將會(huì)造成嚴(yán)重的問(wèn)題(對(duì)于服務(wù)端來(lái)說(shuō),這個(gè)Client的會(huì)話實(shí)際處于“假死”狀態(tài),消息是無(wú)法實(shí)時(shí)發(fā)送過(guò)去的)。
此時(shí)就需要一種ping/pong機(jī)制(也就是心跳機(jī)制啦)。
實(shí)現(xiàn)原理就是:通過(guò)定時(shí)任務(wù),Client每隔一段時(shí)間給NettyServer發(fā)一個(gè)ping消息,NettyServer收到ping消息后給客戶端回復(fù)一個(gè)pong消息,確??蛻舳撕头?wù)端能一直保持鏈接狀態(tài)。如果Client與NettyServer斷連了,NettyServer可以立即發(fā)現(xiàn)并清空會(huì)話數(shù)據(jù)。Netty中的我們可以在Pipeline中添加IdleStateHandler,可達(dá)到這樣的目的。
如果你不明白心跳的作用,務(wù)必讀以下文章:
- 《為何基于TCP協(xié)議的移動(dòng)端IM仍然需要心跳保活機(jī)制?》
- 《一文讀懂即時(shí)通訊應(yīng)用中的網(wǎng)絡(luò)心跳包機(jī)制:作用、原理、實(shí)現(xiàn)思路等》
也可以學(xué)習(xí)一下主流IM的心跳邏輯:
- 《微信團(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ò)保活篇)》
- 《移動(dòng)端IM實(shí)踐:實(shí)現(xiàn)Android版微信的智能心跳機(jī)制》
- 《移動(dòng)端IM實(shí)踐:WhatsApp、Line、微信的心跳策略分析》
如果覺(jué)得理論不夠直觀,下面的代碼實(shí)例可以直觀地進(jìn)行學(xué)習(xí):
- 《正確理解IM長(zhǎng)連接的心跳及重連機(jī)制,并動(dòng)手實(shí)現(xiàn)(有完整IM源碼)》
- 《一種Android端IM智能心跳算法的設(shè)計(jì)與實(shí)現(xiàn)探討(含樣例代碼)》
- 《自已開(kāi)發(fā)IM有那么難嗎?手把手教你自擼一個(gè)Andriod版簡(jiǎn)易IM (有源碼)》
- 《手把手教你用Netty實(shí)現(xiàn)網(wǎng)絡(luò)通信程序的心跳機(jī)制、斷線重連機(jī)制》
其實(shí),心跳算法的實(shí)際效果,還是有一些邏輯技巧的,以下兩篇建議必讀:
- 《Web端即時(shí)通訊實(shí)踐干貨:如何讓你的WebSocket斷網(wǎng)重連更快速?》
- 《融云技術(shù)分享:融云安卓端IM產(chǎn)品的網(wǎng)絡(luò)鏈路?;罴夹g(shù)實(shí)踐》
14、技術(shù)關(guān)鍵點(diǎn)4:為Server和Client添加Hook
如果NettyServer重啟了或者進(jìn)程被kill掉,我們需要清除當(dāng)前節(jié)點(diǎn)的SessionMap(其實(shí)不用清理SessionMap,數(shù)據(jù)在內(nèi)存里重啟會(huì)自動(dòng)刪除的)和Redis保存的Client的鏈接信息。
我們需要遍歷SessionMap找出所有的uid,然后一一清除Redis的數(shù)據(jù),然后優(yōu)雅退出。此時(shí),我們就需要為我們的NettyServer添加一個(gè)Hook,來(lái)做數(shù)據(jù)清理。
15、技術(shù)關(guān)鍵點(diǎn)5:對(duì)方不在線該如何處理消息?
Client1給對(duì)方發(fā)消息,我們通過(guò)SessionMap或Redis拿不到對(duì)方的會(huì)話數(shù)據(jù),這就表明對(duì)方不在線。
此時(shí):我們需要把消息存儲(chǔ)在離線消息表中,當(dāng)對(duì)方下次登錄時(shí),NettyServer查離線消息表,把消息發(fā)給登錄用戶(最好是批量發(fā)送,提高性能)。
IM中的離線消息處理,也不是個(gè)簡(jiǎn)單的技術(shù)點(diǎn),有興趣可以深入學(xué)習(xí)一下:
- 《IM消息送達(dá)保證機(jī)制實(shí)現(xiàn)(二):保證離線消息的可靠投遞》
- 《阿里IM技術(shù)分享(六):閑魚(yú)億級(jí)IM消息系統(tǒng)的離線推送到達(dá)率優(yōu)化》
- 《IM開(kāi)發(fā)干貨分享:我是如何解決大量離線消息導(dǎo)致客戶端卡頓的》
- 《IM開(kāi)發(fā)干貨分享:如何優(yōu)雅的實(shí)現(xiàn)大量離線消息的可靠投遞》
- 《喜馬拉雅億級(jí)用戶量的離線消息推送系統(tǒng)架構(gòu)設(shè)計(jì)實(shí)踐》
16、寫(xiě)在最后
代碼寫(xiě)成這樣,也算是了確了自已手?jǐn)]IM的心愿。唯一遺憾的是,時(shí)間比較緊張,還沒(méi)來(lái)得及實(shí)現(xiàn)消息ack機(jī)制,保證消息一定會(huì)送達(dá),這個(gè)筆者以后會(huì)補(bǔ)充上去的。
好了,這就是我開(kāi)發(fā)的這個(gè)簡(jiǎn)易的聊天系統(tǒng),麻雀雖小,五臟俱全,大家有什么不明白的地方,可以直接在下方留言,筆者會(huì)一一回復(fù)的,謝謝大家。
17、系列文章
- 《跟著源碼學(xué)IM(一):手把手教你用Netty實(shí)現(xiàn)心跳機(jī)制、斷線重連機(jī)制》
- 《跟著源碼學(xué)IM(二):自已開(kāi)發(fā)IM很難?手把手教你擼一個(gè)Andriod版IM》
- 《跟著源碼學(xué)IM(三):基于Netty,從零開(kāi)發(fā)一個(gè)IM服務(wù)端》
- 《跟著源碼學(xué)IM(四):拿起鍵盤(pán)就是干,教你徒手開(kāi)發(fā)一套分布式IM系統(tǒng)》
- 《跟著源碼學(xué)IM(五):正確理解IM長(zhǎng)連接、心跳及重連機(jī)制,并動(dòng)手實(shí)現(xiàn)》
- 《跟著源碼學(xué)IM(六):手把手教你用Go快速搭建高性能、可擴(kuò)展的IM系統(tǒng)》
- 《跟著源碼學(xué)IM(七):手把手教你用WebSocket打造Web端IM聊天》
- 《跟著源碼學(xué)IM(八):萬(wàn)字長(zhǎng)文,手把手教你用Netty打造IM聊天》
- 《跟著源碼學(xué)IM(九):基于Netty實(shí)現(xiàn)一套分布式IM系統(tǒng)》
- 《跟著源碼學(xué)IM(十):基于Netty,搭建高性能IM集群(含技術(shù)思路+源碼)》(* 本文)
18、參考資料
[1] 新手入門(mén):目前為止最透徹的的Netty高性能原理和框架架構(gòu)解析
[2] 寫(xiě)給初學(xué)者:Java高性能NIO框架Netty的學(xué)習(xí)方法和進(jìn)階策略
[3] 史上最強(qiáng)Java NIO入門(mén):擔(dān)心從入門(mén)到放棄的,請(qǐng)讀這篇!
[4] Java的BIO和NIO很難懂?用代碼實(shí)踐給你看,再不懂我轉(zhuǎn)行!
[5] 史上最通俗Netty框架入門(mén)長(zhǎng)文:基本介紹、環(huán)境搭建、動(dòng)手實(shí)戰(zhàn)
[6] 理論聯(lián)系實(shí)際:一套典型的IM通信協(xié)議設(shè)計(jì)詳解
[7] 淺談IM系統(tǒng)的架構(gòu)設(shè)計(jì)
[8] 簡(jiǎn)述移動(dòng)端IM開(kāi)發(fā)的那些坑:架構(gòu)設(shè)計(jì)、通信協(xié)議和客戶端
[9] 一套海量在線用戶的移動(dòng)端IM架構(gòu)設(shè)計(jì)實(shí)踐分享(含詳細(xì)圖文)
[10] 一套原創(chuàng)分布式即時(shí)通訊(IM)系統(tǒng)理論架構(gòu)方案
[11] 一套高可用、易伸縮、高并發(fā)的IM群聊、單聊架構(gòu)方案設(shè)計(jì)實(shí)踐
[12] 一套億級(jí)用戶的IM架構(gòu)技術(shù)干貨(上篇):整體架構(gòu)、服務(wù)拆分等
[13] 一套億級(jí)用戶的IM架構(gòu)技術(shù)干貨(下篇):可靠性、有序性、弱網(wǎng)優(yōu)化等
[14] 從新手到專(zhuān)家:如何設(shè)計(jì)一套億級(jí)消息量的分布式IM系統(tǒng)
[15] 基于實(shí)踐:一套百萬(wàn)消息量小規(guī)模IM系統(tǒng)技術(shù)要點(diǎn)總結(jié)
(本文已同步發(fā)布于:http://www.52im.net/thread-3816-1-1.html )
作者:Jack Jiang (點(diǎn)擊作者姓名進(jìn)入Github)
出處:http://www.52im.net/space-uid-1.html
交流:歡迎加入即時(shí)通訊開(kāi)發(fā)交流群 215891622
討論:http://www.52im.net/
Jack Jiang同時(shí)是【原創(chuàng)Java
Swing外觀工程BeautyEye】和【輕量級(jí)移動(dòng)端即時(shí)通訊框架MobileIMSDK】的作者,可前往下載交流。
本博文
歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明出處(也可前往 我的52im.net 找到我)。