channelRead對於耗時業務邏輯處理的優化

channelRead對於耗時業務邏輯處理的優化

背景:之前在channelRead中,接收到遠端消息進行解碼後直接使用了操作數據庫這種耗時較久的業務邏輯處理。導致本地netty的工作線程阻塞,會降低可用線程數。另一個對於當前channel的心跳機制也有影響,會導致遠端機器長時間接受不到心跳信號,認爲這臺機器掛掉了。。。

原始代碼

       public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if(msg instanceof MessageEntity)
        {
            MessageEntity messageEntity = (MessageEntity) msg;
            if (2==messageEntity.getMsgType())
            {
                LOGGER.info("收到服務端發來的方法請求了--------------------------------------------");
                // 轉換爲MethodInvokeMeta
                MethodInvokeMeta invokeMeta = (MethodInvokeMeta) ((MessageEntity) msg).getData();
                LOGGER.info("{} -> [客戶端信息] \n 方法名  - > {} \n 參數列表  -> {} \n " +
                                "返回值  ->  {} ", this.getClass().getName(), invokeMeta.getMethodName(), invokeMeta.getArgs()
                        , invokeMeta.getReturnType());
                // 具體的處理類
                RequestDispatcher requestDispatcher = new RequestDispatcher();
                requestDispatcher.dispatcher(ctx, invokeMeta);
            }
            else
            {
                LOGGER.error("接受到的服務端請求無法識別");
            }
        }else
        {
            LOGGER.error("接受到的服務端請求無法識別");
        }
    }

在channelRead中,dispatch是一個接受到遠程調用請求的分發器,會根據調用參數執行本地具體的方法。其中大多數都包括耗時較久的數據庫操作,因此這塊代碼亟需優化。

    requestDispatcher.dispatcher(ctx, invokeMeta); 

解決方案

啥都不說,先上代碼,如下:

    ExecutorService executor = Executors.newFixedThreadPool(2);

    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //引入異步業務線程池的方式,避免長時間業務耗時業務阻塞netty本身的worker工作線程
        executor.submit(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                if(msg instanceof MessageEntity)
                {
                    MessageEntity messageEntity = (MessageEntity) msg;
                    if (2==messageEntity.getMsgType())
                    {
                        LOGGER.info("收到服務端發來的方法請求了--------------------------------------------");
                        // 轉換爲MethodInvokeMeta
                        MethodInvokeMeta invokeMeta = (MethodInvokeMeta) ((MessageEntity) msg).getData();
                        LOGGER.info("{} -> [客戶端信息] \n 方法名  - > {} \n 參數列表  -> {} \n " +
                                        "返回值  ->  {} ", this.getClass().getName(), invokeMeta.getMethodName(), invokeMeta.getArgs()
                                , invokeMeta.getReturnType());
                        // 具體的處理類
                        RequestDispatcher requestDispatcher = new RequestDispatcher();
                        requestDispatcher.dispatcher(ctx, invokeMeta);
                    }
                    else
                    {
                        LOGGER.error("接受到的服務端請求無法識別");
                    }
                }else
                {
                    LOGGER.error("接受到的服務端請求無法識別");
                }
                return null;
            }
        });
    }

通過自己添加業務線程池的方式,避免阻塞worker工作線程(因爲讀完數據後,ChannelPipeline會觸發 ChannelHandler鏈來處理業務邏輯,而ChannelHandler鏈的整個過程是是同步的)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章