Netty高性能编程备忘录(上)

标签: tuicool | 发表时间:2016-08-14 00:00 | 作者:
出处:http://itindex.net/admin/pagedetail

网上赞扬Netty高性能的文章不要太多,但如何利用Netty写出高性能网络应用的文章却甚少,此文权当抛砖引玉。

估计此文很快就要被拍砖然后修改,因此转载请保持原文链接:

http://calvin1978.blogcn.com/articles/netty-performance.html,否则视为侵权。。。

参考资料:

1. 连接篇

1.1 Netty Native

Netty Native是由Twitter将Tomcat Native的移植过来,用C++编写JNI调用的Socket Transport。

经测试,Netty Native的确比JDK NIO更省CPU。

也许有人问,JDK的NIO也用EPOLL啊,大家有什么不同? Norman Maurer这么说的:

* Netty的 epoll transport使用 epoll edge-triggered 而 java的 nio 使用 level-triggered.

* C++的代码,更少GC,更少synchronized。

* netty的epoll transport 暴露了更多的配置参数。

第一条没看懂,反正测试结果的确更快省更CPU。

用法倒是简单,只要把NioEventLoopGrouph等几个类改名成EpollEventLoopGroup之类即可,详见Netty的 官方文档1文档2

但要注意,首先它跟OS相关,而且基于GLIBC2.10编译,而CentOS 5.8就只有GLIBC2.5(别问为什么,厂大怪事多,我厂就是还有些CentOS5.8的机器),所以最好还是不要狠狠的直接全文搜索替换,而是用System.getProperty(“os.name”) 和 System.getProperty(“os.version”) 取出操作系统名称与版本,做成一个开关。

另外,Netty很多版本都有修复Netty Native相关的bug,看得人心里发毛,好在最近的版本终于不再说了,所以要用就用Netty的新版。

最后,Netty Native还包含了Google的boringssl(A fork of OpenSSL),JDK的原生SSL实现比较慢而且GC甚多,而大家把SSL Provider配置成OpenSSL时,又要担心操作系统有没装OpenSSL,或者版本会不会太旧。现在好了。

1.2 异步连接,异步传输,告别Commons Pool

使用NIO最牛头不对马嘴的事情就是,给它配一个类似Commons Pool这样,有借有还的连接池。

因为NIO的本质就是轮询事件,不阻塞不独占,所以无论做什么事情,根本不需要独占一条连接,不需要把它借出去,再还回池里。Netty现在也有个ChannelPool了,不过我还是不知道有什么用。一来连接池出入之间有锁,二来并发请求一多就要无厘头的狂建连接,到连接池上限时还要白白等待别人释放连接,而这在NIO的世界里其实毫无必要。

所以,建议直接建一个连接数组,随机到哪个连接就用哪个连接发数据。如果数组里的某个连接还没建立或者已经失效,那就重新建立连接。

顺便说一句,异步的世界里,连建立连接的过程也是异步的,主线程不要等在建连接上,而是把发送的动作封成一个ChannelCallback,等连接建立了,再回调它发送数据,避免因为连接建立的缓慢或网络根本不通,把线程都堵塞了。

1.3 最佳连接数:一条连接打天下?还有传说中的海量连接?

NIO这么神奇,有一种做法是只建一条连接,如Memcached的客户端SpyMemcached。还有一种是既然你能支持海量连接,几千几万的,那我就无节制的可劲的建了。

测试表明,一条连接有瓶颈,毕竟只用到了一个CPU核。 海量连接,CPU和内存在燃烧。。。。

那最佳连接数是传说中的CPU核数么?依然不是。

一切还是看你的场景,连接数在满足传输吞吐量的情况下,越少越好。

举个例子,在我的Proxy测试场景里:

  • 2条连接时,只能有40k QPS。
  • 48条连接,升到62k QPS,CPU烧了28%
  • 4条连接,QPS反而上升到68k ,而且CPU降到20%。

1.4 Channel参数设定

1.4.1 TCP/Socket参数

TCP/Socket的大路设置,无非 SO_REUSEADDR, TCP_NODELAY, SO_KEEPALIVE 。

