Netty高性能编程备忘录(上)
http://calvin1978.blogcn.com/articles/netty-performance.html
网上赞扬Netty高性能的文章不要太多,但如何利用Netty写出高性能网络应用的文章却甚少,此文权当抛砖引玉。
估计很快就要被拍砖然后修改,因此转载请保持原文链接,否则视为侵权...
http://calvin1978.blogcn.com/articles/netty-performance.html
参考资料:
- Netty Best Practices a.k.a Faster == Better by Norman Maurer,Netty核心开发
- Netty高性能之道 by 李林锋,《Netty权威指南》作者
- Netty系列之Netty百万级推送服务设计要点 by 李林锋,但和本文针对的SOA场景不太一样
- 用Netty开发中间件:高并发性能优化
1. 连接篇
1.1 Netty Native
Netty Native用C++编写JNI调用的Socket Transport,是由Twitter将Tomcat Native的移植过来,现在还时不时和汤姆家同步一下代码。
经测试,的确比JDK NIO更省CPU。
也许有人问,JDK的NIO也用EPOLL啊,大家有什么不同? Norman Maurer这么说的:
- Netty的 epoll transport使用 edge-triggered 而 JDK NIO 使用 level-triggered
- C代码,更少GC,更少synchronized
- 暴露了更多的Socket配置参数
第一条没看懂,反正测试结果的确更快更省CPU。
用法倒是简单,只要几个类名替换一下,详见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实现比OpenSSL慢很多很多,而大家把SSL Provider配置成OpenSSL时,又要担心操作系统有没装OpenSSL,或者版本会不会太旧。现在好了。
1.2 异步连接,异步传输,告别Commons Pool
异步化最牛头不对马嘴的事情就是,给它配一个类似Commons Pool这样,有借有还的连接池。
在很多异步化的场景里,都用channel.writeAndFlush()原子的发送数据,发完不用同步等response,这时其实不需要独占一条Channel,不需要把它借出去,再还回池里。一来连接池出入之间有并发锁,二来并发请求一多就要狂建连接,到了连接池上限时还要傻傻的等待别人释放连接,而这可能毫无必要。
此时,建议直接建一个连接数组,随机到哪个连接就直接用它发送数据。如果那个连接还没建立或者已经失效,那就建立连接。
顺便说一句,异步的世界里,连建立连接的过程也是异步的,主线程不要等在建连接上,而是把发送的动作封成一个ChannelCallback,等连接建立了,再回调它发送数据,避免因为连接建立的缓慢或网络根本不通,把线程都堵塞了。
Netty4.0.28开始也有ChannelPool了,供需要独占Channel的场景如HTTP1.1,比之Commons Pool的特色之一也是这个异步的建连接过程。
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参数设定
TCP/Socket的大路设置,无非 SO_REUSEADDR, TCP_NODELAY, SO_KEEPALIVE 。另外还有SO_LINGER , SO_TIMEOUT, SO_BACKLOG, SO_SNDBUF, SO_RCVBUF。
而用了Native后又加了TCP_CORK和KeepAlive包发送的时间间隔(默认2小时),详见EpoolSocketChannelConfig的JavaDoc。
所有这些参数的含义,不一一描述了,自己搜索,比如Linux下高性能网络编程中的几个TCP/IP选项。
而Netty自己的参数CONNECT_TIMEOUT_MILLIS,是Netty自己起一个定时任务来监控建立连接是否超时,默认30秒太长谁也受不了,一般会弄短它。
2. 线程篇
基本知识:《Netty in Action》中文版—第七章 EventLoop和线程模型
2.1 WorkerGroup 与 Boss Group
大家都知道,Boss Group用于服务端处理建立连接的请求,WorkGroup用于处理I/O。
EventLoopGroup的默认大小都是是2倍的CPU核数,但这并不是一个恒定的最佳数量,为了避免线程上下文切换,只要能满足要求,这个值其实越少越好。
Boss Group每个端口平时好像就只占1条线程,无论配了多少。
2.2 上下游线程的绑定
在服务化的应用里,一般处理上游请求的同时,也会向多个下游的服务集群发送请求,但调优指南里都说,尽量,全部重用同一个EventLoop。否则,处理上游请求的线程,就要把后续任务以Runnable的方式,提交到下游Channel的处理线程。
但,一个EventLoop线程可以处理多个Channel的信息,而一个Channel只能注册一个EventLoop线程。所以没办法保证处理上游的Channel,与下游多个连接的Channel,刚好是属于一个EventLoop?
因此,追求极致的Proxy型应用,可能会放弃前面的固定连接池的做法,而是为每个处理上游请求的线程,对应每一台下游服务器创建一条Channel,而且设定它的工作线程就是本上游线程,然后存到threadLocal里。这样的做法连接数可能会增多,但减少了切换,要自行测试权衡。
2.2 业务线程池
Netty线程的数量一般固定且较少,所以很怕线程被堵塞,比如同步的数据库查询,比如下游的服务调用(又来罗嗦,future.get()式的异步在执行future.get()时还是堵住当前线程的啊)。
所以,此时就要把处理放到一个业务线程池里操作,即使要付出线程上下文切换的代价,甚至还有些ThreadLocal需要复制。
2.3 定时任务
像发送超时控制之类的一次性任务,不要使用JDK的ScheduledExecutorService,而是如下:
ctx.executor().schedule(new MyTimeoutTask(p), 30, TimeUnit.SECONDS)
首先,JDK的ScheduledExecutorService是一个大池子,多线程争抢并发锁。而上面的写法,TimeoutTask只属于当前的EventLoop,没有任何锁。
其次,如果发送成功,需要从长长Queue里找回任务来取消掉它。现在每个EventLoop一条Queue,明显长度只有原来的N分之一。
2.4 快速复习一下Netty的高性能线程池
Netty的线程池理念有点像ForkJoinPool,都不是一个线程大池子并发等待一条任务队列,而是每条线程自己一个任务队列。
不过Netty4的方法是建了N个只有一条线程的线程池,然后用前面说的选择器去选择。而曾经的Netty5 Alpha好像直接就用了ForkJoinPool。
而且Netty的线程,并不只是简单的阻塞地拉取任务,而是非常辛苦命的在每个循环同时做三件事情:
- 先处理NIO的事件
- 然后获取2.3里提到的本线程的定时任务,放到本线程的任务队列里
- 再然后混合2.2里提到的其他线程提交给本线程的任务,一起执行
每个循环里处理NIO事件与其他任务的时间消耗比例,还能通过ioRatio变量来控制,默认是各占50%。
可见,Netty的线程根本没有阻塞等待任务的清闲日子,所以也不使用有锁的BlockingQueue如ArrayBlockingQueue来做任务队列了,而是直接使用下篇里提到的JCTools提供的无锁的MpscLinkedQueue(Mpsc 是Multiple Producer, Single Consumer的缩写)。
文章太长没人看,写到这里就停笔了。剩下内容请看 Netty高性能编程备忘录(下)
Netty高性能编程备忘录(上)的更多相关文章
- Netty高性能编程备忘录(下)
估计很快就要被拍砖然后修改,因此转载请保持原文链接,否则视为侵权... http://calvin1978.blogcn.com/articles/netty-performance.html 前文再 ...
- Netty 系列之 Netty 高性能之道
1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用 Netty4 + Thrift 压缩二进制编解码技术,他们实现了 10 W TPS(1 K 的复杂 POJO 对象)的跨 ...
- Netty系列之Netty高性能之道
转载自http://www.infoq.com/cn/articles/netty-high-performance 1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用Ne ...
- Netty高性能之道
1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友告诉我,通过使用Netty4 + Thrift压缩二进制编解码技术,他们实现了10W TPS(1K的复杂POJO对象)的跨节点远程服务调用.相比于 ...
- 转:Netty系列之Netty高性能之道
1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用Netty4 + Thrift压缩二进制编解码技术,他们实现了10W TPS(1K的复杂POJO对象)的跨节点远程服务调用 ...
- 新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析
1.引言 Netty 是一个广受欢迎的异步事件驱动的Java开源网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端. 本文基于 Netty 4.1 展开介绍相关理论模型,使用场景,基本组件 ...
- 【读后感】Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ?
[读后感]Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ? 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商 ...
- Netty高性能原理和框架架构解析
1.引言 Netty 是一个广受欢迎的异步事件驱动的Java开源网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端. 本文基于 Netty 4.1 展开介绍相关理论模型,使用场景,基本组件 ...
- Netty 系列之 Netty 高性能之道 高性能的三个主题 Netty使得开发者能够轻松地接受大量打开的套接字 Java 序列化
Netty系列之Netty高性能之道 https://www.infoq.cn/article/netty-high-performance 李林锋 2014 年 5 月 29 日 话题:性能调优语言 ...
随机推荐
- 20145318《网络对抗》注入shellcode及Return-to-libc
20145318<网络对抗>注入shellcode及Return-to-libc 注入shellcode 知识点 注入shellcodeShellcode实际是一段代码(也可以是填充数据) ...
- bzoj 3600 没有人的算术 - 替罪羊树 - 线段树
题目都是图片,就不给了,就给链接好了 由于bzoj比较慢,就先给[vjudge传送门] 有兴趣的可以去逛bzoj[bzoj传送门] 题目大意 有n个数a[1],a[2],...,a[n],它们开始都是 ...
- Splay简介
Splay树,又叫伸展树,可以实现快速分裂合并一个序列,几乎可以完成平衡树的所有操作.其中最重要的操作是将指定节点伸展到指定位置, 目录 节点定义 旋转操作 伸展操作 插入操作 删除操作 lower_ ...
- Python3基础 random 配合while输出10个随机整数
Python : 3.7.0 OS : Ubuntu 18.04.1 LTS IDE : PyCharm 2018.2.4 Conda ...
- Android和PHP开发最佳实践
Android和PHP开发最佳实践 <Android和PHP开发最佳实践>基本信息作者: 黄隽实丛书名: 移动应用开发技术丛书出版社:机械工业出版社ISBN:9787111410508上架 ...
- kubernetes 命令记录
操作基本命令: 通过yaml文件创建: kubectl create -f xxx.yaml (不建议使用,无法更新,必须先delete) kubectl apply -f xxx.yaml (创 ...
- 基于nodejs环境,用npm简单搭建一个本地服务器Live-server的使用
用npm 或者cnpm进行全局安装 cnpm install -g live-server 运行后就可以直接给你虚拟一个本地服务器,而且还可以热同步 运行 live-server
- 【Coursera】History: Dawn of Electronic Computing学后小结
今天学习了Coursera上University of Michigan开的互联网的历史.技术和安全课程的FirstWeek内容. 先是吐槽下这个Coursera,认证非常麻烦,PC端需要摄像头拍照. ...
- 机器学习 MLIA学习笔记(二)之 KNN算法(一)原理入门实例
KNN=K-Nearest Neighbour 原理:我们取前K个相似的数据(排序过的)中概率最大的种类,作为预测的种类.通常,K不会大于20. 下边是一个简单的实例,具体的含义在注释中: impor ...
- 遇到Io阻塞时会切换任务之【爬虫版】
#! /usr/bin/env python3 # -*- coding:utf- -*- from urllib import request import gevent,time from gev ...