最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

基于Netty,從零開發(fā)IM(四):編碼實(shí)踐篇(系統(tǒng)優(yōu)化)

2022-07-25 12:17 作者:nickkckckck  | 我要投稿

本文由作者“大白菜”分享,有較多修訂和改動(dòng)。注意:本系列是給IM初學(xué)者的文章,IM老油條們還望海涵,勿噴!

1、引言

前兩篇《編碼實(shí)踐篇(單聊功能)》、《編碼實(shí)踐篇(群聊功能)》分別實(shí)現(xiàn)了控制臺(tái)版本的IM單聊和群聊的功能。

通過前兩篇這兩個(gè)小案例來體驗(yàn)的只是Netty在IM系統(tǒng)這種真實(shí)的開發(fā)實(shí)踐,但對(duì)比在真實(shí)的Netty應(yīng)用開發(fā)當(dāng)中,本系列的案例是非常的簡(jiǎn)單的,主要目的其實(shí)是讓大家可以更好地了解其原理,從而寫出更高質(zhì)量的 Netty 代碼。

不過,雖然 Netty 的性能很高,但是也不能保證隨意寫出來的項(xiàng)目就是性能很高的,所以本篇將主要講解幾個(gè)基于Netty的IM系統(tǒng)的優(yōu)化實(shí)戰(zhàn)技術(shù)點(diǎn)。

學(xué)習(xí)交流:

- 移動(dòng)端IM開發(fā)入門文章:《新手入門一篇就夠:從零開發(fā)移動(dòng)端IM》

- 開源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK(備用地址點(diǎn)此)

(本文同步發(fā)布于:http://www.52im.net/thread-3988-1-1.html)

2、寫在前面

建議你在閱讀本文之前,務(wù)必先讀本系列的前三篇《IM系統(tǒng)設(shè)計(jì)篇》、《編碼實(shí)踐篇(單聊功能)》、《編碼實(shí)踐篇(群聊功能)》。

最后,在開始本文之前,請(qǐng)您務(wù)必提前了解Netty的相關(guān)基礎(chǔ)知識(shí),可從本系列首篇《IM系統(tǒng)設(shè)計(jì)篇》中的“知識(shí)準(zhǔn)備”一章開始。

3、系列文章

本文是系列文章的第3篇,以下是系列目錄:

  • 《基于Netty,從零開發(fā)IM(一):IM系統(tǒng)設(shè)計(jì)篇》

  • 《基于Netty,從零開發(fā)IM(二):編碼實(shí)踐篇(單聊功能)》

  • 《基于Netty,從零開發(fā)IM(三):編碼實(shí)踐篇(群聊功能)》

  • 《基于Netty,從零開發(fā)IM(四):編碼實(shí)踐篇(系統(tǒng)優(yōu)化)》(* 本文

4、基于Netty的IM系統(tǒng)常見優(yōu)化方向

常見優(yōu)化方向腦圖:

我們逐條詳細(xì)解釋一下這些優(yōu)化的目的:

  • 1)心跳檢測(cè):主要是避免連接假死現(xiàn)象;

  • 2)連接斷開:則刪除通道綁定屬性、刪除對(duì)應(yīng)的映射關(guān)系,這些信息都是保存在內(nèi)存當(dāng)中的,如果不刪除則造成資源浪費(fèi);

  • 3)性能問題:用戶 ID 和?Channel?的關(guān)系綁定存在內(nèi)存當(dāng)中,比如:Map,key 是用戶 ID,value 是 Channel,如果用戶量多的情況(客戶端數(shù)量過多),那么服務(wù)端的內(nèi)存將被消耗殆盡;

  • 4)性能問題:每次服務(wù)端往客戶端推送消息,都需從Map里查找到對(duì)應(yīng)的Channel,如果數(shù)量較大和查詢頻繁的情況下如何保證查詢性能;

  • 5)安全問題:HashMap 是線程不安全的,并發(fā)情況下,我們?nèi)绾稳ケWC線程安全;

  • 6)身份校驗(yàn):如何 LoginHandler 是負(fù)責(zé)登錄認(rèn)證的業(yè)務(wù) Handler,AuthHandler 是負(fù)責(zé)每次請(qǐng)求時(shí)校驗(yàn)該請(qǐng)求是否已經(jīng)認(rèn)證了,這些 Handler 在鏈接就緒時(shí)已經(jīng)被添加到 Pipeline 管道當(dāng)中,其實(shí),我們可以采用熱插拔的方式去把一些在做業(yè)務(wù)操作時(shí)用不到的 Handler 給剔除掉。

