netty 业务线程池处理方式应该怎么选择

上文《Netty框架入门》说到:如果业务处理handler耗时长,将严重影响可支持的并发数。
针对这一问题,经过学习,发现了可以使用ExecutionHandler来优化。
先来回顾一下没有使用ExecutionHandler优化的流程:
& & 1)Boss线程(接收到客户端连接)-&生成Channel-&交给Worker线程池处理。
& & 2)某个被分配到任务的Worker线程-&读完已接收的数据到ChannelBuffer-&触发ChannelPipeline中的ChannelHandler链来处理业务逻辑。
& & 注意:执行ChannelHandler链的整个过程是同步的,如果业务逻辑的耗时较长,会将导致Work线程长时间被占用得不到释放,从而影响了整个服务器的并发处理能力。
一、引入ExecutionHandler优化
//HttpServerPipelineFactory.java
private final ExecutionHandler executionHandler = new ExecutionHandler(
new OrderedMemoryAwareThreadPoolExecutor(16, 48576));
public class HttpServerPipelineFactory implements ChannelPipelineFactory {
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast("execution", executionHandler);
pipeline.addLast("handler", new HttpServerHandler());
&&&&当我们引入ExecutionHandler后,原本同步的ChannelHandler链在经过 ExecutionHandler后就结束了,它会被ChannelFactory的worker线程池所回收,而剩下的ChannelHandler链将由ExecutionHandler的线程池接手处理。
& &&对于ExecutionHandler需要的线程池模型,Netty提供了两种可选:
&&&&&&&&1) MemoryAwareThreadPoolExecutor 通过对线程池内存的使用控制,可控制Executor中待处理任务的上限(超过上限时,后续进来的任务将被阻塞),并可控制单个Channel待处理任务的上限,防止内存溢出错误。但是它不维持同一Channel的ChannelEvents秩序,当经过ExecutionHandler后的ChannelHandler链中有不止一个Handler时,这些事件驱动存在混乱的可能。例如:
----------------------------------------& Timeline -------------------------------------&
Thread X: --- Channel A (Event 2) --- Channel A (Event 1) -----------------------------&
Thread Y: --- Channel A (Event 3) --- Channel B (Event 2) --- Channel B (Event 3) ---&
Thread Z: --- Channel B (Event 1) --- Channel B (Event 4) --- Channel A (Event 4) ---&
&&&&&&&&2) OrderedMemoryAwareThreadPoolExecutor 是 MemoryAwareThreadPoolExecutor 的子类。除了MemoryAwareThreadPoolExecutor 的功能之外,它还可以保证同一Channel中处理的事件流的顺序性(不同Channel使用不同的key保持事件顺序),这主要是控制事件在异步处理模式下可能出现的错误事件顺序,但它并不保证同一 Channel中的事件都在一个线程中执行(通常也没必要)。例如:
& & & & & &
----------------------------------------& Timeline ----------------------------------------&
Thread X: --- Channel A (Event 1) --.
.-- Channel B (Event 2) --- Channel B (Event 3) ---&
Thread Y: --- Channel B (Event 1) --'
'-- Channel A (Event 2) --- Channel A (Event 3) ---&
二、具有可伸缩性的OrderedMemoryAwareThreadPoolExecutor使用策略
&&&&在大多数情况下,我们会使用OrderedMemoryAwareThreadPoolExecutor,它的构造函数要求我们提供线程池的大小,在上面的代码中,我们使用了16这个具体的值,是一种很不好的写法,通常情况下,我们会使用配置文件使之可变,但是在实际部署时,并不能保证实施人员能很好的去调整,故提供如下的一种写法:
double coefficient = 0.8;
int numberOfCores = Runtime.getRuntime().availableProcessors();
int poolSize = (int)(numberOfCores / (1 - coefficient));
我们可以使用poolSize取代OrderedMemoryAwareThreadPoolExecutor(16, 48576)中的那个16,因为当一个系统被开发出来后,它是CPU密集型还是IO密集型是可评估的,通过评估其密集型,调整系数即可:CPU密集型接近0,IO密集型接近1。
阅读(...) 评论()netty 业务线程处理方式应该怎么选择? - 知乎4被浏览318分享邀请回答1添加评论分享收藏感谢收起多线程并发编程在Netty中的应用分析_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
多线程并发编程在Netty中的应用分析
阅读已结束,下载文档到电脑
想免费下载更多文档?
定制HR最喜欢的简历
下载文档到电脑,方便使用
还剩18页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢

我要回帖

更多关于 netty io线程处理业务 的文章

 

随机推荐