1、禁止缺省的threadmodel设置
mina2.0及以后版本已经没有threadmodel了,如果使用这些版本的话,可以跳过本节。
threadmodel设置是在mina1.0以后引入的,但是使用threadmodel增加了配置的复杂性,推荐禁止掉缺省的theadmodel配置。
ioacceptor acceptor = ...;
ioserviceconfig acceptorconfig = acceptor.getdefaultconfig();
acceptorconfig.setthreadmodel(threadmodel.manual);
注意在相关指南中,假定你已经如本节所说的禁止了threadmodel的缺省配置。
2、配置i/o工作线程的数量
这节只是nio实现相关的,nio数据包以及虚拟机管道等的实现没有这个配置。
在mina的nio实现中,有三种i/o工作线程:
>>acceptor线程 接受进入连接,并且转给i/o处理器线程来进行读写操作。每一个socketacceptor产生一个acceptor线程,线程的数目不能配置。
>>connector线程 尝试连接远程对等机,并且将成功的连接转给i/o处理器线程来进行读写操作。每一个socketconnector产生一个connector线程,这个的数目也不可以配置。
>>i/o处理器线程 执行实际上的读写操作直到连接关闭。每一个socketacceptor或socketconnector都产生它们自己的i/o处理线程。这个数目可以配置,缺省是1。
因此,对于每个ioservice,可以配置的就是i/o处理线程的数目。下面的代码产生一个有四个i/o处理线程的socketacceptor。
ioacceptor acceptor = new socketacceptor(4, executors.newcachedthreadpool());
没有单凭经验来决定i/o处理线程数目的方法,大概可以从1开始增加。
ioacceptor acceptor = new socketacceptor(runtime.getruntime().availableprocessors() + 1, executors.newcachedthreadpool());
3、增加一个executorfilter到iofilterchain中
executorfilter是一个iofilter,用于将进入的i/o事件转到一个 java.util.concurrent.executor实现。事件会从这个executor转到下一个iofilter,通常是一个线程池。可以在 iofilterchain的任何地方增加任意数目的executorfilter,实现任何类型的线程模型,从简单的线程池到复杂的seda。
到现在为止我们还没有增加executorfilter,如果没有增加executorfilter,事件会通过方法调用转到一个 iohandler,这意味着在iohandler实现中的业务逻辑会在i/o处理线程里运行。我们叫这种线程模型为"单线程模型"。单线程模型可以用来就会低反应网络应用程序,受cpu限制的业务逻辑(如,游戏服务器)。
典型的网络应用需要一个executorfilter插入到iofilterchain中,因为业务逻辑和i/o处理线程有不同的资源使用模式。如果你用iohandler的实现来执行数据库操作,而没有增加一个executorfilter的话,那么,你整个服务器会在执行数据库操作的时候锁定,特别是数据库性能低的时候。下面的例子配置一个ioservice在一个新的iosession建立时增加一个executorfilter。
ioacceptor acceptor = ...;
defaultiofilterchainbuilder filterchainbuilder = acceptor.getdefaultconfig().getfilterchain();
filterchainbuilder.addlast("threadpool", new executorfilter(executors.newcachedthreadpool());
这里要注意executorfilter没有管理特定的executor的生命周期,当完成时,需要关闭所有特定executor的工作线程。
executorservice executor = ...;
ioacceptor acceptor = ...;
defaultiofilterchainbuilder filterchainbuilder = acceptor.getdefaultconfig().getfilterchain();
filterchainbuilder.addlast("threadpool", new executorfilter(executor);
// start the server.
acceptor.bind(...);
// shut down the server.
acceptor.unbind(...);
executor.shutdown();
使用一个executorfilter通常不意味着要用一个线程池,对于executor的实现没有任何限制。
4、应该把executorfilter放在iofilterchain的什么地方
这个要根据于具体应用的情况来定。如果一个应用有一个protocolcodecfilter实现和一个常用的有数据库操作的iohandler实现的话,那么就建议在protocolcodecfilter实现的后面增加一个executorfilter,这是因为大部分的协议解码实现的性能特性是受cpu限制的,和i/o处理线程是一样的。
ioacceptor acceptor = ...;
defaultiofilterchainbuilder filterchainbuilder = acceptor.getdefaultconfig().getfilterchain();
// add cpu-bound job first,
filterchainbuilder.addlast("codec", new protocolcodecfactory(...));
// and then a thread pool.
filterchainbuilder.addlast("threadpool", new executorfilter(executors.newcachedthreadpool());
5、选择ioservice的线程池类型时要小心
executors.newcachedthreadpool()经常是ioservice首选的。因为如果使用其它类型的话,可能会对 ioservice产生不可预知的性能方面的影响。一旦池中的所有线程都在使用中,ioservice会在向池尝试请求一个线程时开始锁定,然后会出现一个奇怪的性能下降,这有时是很难跟踪的。
6、不推荐ioservices和executorfilters共享一个线程池
你可以想让ioservices和executorfilters共享一个线程池,而不是一家一个。这个是不禁止的,但是会出现很多问题,在这种情况下,除非你为ioservices建立一个缓冲线程池。
闽公网安备 35060202000074号