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鏈的整個過程是是同步的)