最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Netty的心跳檢測解析

 更新時間:2023年12月13日 09:27:56   作者:得過且過的勇者y  
這篇文章主要介紹了Netty的心跳檢測解析,客戶端的心跳檢測對于任何長連接的應(yīng)用來說,都是一個非?;A(chǔ)的功能,要理解心跳的重要性,首先需要從網(wǎng)絡(luò)連接假死的現(xiàn)象說起,需要的朋友可以參考下

一、網(wǎng)絡(luò)連接假死現(xiàn)象

客戶端的心跳檢測對于任何長連接的應(yīng)用來說,都是一個非?;A(chǔ)的功能。

要理解心跳的重要性,首先需要從網(wǎng)絡(luò)連接假死的現(xiàn)象說起。

什么是連接假死呢?如果底層的TCP連接已經(jīng)斷開,但是服務(wù)器端并沒有正常地關(guān)閉套接字,認(rèn)為這條連接仍然是存在的。

連接假死的具體表現(xiàn)如下:

  1. 在服務(wù)器端,會有一些處于TCP_ESTABLISHED狀態(tài)的正常連接
  2. 在客戶端,TCP客戶端已經(jīng)顯示連接已經(jīng)斷開
  3. 客戶端此時雖然可以進(jìn)行斷線重連操作,但是上一次連接狀態(tài)依然被服務(wù)器端認(rèn)為有效,并且服務(wù)器端的資源得不到正確釋放,包括套接字上下文以及接受/發(fā)送緩沖區(qū)

連接假死的情況雖然不常見,但是確實存在。服務(wù)器端長時間運行后,會面臨大量假死連接得不到釋放的情況。由于每個連接都會消耗CPU和內(nèi)存資源,因此大量假死的連接會逐漸耗光服務(wù)器的資源,使得服務(wù)器越來越慢,IO處理效率越來越低,最終導(dǎo)致服務(wù)器崩潰。

連接假死通常是由多個原因造成的:

  • 應(yīng)用程序出現(xiàn)線程堵塞,無法進(jìn)行連接的讀寫
  • 網(wǎng)絡(luò)相關(guān)的設(shè)別出現(xiàn)故障
  • 網(wǎng)絡(luò)丟包

解決假死的有效手段是客戶端定時進(jìn)行心跳檢測,服務(wù)端定時進(jìn)行空閑檢測。

二、服務(wù)器端的空閑檢測

想解決假死問題,服務(wù)器端的有效手段是空閑檢測。所謂空閑檢測就是每隔一段時間監(jiān)測子通道是否有數(shù)據(jù)讀寫,如果有則子通道是正常的,如果沒有則判定為假死,關(guān)閉子通道。

服務(wù)器端實現(xiàn)空閑檢測只需要使用Netty自帶的IdleStateHandler空閑狀態(tài)處理器就可以實現(xiàn)這個功能。

@Slf4j
public class HeartBeatServerHandler extends IdleStateHandler {
    private static final int READ_IDLE_GAP = 150; // 最大空閑時間(s)
    public HeartBeatServerHandler() {
        super(READ_IDLE_GAP, 0, 0, TimeUnit.SECONDS);
    }
    @Override
    protected void channelIdle(ChannelHandlerContext ctx, IdleStateEvent evt) throws Exception {
        log.info("{}秒內(nèi)未讀到數(shù)據(jù),關(guān)閉連接", READ_IDLE_GAP);
        // 其他處理,如關(guān)閉會話
    }
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // 判斷消息實例
        if (!(msg instanceof MessageProtos.Message message)) {
            super.channelRead(ctx, msg);
            return;
        }
        if (message.getType() == MessageProtos.HeadType.HEART_BEAT) {
            if (ctx.channel().isActive()) {
                // 將心跳數(shù)據(jù)包直接回給客戶端
                ctx.writeAndFlush(msg);
            }
        }
        super.channelRead(ctx, msg);
    }
}

在HeartBeatServerHandler的構(gòu)造函數(shù)中,調(diào)用了基類IdleStateHandler的構(gòu)造函數(shù),傳遞了四個參數(shù):

  • 入站空閑檢測時長:指的是一段時間內(nèi)如果沒有消息入站就判定為連接假死
  • 出站空閑檢測時長:指的是一段時間內(nèi)如果沒有數(shù)據(jù)出站就判定為連接假死
  • 出/入站檢測時長:表示在一段時間內(nèi)如果沒有出站或者入站就判定為連接假死
  • 時間單位

判定為假死之后IdleStateHandler會回調(diào)自己的channelIdle()方法,一般在這個方法中去進(jìn)行一些連接的關(guān)閉。