另外还有SO_LINGER , SO_TIMEOUT, SO_BACKLOG, SO_SNDBUF, SO_RCVBUF ,建议缓冲区大小不要显式设定覆盖内核参数里设定的动态适配。

而用了Native后还有其他的配置,比如TCP_CORK和KeepAlive包发送的时间间隔(默认2小时),在Java的标准Socket里居然只能设是否KeepAlive而KeepAlive的其他参数要通过内核参数设定,比较奇葩,详见 EpoolSocketChannelConfig的JavaDoc

所有这些参数的含义,不一一描述了,自己搜索,比如 Linux下高性能网络编程中的几个TCP/IP选项

1.4.2 Netty参数

CONNECT_TIMEOUT_MILLIS,Netty自己起一个定时任务来监控建立连接是否超时,默认30秒太长谁也受不了,一般会弄短它。

WRITE_BUFFER_HIGH_WATER_MARK 与 WRITE_BUFFER_LOW_WATER_MARK是两个流控的参数,默认值分别为32*2K与32K.。如果在writer buffet里排队准备输出的字节超过上限,Channel就不是writable的,NIO的事件轮询里就会把它摘掉,直到它低于32k才重新变回writable。建议没有足够的测试不要动它。

2. 线程篇

2.1 WorkerGroup 与 Boss Group

大家都知道,Boss Group用于服务端处理建立连接的请求,WorkGroup用于处理I/O。

EventLoopGroup的默认大小都是是2倍的CPU核数,但这并不是一个恒定的最佳数量,为了避免线程上下文切换,只要能满足要求,这个值其实越少越好,比如WorkerGroup我的场景里就只设了max(2, 核数1/2),核数再少也得有两条,否则就是核数一半。

至于Boss Group,如果都是长连接,它要做的事情也不多。幸亏它只有忙起来才会多起线程,平时就只占1条,所以我设了类似的核数/4。

在服务化的应用里,一般处理上游请求的同时,也会向多个下游的服务集群发送请求,就会有多个BootStrap,但调优指南里都说,尽量,全部收发重用同一个EventLoopGroup。还是那句,减少线程总数,除非你有特别的,隔离的需求。

同时,多个Channel可能会对应一个EventLoop线程,但对于一个Channel来说只能对应一个EventLoop线程。也就是在同一个请求里上下游的不同Channel的处理还是很可能会切换到不同的线程里。

2.2 业务线程池

Netty线程的数量一般固定且较少,所以很怕线程被堵塞,比如同步的数据库查询,比如下游的服务调用(又来罗嗦,future.get()式的异步在执行future.get()时还是堵住当前线程的啊)。

所以,此时就要把处理放到一个业务线程池里操作,即使要付出线程上下文切换的代价,甚至还有些ThreadLocal需要复制。

2.3 定时任务

像发送超时控制之类的任务,不要使用JDK自己的ScheduledExecutorService,而是使用如下语句:

ctx.executor().schedule(new WriteTimeoutTask(p), 30, TimeUnit.SECONDS)

首先,JDK的ScheduledExecutorService是一个大池子,多线程争抢并发锁。而上面的写法,TimeoutTask只属于当前的EventLoop,没有任何锁。

其次,如果发送成功,需要从长长Queue里找回任务来取消掉它。现在每个EventLoop一条Queue,明显长度只有原来的N分之一。

文章太长没人看,写到这里就停笔了。未完待续。下篇会继续写,内存篇,工具类篇,使用方法篇

另外,不来唯品会的基础架构部的话,我可能永远不会写这种文章,本文也有来自其他同事的经验总结,简历请发 calvin.xiao@vipshop.com

有个叫“我是猫”的同学离职有一阵了,有点想念他,配图一幅。

相关 [netty 性能 编程] 推荐:

Netty高性能编程备忘录(上)

- - IT瘾-tuicool
网上赞扬Netty高性能的文章不要太多,但如何利用Netty写出高性能网络应用的文章却甚少,此文权当抛砖引玉. 估计此文很快就要被拍砖然后修改,因此转载请保持原文链接:. http://calvin1978.blogcn.com/articles/netty-performance.html,否则视为侵权.

