My favorites | Sign in
Project Logo
                
Search
for
Updated Oct 09, 2009 by killme2008
Labels: Phase-Support, Performance
Performance  

TCP选项

Yanf4j的性能调优分为两部分,一个是socket选项方面的设置,一个框架本身的配置。首先,以设置Socket选项为例,yanf4j 1.0开始引入了SocketOption类用于Socket选项的设置,这个类与jdk7即将引入的同名类的使用方法是类似的,例如,设置TCP_NODELAY为true来禁止Nagle算法可以这样做:

  TCPController controller=...
  controller.setSocketOption(StandardSocketOption.TCP_NODELAY, true);

更多选项如SO_RCVBUF、SO_KEEPALIVE、SO_LINGER、SO_SNDBUF等选项请参见com.google.code.yanf4j.core.impl.StandardSocketOption类的文档说明。请注意,部分选项如SO_RCVBUF需要在Controller绑定到IP地址之前设置才有效,如果你无法确认哪些选项需要在绑定之前设置,那么我们统一推荐您在调用bind或者start方法之前做Socket选项设置。

至于TCP选项的选择,请参考网络编程书籍以及您的具体应用环境来做选择,性能攸关的几个选项是用于设置socket缓冲区的SO_RCVBUF、SO_SNDBUF;用于禁止Nagle算法的TCP_NODELAY;用于允许重复端口绑定的SO_REUSEADDR;用于控制关闭行为的SO_LINGER选项等等。关于SO_LINGER选项,你除了设置SO_LINGER的数值大小之外,你还需要设置是否开启,这可以通过:

  TCPController controller=...
  controller.setSoLinger(true, 0);

来设置。

框架配置

除了常见的Socket选项之外,Yanf4j另一个性能的关键点在于框架本身的配置,如线程模型、线程池大小、是否启用统计、是否启用流量控制、是否设置连接过期或者idle超时、读的缓冲区大小、是否允许读写并行等等。下面将做一个大概阐述。

框架这些选项的设置都是通过 com.google.code.yanf4j.config.Configuration类,在构造Controller的时候你可以传入一个Configuration对象作为配置对象,如果没有,将采用默认配置:

  Configuration configuration = new Configuration();
  //开启统计
  configuration.setStatisticsServer(true);
  //设置读线程数
  configuration.setReadThreadCount(1);
  TCPController controller = new TCPController(configuration);

线程模型

Yanf4j用到了4个线程池:读线程池、写线程池、消息派发线程池、Reactor池。 其中读线程池用于处理可读事件,当某个连接可读的时候,将提交给这个线程池来处理,默认读线程池大小为1,也就是有一个单独的线程处理所有连接的Read请求。这个参数可以通过

  configuration.setReadThreadCount(1);

修改。

写线程池用于处理可写事件,用于向Socket写入消息,默认情况下是0个线程,也就是说写socket的操作跟Reactor产生可写事件并派发此事件的线程是同一个(也就是select线程)。通常来说这个数值不需要太大,可以通过

  configuration.setWriteThreadCount(0);

设置。

消息派发线程池,是指当读到的数据被decode出来之后成为一个用户级别的消息的时候,派发给用户处理器的onMessageReceived方法的时候提交一个线程池处理,此线程池其实是应用处理线程池,通常来说需要根据你应用的类型来设置这个参数大小,如果你的应用是CPU密集型通常设置为cpus+1个线程,如果是IO密集型就根据测试情况进行调整,调整方式如下:

  configuration.setDispatchMessageThreadCount(3);

Reactor池是指Reactor的池大小,Yanf4j 1.0开始open多个Selector来处理事件注册、触发和派发,缓解高负载下单Selector的过大压力。一个Reactor管理一个Selector,当一个新的连接建立时将被绑定到某个Reactor上,Reactor池默认大小通过一个公式计算,如果cpus为CPU个数的话,那么Reactor池大小为:

  cpus > 8 ? 4 + cpus * 5 / 8 : cpus + 1

通常来说不建议用户修改此值,如果你确实要修改的话,可以通过

   NioController controller=...
   controller.setSelectorPoolSize(10);

来修改。

关于线程池大小的设置,需要根据你的应用类型来做选择,通用的原则是如果你的业务处理层面非常迅速,也就是onMessageReceived方法回调非常快,那么通常建议将readThreadCount和dispatchMessageThreadCount都设置为0来减少线程切换的开销;如果你的业务处理非常慢,或者很耗费CPU,那么通常建议将readThreadCount或者dispatchMessageThreadCount设置得相对大一些。当然,一切以你的测试结果为准。

待续。。。


Sign in to add a comment
Powered by Google Project Hosting