HeartBeatServerHandler實現(xiàn)的主要功能是空閑檢測,需要客戶端定時發(fā)送心跳數(shù)據(jù)包(或報文、消息)進(jìn)行配合,而且客戶端發(fā)送心跳數(shù)據(jù)包的時間間隔需要遠(yuǎn)遠(yuǎn)小于服務(wù)器端的空閑檢測時間間隔。

收到客戶端的心跳數(shù)據(jù)包之后可以直接回復(fù)客戶端,讓客戶端也能進(jìn)行類似的空閑檢測。由于IdleStateHandler本身是一個入站處理器,只需要重寫這個子類的channelRead方法,然后將心跳數(shù)據(jù)包直接寫回給客戶端即可。

如果HeartBeatServerHandler要重寫channelRead方法,一定要調(diào)用積累的channelRead方法,不然IdleStateHandler的入站空閑檢測會無效。

三、客戶端的心跳報文

與服務(wù)器端的空閑檢測相配合,客戶端需要定期發(fā)送數(shù)據(jù)包到服務(wù)器端,通常這個數(shù)據(jù)包稱為心跳數(shù)據(jù)包。

@Slf4j
public class HeartBeatClientHandler extends ChannelInboundHandlerAdapter {
    // 心跳的時間間隔,單位為秒
    private static final int HEART_BEAT_INTERVAL = 50;
    // 在Handler業(yè)務(wù)處理器被加入到流水線時開始發(fā)送心跳數(shù)據(jù)包
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        ClientSession session = ctx.channel().attr(ClientSession.CLIENT_SESSION).get();
        MessageProtos.MessageHeartBeat heartBeat =
                MessageProtos.MessageHeartBeat.newBuilder()
                        .setSeq(0)
                        .setJson("{\"from\":\"client\"}")
                        .setUid(session.getUserDTO().getUserId())
                        .build();
        MessageProtos.Message message = MessageProtos.Message.newBuilder()
                .setType(MessageProtos.HeadType.HEART_BEAT)
                .setSessionId(session.getSessionId())
                .setMessageHeartBeat(heartBeat)
                .build();
        heartBeat(ctx, message);
        super.handlerAdded(ctx);
    }
    private void heartBeat(ChannelHandlerContext ctx, MessageProtos.Message message) {
        // 提交在給定延遲后啟用的一次性任務(wù)。
        ctx.executor().schedule(() -> {
            if (ctx.channel().isActive()) {
                log.info("發(fā)送心跳消息給服務(wù)端");
                ctx.writeAndFlush(message);
                // 遞歸調(diào)用,發(fā)送下一次的心跳
                heartBeat(ctx, message);
            }
        }, HEART_BEAT_INTERVAL, TimeUnit.SECONDS);
    }
    // 接收到服務(wù)器的心跳回寫
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (!(msg instanceof MessageProtos.Message message)) {
            super.channelRead(ctx, msg);
            return;
        }
        if (message.getType() == MessageProtos.HeadType.HEART_BEAT) {
            log.info("收到會寫的心跳信息");
        } else {
            super.channelRead(ctx, msg);
        } 
    }
}

在HeartBeatClientHandler實例被加入到流水線時,它重寫的handlerAdded方法被回調(diào)。在handlerAdded方法中開始調(diào)用heartBeat方法發(fā)送心跳數(shù)據(jù)包。heartBeat是一個不斷遞歸調(diào)用的方法,它使用了ctx.executor()獲取當(dāng)前通道綁定的Reactor反應(yīng)器NIO線,然后通過NIO現(xiàn)線程的schedule定時調(diào)度方法,在50s后觸發(fā)這個方法的執(zhí)行,再之后遞歸調(diào)用同樣延時50s后繼續(xù)發(fā)送。

客戶端的心跳間隔要比服務(wù)器端的空閑檢測時間間隔要短,一般來說要比它的一半要短一些,可以直接定義為空閑檢測時間間隔的1/3,以防止公網(wǎng)偶發(fā)的秒級抖動。

HeartBeatClientHandler實例并不是一開始就裝配到流水線中的,它裝配的實際實在登錄成功之后。

HeartBeatClientHandler實際上也可以集成IdleStateHandler類在客戶端進(jìn)行空閑檢測,這樣客戶端也可以對服務(wù)器進(jìn)行假死判定,在服務(wù)器假死的情況下,客戶端可以發(fā)起重連。

