现状: 心跳是单向的,Server给client发送ping,后者回一个ping,完事。
现象: client经常收不到心跳,导致断线重连。
分析: p.addLast(new bizHandler()); 代码中是这样写的,没有指定executor,那么默认使用IO线程。 假设有8个IO线程,1万个channel,那么这1万个channel会分别绑定到某个IO线程上。 一个channel的所有读写操作,都由某个IO线程处理。
该IO线程持有一个无界队列,所有读写操作都会封装为一个TASK,放入该队列,由线程依次执行。 如果某个TASK很耗时,那么后面的TASK都要等待。 心跳包,是一个write操作,也会进入该队列,傻等……
解决办法: 需要将心跳包独立出来,使用独立的线程池。 新写一个inbound的Handler,实现超时处理方法,发心跳。
// 业务线程 static final EventExecutorGroup bizGroup = new DefaultEventExecutorGroup(Runtime.getRuntime().availableProcessors() * 2);
p.addLast(new 心跳Handler()); p.addLast(bizGroup,new bizHandler());
心跳Handler放前面,使用IO线程。 业务Handler放后面,使用业务线程。 哦了……
超时后,netty会往后找第一个inbound的Hander,调用其中的处理方法。 我看了两天源代码,才分析出来的。 ----------------------------------- 如果不用netty的线程池,使用JDK的线程池,那么要注意, 要在解包完毕后,得到完整消息后,再扔给线程池处理。 写消息时,也注意,要write完整的消息,否则可能会有并发写入的问题,导致消息数据错乱。
|