Netty系列之Netty高性能之道

- - CSDN博客推荐文章
最近一个圈内朋友通过私信告诉我,通过使用Netty4 + Thrift压缩二进制编解码技术,他们实现了10W TPS(1K的复杂POJO对象)的跨节点远程服务调用. 相比于传统基于Java序列化+BIO(同步阻塞IO)的通信框架,性能提升了8倍多. 事实上,我对这个数据并不感到惊讶,根据我5年多的NIO编程经验,通过选择合适的NIO框架,加上高性能的压缩二进制编解码技术,精心的设计Reactor线程模型,达到上述性能指标是完全有可能的.

Netty SSL性能调优

- - ImportNew
嗯,这篇不长的文章,是一个晚上工作到三点的血泪加班史总结而成. 《 TLS协议分析 与 现代加密通信协议设计》 首先要感谢这篇文章,如果没有它,我可能还要花更多的时间才能完成. 文章有点长,能看多少是多少,每句都是收获. 目前(2015年)已经不安全,必须禁用. 互联网标准化组织ISOC接替NetScape公司,发布了SSL的升级版TLS 1.0版.

用Netty开发中间件:高并发性能优化

- - CSDN博客推荐文章
用Netty开发中间件:高并发性能优化. 最近在写一个后台中间件的原型,主要是做消息的分发和透传. 因为要用Java实现,所以网络通信框架的第一选择当然就是Netty了,使用的是Netty 4版本. Netty果然效率很高,不用做太多努力就能达到一个比较高的tps. 但使用过程中也碰到了一些问题,个人觉得都是比较经典而在网上又不太容易查找到相关资料的问题,所以在此总结一下.

Netty代码分析

- LightingMan - 淘宝JAVA中间件团队博客
Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序[官方定义],整体来看其包含了以下内容:1.提供了丰富的协议编解码支持,2.实现自有的buffer系统,减少复制所带来的消耗,3.整套channel的实现,4.基于事件的过程流转以及完整的网络事件响应与扩展,5.丰富的example.

Netty 5用户指南

- - 并发编程网 - ifeve.com
原文地址: http://netty.io/wiki/user-guide-for-5.x.html     译者:光辉勇士       校对:郭蕾. 现如今我们使用通用的应用程序或者类库来实现系统之间地互相访问,比如我们经常使用一个HTTP客户端来从web服务器上获取信息,或者通过web service来执行一个远程的调用.

Netty 用户指南4.x

- - CSDN博客推荐文章
现在我们经常使用程序或者库和其他人交流信息.例如,我们经常使用http程序库去从一个web server接收信息,或者调用一个远程的web服务.然而,一个通用的传输协议或者实现有的时候不能适应我们自己的场景.例如,我们不会用http server来传输一些大的文件,Email和一些实时性的信息,例如金融方面或者有些游戏数据方面的信息.这些需要一个高度优化的协议,为了使用某一种特定的应用场景.

Netty 实现原理浅析

- - Java - 编程语言 - ITeye博客
关注微信号:javalearns   随时随地学Java. Netty是JBoss出品的高效的Java NIO开发框架,关于其使用,可参考我的另一篇文章 netty使用初步. 本文将主要分析Netty实现方面的东西,由于精力有限,本人并没有对其源码做了极细致的研 究. 如果下面的内容有错误或不严谨的地方,也请指正和谅解.

Netty实现网络通信

- - 互联网 - ITeye博客
原文同步至  http://www.waylau.com/netty-chat/. Netty 是一个 Java NIO 客户端服务器框架,使用它可以快速简单地开发网络应用程序,比如服务器和客户端的协议. Netty 大大简化了网络程序的开发过程比如 TCP 和 UDP 的 socket 服务的开发.

Netty Client重连实现

- - 鸟窝
当我们用Netty实现一个TCP client时,我们当然希望当连接断掉的时候Netty能够自动重连. Netty Client有两种情况下需要重连:. Netty Client启动的时候需要重连. 在程序运行中连接断掉需要重连. 对于第一种情况,Netty的作者在stackoverflow上给出了 解决方案,.