以上是基于Netty的IM系統(tǒng)開發(fā)當(dāng)中,需要去注意的技術(shù)優(yōu)化點(diǎn),當(dāng)然還有很多其他的細(xì)節(jié),比如:線程池這塊,需要大家慢慢去從實(shí)戰(zhàn)中積累。

5、本篇優(yōu)化方向

本篇主要的優(yōu)化內(nèi)容主要是在第二篇單聊功能和第三篇群聊功能的基礎(chǔ)上繼續(xù)完善幾點(diǎn)。

具體的優(yōu)化方向如下:

  • 1)無論客戶端還是服務(wù)端都分別只有一個(gè) Handler,這樣的話,業(yè)務(wù)越來越多,Handler 里面的代碼就會(huì)越來越臃腫,我們應(yīng)該想辦法把 Handler 拆分成各個(gè)獨(dú)立的 Handler;

  • 2)如果拆分的 Handler 很多,每次有連接進(jìn)來,那么都會(huì)觸發(fā) initChannel () 方法,所有的 Handler 都得被 new 一遍,我們應(yīng)該把這些 Handler 改成單例模式(不需要每次都 new,提高效率);

  • 3)發(fā)送消息時(shí),無論是單聊還是群聊,對(duì)方不在線,則把消息緩存起來,等待其上線再推送給他;

  • 4)連接斷開時(shí),無論是主動(dòng)和被動(dòng),需要?jiǎng)h除 Channel 屬性、刪除用戶和 Channel 映射關(guān)系。

6、業(yè)務(wù)拆分以及單例模式優(yōu)化

6.1 概述

主要優(yōu)化細(xì)節(jié)如下:

  • 1)自定義 Handler 繼承?SimpleChannelInboundHandler,那么解碼的時(shí)候,會(huì)自動(dòng)根據(jù)數(shù)據(jù)格式類型轉(zhuǎn)到相應(yīng)的 Handler 去處理;

  • 2)@Shareable?修飾 Handler,保證 Handler 是可共享的,避免每次都創(chuàng)建一個(gè)實(shí)例。

6.2 登錄Handler優(yōu)化

@ChannelHandler.Sharable

public class ClientLogin2Handler extends SimpleChannelInboundHandler<LoginResBean> {

????//1.構(gòu)造函數(shù)私有化,避免創(chuàng)建實(shí)體

????private ClientLogin2Handler(){}

????//2.定義一個(gè)靜態(tài)全局變量

????public static ClientLogin2Handler instance=null;

????//3.獲取實(shí)體方法

????public static ClientLogin2Handler getInstance(){

????????if(instance==null){

????????????synchronized(ClientLogin2Handler.class){

????????????????if(instance==null){

????????????????????instance=new ClientLogin2Handler();

????????????????}

????????????}

????????}

????????return instance;

????}

?

????protected void channelRead0(

????????ChannelHandlerContext channelHandlerContext,

????????LoginResBean loginResBean) throws Exception {

?

????????//具體業(yè)務(wù)代碼,參考之前

????}

}

6.3 消息發(fā)送Handler優(yōu)化

@ChannelHandler.Sharable

public class ClientMsgHandler extends SimpleChannelInboundHandler<MsgResBean> {

????//1.構(gòu)造函數(shù)私有化,避免創(chuàng)建實(shí)體

????private ClientMsgHandler(){}

????//2.定義一個(gè)靜態(tài)全局變量

????public static ClientMsgHandler instance=null;

????//3.獲取實(shí)體方法

????public static ClientMsgHandler getInstance(){

????????if(instance==null){

????????????synchronized(ClientMsgHandler.class){

????????????????if(instance==null){

????????????????????instance=new ClientMsgHandler();

????????????????}

????????????}

????????}

????????return instance;

????}

?

????protected void channelRead0(

????????ChannelHandlerContext channelHandlerContext,

????????MsgResBean msgResBean) throws Exception {

?

????????//具體業(yè)務(wù)代碼,參考之前

????}

}

6.4 initChannel方法優(yōu)化

.handler(newChannelInitializer<SocketChannel>() {

????@Override

????public void initChannel(SocketChannel ch) {

????????//1.拆包器

????????ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,5,4));

????????//2.解碼器

????????ch.pipeline().addLast(new MyDecoder());

????????//3.登錄Handler,使用單例獲取

????????ch.pipeline().addLast(ClientLogin2Handler.getInstance());

????????//4.消息發(fā)送Handler,使用單例獲取

????????ch.pipeline().addLast(ClientMsgHandler.getInstance());

????????//5.編碼器

????????ch.pipeline().addLast(new MyEncoder());

????}

});

6.5 小結(jié)