相關(guān)文章

  • JSON序列化Redis讀取出錯問題解決方案

    JSON序列化Redis讀取出錯問題解決方案

    這篇文章主要介紹了JSON序列化Redis讀取出錯問題解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-09-09
  • 基于Nacos實現(xiàn)動態(tài)線程池的設(shè)計與實踐分享

    基于Nacos實現(xiàn)動態(tài)線程池的設(shè)計與實踐分享

    在分布式系統(tǒng)架構(gòu)中,線程池是資源調(diào)度的重要工具,傳統(tǒng)固定參數(shù)的線程池在流量平穩(wěn)的場景下表現(xiàn)良好,但面對現(xiàn)代互聯(lián)網(wǎng)業(yè)務(wù)的潮汐流量特征時,往往會出現(xiàn)資源浪費或處理能力不足的問題,所以本文將介紹基于Nacos實現(xiàn)動態(tài)線程池的設(shè)計與實踐,需要的朋友可以參考下
    2025-05-05
  • 關(guān)于JDK源碼中的@author unascribed注釋閑談

    關(guān)于JDK源碼中的@author unascribed注釋閑談

    這篇文章主要介紹了關(guān)于JDK源碼中的@author unascribed注釋閑談,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • javascript最新2020經(jīng)典面試題

    javascript最新2020經(jīng)典面試題

    這篇文章主要介紹了javascript最新2020經(jīng)典面試題的相關(guān)內(nèi)容,有需要的朋友們可以學(xué)習(xí)下。
    2020-02-02
  • 從零構(gòu)建可視化jar包部署平臺JarManage教程

    從零構(gòu)建可視化jar包部署平臺JarManage教程

    這篇文章主要為大家介紹了從零構(gòu)建可視化jar包部署平臺JarManage教程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • Java中多線程Reactor模式的實現(xiàn)

    Java中多線程Reactor模式的實現(xiàn)

    多線程Reactor模式旨在分配多個reactor每一個reactor獨立擁有一個selector,本文就詳細(xì)的來介紹一下Java中多線程Reactor模式的實現(xiàn),需要的朋友可以參考下
    2021-12-12
  • JAVA動態(tài)代理模式(從現(xiàn)實生活角度理解代碼原理)

    JAVA動態(tài)代理模式(從現(xiàn)實生活角度理解代碼原理)

    本文主要介紹了JAVA動態(tài)代理模式(從現(xiàn)實生活角度理解代碼原理)的相關(guān)知識。具有很好的參考價值。下面跟著小編一起來看下吧
    2017-03-03
  • 基于JavaMail API收發(fā)郵件的方法

    基于JavaMail API收發(fā)郵件的方法

    這篇文章主要介紹了基于JavaMail API收發(fā)郵件的方法,實例分析了javamail的使用方法與相關(guān)注意事項,非常具有實用價值,需要的朋友可以參考下
    2015-07-07
  • MyBatis Flex全解析

    MyBatis Flex全解析

    MyBatis-Flex是一個輕量高效的MyBatis增強框架,具有極高性能和靈活性,MyBatis-Flex 能夠極大地提高我們的開發(fā)效率和開發(fā)體驗,讓我們有更多的時間專注于自己的事情,本文給大家介紹MyBatis Flex全解析,感興趣的朋友跟隨小編一起看看吧
    2025-12-12
  • SpringBoot對敏感數(shù)據(jù)進(jìn)行脫敏的全過程

    SpringBoot對敏感數(shù)據(jù)進(jìn)行脫敏的全過程

    在項目開發(fā)中,數(shù)據(jù)庫經(jīng)常會存儲大量用戶敏感信息,例如手機號、身份證號、郵箱、銀行卡號、家庭地址、姓名等數(shù)據(jù),如果后端直接把原始數(shù)據(jù)返回給前端,會造成嚴(yán)重的用戶隱私泄露問題,所以本文給大家介紹了SpringBoot對敏感數(shù)據(jù)進(jìn)行脫敏的全過程,需要的朋友可以參考下
    2026-04-04

最新評論

翼城县| 喀什市| 陵水| 宁海县| 新沂市| 四子王旗| 承德市| 杂多县| 永川市| 丁青县| 郸城县| 永城市| 女性| 威远县| 鹤岗市| 噶尔县| 佛山市| 尉氏县| 宁海县| 普定县| 临邑县| 瑞金市| 九龙城区| 南乐县| 阿拉善左旗| 卓资县| 晋江市| 九龙坡区| 汾阳市| 铜山县| 台州市| 云梦县| 赫章县| 福泉市| 清苑县| 天台县| 灌云县| 南汇区| 黎川县| 修水县| 郯城县|