這種業(yè)務(wù)拆分以及單例模式優(yōu)優(yōu)化是Netty開發(fā)當(dāng)中很常用的,可以更好的維護(hù)基于Netty的代碼并提高應(yīng)用性能。

7、數(shù)據(jù)緩存優(yōu)化

為了提高用戶體驗(yàn),在發(fā)送消息(推送消息)時(shí),如果接收方不在線,則應(yīng)該把消息緩存起來,等對(duì)方上線時(shí),再推送給他。

7.1 數(shù)據(jù)緩存到集合

//1.定義一個(gè)集合存放數(shù)據(jù)(真實(shí)項(xiàng)目可以存放數(shù)據(jù)庫或者redis緩存),這樣數(shù)據(jù)比較安全。

private List<Map<Integer,String>> datas=new ArrayList<Map<Integer,String>>();

?

//2.服務(wù)端推送消息

private void pushMsg(MsgReqBean bean,Channel channel){

????Integer touserid=bean.getTouserid();

????Channel c=map.get(touserid);

?

????if(c==null){//對(duì)方不在線

????????//2.1存放到list集合

????????Map<Integer,String> data=new HashMap<Integer, String>();

????????data.put(touserid,bean.getMsg());

????????datas.add(data);

?

????????//2.2.給消息“發(fā)送人”響應(yīng)

????????MsgResBean res=new MsgResBean();

????????res.setStatus(1);

????????res.setMsg(touserid+">>>不在線");

????????channel.writeAndFlush(res);

?

????}else{//對(duì)方在線

????????//2.3.給消息“發(fā)送人”響應(yīng)

????????MsgResBean res=new MsgResBean();

????????res.setStatus(0);

????????res.setMsg("發(fā)送成功);

????????channel.writeAndFlush(res);

?

????????//2.4.給接收人推送消息

????????MsgRecBean res=new MsgRecBean();

????????res.setFromuserid(bean.getFromuserid());

????????res.setMsg(bean.getMsg());

????????c.writeAndFlush(res);

????}

}

7.2 上線推送

private void login(LoginReqBean bean, Channel channel){

????Channel c=map.get(bean.getUserid());

????LoginResBean res=new LoginResBean();

????if(c==null){

????????//1.添加到map

????????map.put(bean.getUserid(),channel);

????????//2.給通道賦值

????????channel.attr(AttributeKey.valueOf("userid")).set(bean.getUserid());

????????//3.登錄響應(yīng)

????????res.setStatus(0);

????????res.setMsg("登錄成功");

????????res.setUserid(bean.getUserid());

????????channel.writeAndFlush(res);

?

????????//4.根據(jù)user查找是否有尚未推送消息

????????//思路:根據(jù)userid去lists查找.......

?

????}else{

????????res.setStatus(1);

????????res.setMsg("該賬戶目前在線");

????????channel.writeAndFlush(res);

????}

}

8、連接斷開事件處理優(yōu)化

如果客戶端網(wǎng)絡(luò)故障導(dǎo)致連接斷開了(非主動(dòng)下線),那么服務(wù)端就應(yīng)該能監(jiān)聽到連接的斷開,且此時(shí)應(yīng)刪除對(duì)應(yīng)的 map 映射關(guān)系。但是映射關(guān)系如果沒有刪除掉,將導(dǎo)致服務(wù)器資源沒有得到釋放,進(jìn)而影響客戶端的下次同一個(gè)賬號(hào)登錄以及大量的客戶端掉線時(shí)性能。

8.1 正確寫法

實(shí)例:

public class ServerChatGroupHandler extends ChannelInboundHandlerAdapter {

????//映射關(guān)系

????private static Map<Integer, Channel> map=new HashMap<Integer, Channel>();

????//連接斷開,觸發(fā)該事件

????@Override

????public void channelInactive(ChannelHandlerContext ctx) throws Exception {

????????//1.獲取Channel

????????Channel channel=ctx.channel();

?

????????//2.從map里面,根據(jù)Channel找到對(duì)應(yīng)的userid

????????Integer userid=null;

????????for(Map.Entry<Integer, Channel> entry : map.entrySet()){

????????????Integer uid=entry.getKey();

????????????Channel c=entry.getValue();

????????????if(c==channel){

????????????????userid=uid;

????????????}

????????}

????????//3.如果userid不為空,則需要做以下處理

????????if(userid!=null){

????????????//3.1.刪除映射

????????????map.remove(userid);

????????????//3.2.移除標(biāo)識(shí)

????????????ctx.channel().attr(AttributeKey.valueOf("userid")).remove();

????????}

????}

}

8.2 錯(cuò)誤寫法

Channel 斷開,服務(wù)端監(jiān)聽到連接斷開事件,但是此時(shí) Channel 所綁定的屬性已經(jīng)被移除掉了,因此這里無法直接獲取的到 userid。

實(shí)例:

public class ServerChatGroupHandler extends ChannelInboundHandlerAdapter {

????//映射關(guān)系

????private static Map<Integer, Channel> map=new HashMap<Integer, Channel>();

?

????//連接斷開,觸發(fā)該事件

????@Override

????public void channelInactive(ChannelHandlerContext ctx) throws Exception {

????????//1.獲取Channel綁定的userid

????????Object userid=channel.attr(AttributeKey.valueOf("userid")).get();

?

????????//2.如果userid不為空

????????if(userid!=null){

????????????//1.刪除映射

????????????map.remove(userid);

????????????//2.移除標(biāo)識(shí)

????????????ctx.channel().attr(AttributeKey.valueOf("userid")).remove();

????????}

????}

}

9、本篇小結(jié)

本篇內(nèi)容還是相對(duì)容易理解的,主要是優(yōu)化前面兩篇實(shí)現(xiàn)的IM聊天功能,優(yōu)化內(nèi)容是業(yè)務(wù) Handler 的拆分以及使用單例模式、接受人不在線則緩存數(shù)據(jù)、等其上線再推送、監(jiān)聽連接斷開刪除對(duì)應(yīng)的映射關(guān)系。

限于篇幅,本系列文章文章沒辦法真正講解開發(fā)一個(gè)完整IM系統(tǒng)所涉及的方方面面,如果有興趣,可以繼續(xù)閱讀更有針對(duì)性的IM開發(fā)文章,比如IM架構(gòu)設(shè)計(jì)、IM通信協(xié)議、IM通信安全、群聊優(yōu)化、弱網(wǎng)優(yōu)化、網(wǎng)絡(luò)?;畹?。

10、參考資料

[1]?新手入門:目前為止最透徹的的Netty高性能原理和框架架構(gòu)解析

[2]?理論聯(lián)系實(shí)際:一套典型的IM通信協(xié)議設(shè)計(jì)詳解

[3]?淺談IM系統(tǒng)的架構(gòu)設(shè)計(jì)

[4]?簡(jiǎn)述移動(dòng)端IM開發(fā)的那些坑:架構(gòu)設(shè)計(jì)、通信協(xié)議和客戶端

[5]?一套海量在線用戶的移動(dòng)端IM架構(gòu)設(shè)計(jì)實(shí)踐分享(含詳細(xì)圖文)

[6]?一套原創(chuàng)分布式即時(shí)通訊(IM)系統(tǒng)理論架構(gòu)方案

[7]??一套高可用、易伸縮、高并發(fā)的IM群聊、單聊架構(gòu)方案設(shè)計(jì)實(shí)踐

[8]?一套億級(jí)用戶的IM架構(gòu)技術(shù)干貨(上篇):整體架構(gòu)、服務(wù)拆分等

[9]?從新手到專家:如何設(shè)計(jì)一套億級(jí)消息量的分布式IM系統(tǒng)

[10]?基于實(shí)踐:一套百萬消息量小規(guī)模IM系統(tǒng)技術(shù)要點(diǎn)總結(jié)

[11]?探探的IM長(zhǎng)連接技術(shù)實(shí)踐:技術(shù)選型、架構(gòu)設(shè)計(jì)、性能優(yōu)化

[12]?拿起鍵盤就是干,教你徒手開發(fā)一套分布式IM系統(tǒng)

[13]?萬字長(zhǎng)文,手把手教你用Netty打造IM聊天

[14]?基于Netty實(shí)現(xiàn)一套分布式IM系統(tǒng)

[15]?SpringBoot集成開源IM框架MobileIMSDK,實(shí)現(xiàn)即時(shí)通訊IM聊天功能

(本文同步發(fā)布于:http://www.52im.net/thread-3988-1-1.html)


基于Netty,從零開發(fā)IM(四):編碼實(shí)踐篇(系統(tǒng)優(yōu)化)的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
嘉鱼县| 乐昌市| 武邑县| 扶风县| 罗田县| 闽清县| 穆棱市| 延边| 加查县| 邻水| 京山县| 保德县| 武威市| 遂平县| 陵川县| 洱源县| 镇平县| 朝阳区| 台山市| 开江县| 华安县| 平利县| 阜阳市| 汉阴县| 开封县| 达孜县| 沈阳市| 宁明县| 澎湖县| 安庆市| 峨眉山市| 枣阳市| 尼勒克县| 苍南县| 和平县| 裕民县| 清徐县| 宿州市| 巴彦淖尔市| 绵阳市| 云龙县|