How Many Non-Persistent Connections Can Nginx/Tengine Support Concurrently

Recently, I took over a product line which has horrible performance issues and our customers complain a lot. The architecture is qute simple, clients, which are SDKs installed in our customers' handsets send POST requests to a cluster of Tengine servers, via a cluster of IPVS load balancers, actually the Tengine is a highly customized Nginx server, it comes with tons of handy features. then, the Tengine proxy redirects the requests to the upstream servers, after some computations, the app servers will send the results to MongoDB.

When using curl to send a POST request like this:
$ curl -X POST -H "Content-Type: application/json" -d '{"name": "jaseywang","sex": "1","birthday": "19990101"}' http://api.jaseywang.me/person -v

Every 10 tries, you'll probably get 8 or even more failure responses with "connection timeout" back.

After some basic debugging, I find that Nginx is quite abnormal with TCP accept queue totally full, therefore, it's explainable that the client get unwanted response. The CPU and memory util is acceptable, but the networking goes wild cuz packets nics received is extremely tremendous, about 300kpps average, 500kpps at peak times, since the package number is so large, the interrupts is correspondingly quite high. Fortunately, these Nginx servers all ship with 10G network cards, with mode 4 bonding, some link layer and lower level are also pre-optimizated like TSO/GSO/GRO/LRO, ring buffer size, etc. I havn't seen any package drop/overrun using ifconfig or similar tools.

After some package capturing, I found more teffifying facts, almost all of the incoming packagea are less than 75Byte. Most of these package are non-persistent. They start the 3-way handshake, send one or a few more usually less than 2 if need TCP sengment HTTP POST request, and exist with 4-way handshake. Besides that, these clients usually resend the same requests every 10 minutes or longer, the interval time is set by the app's developer and is beyond our control. That means:

1. More than 80% of the traffic are purely small TCP packages, which will have significant impact on network card and CPU. You can get the overall ideas about the percent with the below image. Actually, the percent is about 88%.

2. Since they can't keep the connections persistent, just TCP 3-wayhandshak, one or more POST, TCP 4-way handshake, quite simple. You have no way to reuse the connection. That's OK for network card and CPU, but it's a nightmare for Nginx, even I enlarge the backlog, the TCP accept queue quickly becomes full after reloading Nginx. The below two images show the a client packet's lifetime. The first one is the packet capture between load balance IPVS and Nginx, the second one is the communications between Nginx and upstream server.

3. It's quite expensive to set up a TCP connection, especially when Nginx runs out of resources. I can see during that period, the network traffic it quite large, but the new request connected per second is qute small compare to the normal. HTTP 1.0 needs client to specify Connection: Keep-Alive in the request header to enable persistent connection, and HTTP 1.1 enables by default. After turning off, not so much effect.

It now have many evidences shows that our 3 Nginx servers, yes, its' 3, we never thought Nginx will becomes bottleneck one day, are half broken in such a harsh environment. How mnay connections can it keep and how many new connections can it accept? I need to run some real traffic benchmarks to get the accurate result.

Since recovering the product is the top priority, I add another 6 Nginx servers with same configurations to IPVS. With 9 servers serving the online service, it behaves normal now. Each Nginx gets about 10K qps, with 300ms response time, zero TCP queue, and 10% CPU util.

The benchmark process is not complex, remove one Nginx server(real server) from IPVS at a time, and monitor its metrics like qps, response time, TCP queue, and CPU/memory/networking/disk utils. When qps or similar metric don't goes up anymore and begins to turn round, that's usually the maximum power the server can support.

Before kicking off, make sure some key parameters or directives are setting correct, including Nginx worker_processes/worker_connections, CPU affinity to distrubute interrupts, and kernel parameter(tcp_max_syn_backlog/file-max/netdev_max_backlog/somaxconn, etc.). Keep an eye on the rmem_max/wmem_max, during my benchmark, I notice quite different results with different values.

Here are the results:
The best performance for a single server is 25K qps, however during that period, it's not so stable, I observe a almost full queue size in TCP and some connection failures during requesting the URI, except that, everything seems normal. A conservative value is about 23K qps. That comes with 300K TCP established connections, 200Kpps, 500K interrupts and 40% CPU util.
During that time, the total resource consumed from the IPVS perspective is 900K current connection, 600Kpps, 800Mbps, and 100K qps.
The above benchmark was tested during 10:30PM ~ 11:30PM, the peak time usually falls between 10:00PM to 10:30PM.

Turning off your access log to cut down the IO and timestamps in TCP stack may achieve better performance, I haven't tested.

Don't confused TCP keepalievd with HTTP keeplive, they are totally diffent concept. One thing to keep in mind is that, the client-LB-Nginx-upstream mode usually has a LB TCP sesstion timeout value with 90s by default. that means, when client sends a request to Nginx, if Nginx doesn't response within 90s to client, LB will disconnect both end TCP connection by sending rst package in order to save LB's resource and sometimes for security reasons. In this case, you can decrease TCP keepalive parameter to workround.

通过 tcpcopy(pf_ring) 对 BCM 5719 小包做的多组 benchmark

tcpcopy 在文档化、用户参与方式方面有很大的提升空间这个问题在之前已经专门说过。最终,在我们自己阅读代码的情况下,结合 pf_ring,坚持跑通了整个流程,用其对目前 BCM 5719 型号的网卡做了多组对比,结论见结尾。
使用 tcpcopy 做 benchmark,务必确定 tcpcopy 语法使用的正确性, 尽管互联网上绝大多数的文档以及官方文档都写的含糊不清。
比如,我们之前把过滤条件 -F "tcp and dst port 80" 写成了 -F "tcp and src port 80",造成的结果是在错误的基础上得出了一些奇葩的数据以及无法解释的现象,比如到 target server 的流量特别小,并且及其的不稳定,得到的 pps 也是非常的不稳定大到 400kpps/s,小到 20k  甚至 0。

这里列举我们测试环境使用的一组配置。
所有机器都是 RedHat 6.2 2.6.32-279.el6.x86_64,Tcpcopy 1.0 版本,PF_RING 6.0.1,BCM 5719,双网卡 bonding。另外,我们单台生产机器的流量都比较大,并且绝大多数都是 100B 以下的小包,所以对系统的要求还是比较高的。
为了避免后续的误解,先确定几个用语:
1. online server(OS): 即我们线上生产环境的机器
2. target server(TS): 是我们想做 benchmark 的那台机器,以测试其究竟能支撑多大的量
3. assistant server(AS): 是安装了 intercept 的机器
4. mirror server(MS): 通过 tcpcopy 的 mirror 工具把 OS 的流量复制到该台机器上

我们一共做了三大组 benchmark,每组下面包含若干小的 benchmark,包括:
1. tcpcopy + intercept
2. tcpcopy + intercept + tcpcopy mirror,加一个 mirror 是为了减少对 OS 的负载,这样 tcpcopy 在 MS 上运行
3. tcpcopy + intercept + 交换机 mirror,更直接的方式复制线上流量,保证对 OS 没有干扰,并且能保证 100% 全量复制 OS 的流量

Continue reading

服务器网卡收包性能测试

之前写过不少跟网络相关的 benchmark,比如:
* 《网络质量评估
* 《10G(82599EB) 网卡测试优化(总)

上面的更多的是放在带宽使用率上,即如何尽可能的打满,但是都遗漏一个重要的细节,那就是 packet/s,这个论坛的作者一语中的:
– how many packets/sec you have. In fact, network throughput mostly depends on packets/sec, not bytes/sec

可能对于大部分的应用来说,根本无需关注每秒钟到达的包的数量甚至大小,但是对于某些应用来说,这些指标是至关重要的。

要对包(大小、数量、时间)方面的指标做 benchmark,iperf, netperf 之类的就没法用了,他们只能测试带宽,经过一天的使用比较发现下面的一些工具能基本满足需求。要快速的上手的话还是需要对 tcp/ip 有比较深入的了解,比如 ip header,tcp header 之类的,再比如最小的 frame 应该是 64B,这也是众多网络设备厂商做包转发测试的基础,不明白的看下面两张(1, 2)图就清楚了。

跟网络厂商一样,我们也重点关注小包(0-75)的性能,至于小包如何定义,没有严格的标注,我上面的 0-75 也仅仅是从 iptraf 拿到的一个范围,最终还是要根据业务来定。
一般而言,frame(fps) 是针对 data-link(Ethernet) 而言,packet(pps) 是针对 IP 层而言,segment 是针对 TCP 层而言。

Continue reading

如何评估一台服务器(内存)

关于服务器各个部件的问题,可以参考 IITKGP 出的一门叫 《Digital Computer Organization》公开课  ,这里面把计算机的各级 storage 讲述的很详细。
在跑这些(不管是内存的还是磁盘的等等) benchmark 的时候,注意停掉不相关的应用,保持一个干净没有负载的系统。下面会主要介绍 4 种 benchmark 的工具,各个工具的侧重点不一样,求同存异吧。

1. stream
这个工具目前算是比较通用经典,得到工业界认可的工具,之前在 HPC 上用的比较多,现在在互联网行业用的也算是比较广泛的了。
stream 支持 COPY、SCALE、ADD、TRIAD 四种操作,编译后开始运行会默认运行这四种操作。
最新的 5.10 已经将原来的 stream array size 由原来的 2m 增加到 10m 了,以适应越来越大的 L3 需求。总的来说,要运行 stream,需要注意下 STREAM_ARRAY_SIZE 以及 NTIMES 这两个参数。
实际测试中发现运行的特别快,一般 3s 之内就完成一轮测试,因此比较好的方式是多跑几轮(这个在下面要介绍的几款测试工具中都存在,pmbw 在这方面相对做的比较好),取平均值或者中位数。除非你设的 STREAM_ARRAY_SIZE/NTIMES 特别大。

github 上已经有人将其自动化了,可以做从 1 到 $(grep -c processor /proc/cpuinfo) Triad 值;还可以做 multi run。

stream 的官方有不少的测评数据,包括 standard、tuned 等测试包括,可以结合自身的做一下参考。这几个文档,一个通过其发现 bottleneck一个是在 huge pages 里面的应用,最后一个是一个比较综合的测评,在对 postgre 做 benchmark 的时候用到了 stream。


2. bandwidth 
bandwidth 这个工具能够发现内存子系统包括周边的 bus、cache 系统的问题。同时还可以做 network benchmark,不过这个不是我们关注的重点。这个项目除了工具做的不错,跟 stream 一样有不少实体机的 benchmark 数据之外,最出彩的地方是他的文档,尤其是主页的这段,通过 i5 2.5GHz 的 Macbook Pro 机型的测试数据,让你对计算机各个 storage 之间的速度级别有了一个很量化的认识。


3. memtest86+
这是我见到过的最简单的内存 benchmark 工具,只要下载一个 ios 文件,然后重启进入这个系统就可以了。该工具除了能够做 benchmark 之外,还能够做深层次的 failures detection,由于涉及到很多内存的底层构造,因此改工具一直在不断的跟进最新的内存品牌型号。尽管有比这个更简单的方式检测到内存的问题,这个我会单独的写一篇博客说明。


4. pmbw
最后一个要介绍的是 pmbw,据软件作者自己说,是集大成者,弥补了上面软件的不少缺陷。
pmbw 直接通过一些列的汇编指令完成,吸取了 stream(非汇编)以及 bandwidth(局限于 sequential 的测试方式) 的缺点进行改进。同样的,测试报告写的很漂亮,非常有参考价值,比如常见的 E5-2670

最后除了通过 top, htop, vmstat, dstat 等"老掉牙"工具查看系统的实时负载之外,有一个叫 memtop 的工具,原理比较简单,主要是从 /proc/$PID/maps 以及 /proc/meminfo 这两个文件读取,只记录 private/writeable 的内存,而不记录 private/non-writeable 以及 shared 的内存。可以通过他快速的确定有内存问题的应用。除此之外,再介绍几个实时查看系统负载的工具:
1. nmon(Nigel's Monitor)
分为 online 以及 capture 这两种模式,后者可以导入到 csv 文件里面出图。还有个比较方便的地方是可以预先设置环境变量,然后就可以直接运行了:
# export NMON=cmdknjv

2. glances
glances 除了能够导出为 csv, html 的格式外,还能够通过 c/s 的方式对远端的机器进行监控,还能够通过开放的 API 对跟其他的监控系统对接,个人看来意义不是很大,glance 调用的是 psutil 库该库本身就不是很全面,权当参考了。

3. atop
这个功能跟上面的两个类似 ,有个比较独特的是可以通过加载 netatop 模块来查看每一个 process/thread 的网络使用情况,发送接受的包数量、平均的包大小、每一个 process/thread 的带宽消耗等。官方有一个叫 《Case study with atop:memory leakage》的 case study,除了介绍了内存的基本概念之外,还结合了 atop 诊断出了一个内存泄漏的问题,值得一看。

如何评估一台服务器(处理器 CPU)

前面说到了服务器评估运维管理方面的内容,这篇总结下 CPU 的评估。目前还没听说 CPU 会成为一个系统的瓶颈的情况;并且,目前主流的 CPU 也就那么几款,E5-24xx, 26xx,包括会在 Q3 2013 发布 22nm 工艺的 E5-2600 v2 等等。因此 CPU 的 benchmark 相对来说是比较简单的,结果也是显而易见的。

分下面几个方面来进行测试。

1. 浮点
最著名的就是 PI 运算(5000位),网上有不少脚本来做这事,默认情况下,一次 PI 运算只会运行在其中的一个 core 上,建议让每一个 core 都测试一遍,可以使用 taskset 来绑定 CPU core,使得每个 core 都跑一遍 PI 计算。下面这个是 E5-2630 跑的结果:
 0  30.05
 1  30.02
 2  30.07

20  30.15
21  30.06
22  30.12
23  30.01

跟其同等档次的 E5-2430 也仅仅是有很小的差距:
 0  31.34
 1  31.58
 2  31.56
 3  31.53

20  31.50
21  31.51
22  31.40
23  31.50

有点特别需要注意的是,BIOS 里面务必将节能相关的选项关闭,使用 max performance 取代。二者的差距在 CPU 的表现上会非常的明显 ,并且在目前某些服务上会出现莫名其妙的状况。
下面这个是 2630 在使用了 custom 的情况下的 PI 值运行时间:
0  30.48
 1  59.00
 2  58.53
 3  59.09

21  59.02
22  58.80
23  58.65

是不是很夸张?


2. 素数计算
下面几个测试会用到统一工具,sysbench。主流发行版本应该都可以通过包管理器直接安装。
计算 200000 以内的素数:
# sysbench –test=cpu –cpu-max-prime=200000 run

可以指定使用的线程的数量,超过了最大的 core 意义不大:
# sysbench –test=cpu –num-threads=$(grep "processor" /proc/cpuinfo | wc -l)  –cpu-max-prime=200000 run

比如 12 threads,total time 在 74.3045s 左右;而 24 threads 的在 42.0450s 左右,差距还是蛮明显的。


3. thread & mutex
前者主要用来做 scheduler 的 benchmark;后者主要测试 mutex 的性能:
# sysbench –test=threads –num-threads=64 –thread-yields=10000 –thread-locks=8 run
# sysbench –test=mutex –num-threads=200 –mutex-num=10240 –mutex-locks=100000 –mutex-loops=500000 run


除了上面涉及到的 PI、素数、thread/mutex 等,还可以测试非对称密钥的 CPU 计算性能,在没有专有的加解密硬件加速器的情况下,加解密的重任都落到了 CPU 身上。使用 "openssl speed rsa" 这条命令,可以测试出 RSA 的 key operations(signs) 以及其逆过程(verify) 每秒的数值。
# openssl speed rsa512 -multi $(cat /proc/cpuinfo  | grep "model name" | wc  -l)

另外,有个叫 cpuburn-in 的工具,可以尽可能的使得 CPU 升温,使得在比较极端的情况下,发现问题。不过我测试下来发现,CPU 的温度、包括 PSU、Fan 的变化并不是很明显,甚至没有上面使用 openssl 变化的明显。再者,这类物理破坏性测试我认为价值不大,服务器在出厂之前应该都会放到一个高温的屋子里面做温度上的压力测试,最起码我参观过的服务器是这么做压测的。

如何评估一台服务器(管理)

之前我们引进一台新款服务器之前,并没有对其有一个综合的评估,更多是是感性上的认识,没有数据来做支撑。
最早的时候用的是大众型的 11G,12 年升级到了 12G,当时我做的最多的工作就是尽可能的熟悉服务器的每一个细节,每一个硬件配置的差异以及由此带来的影响。后来业务发展需要引进更多型号的机器,为此需要对这些机型做一个客观公正的评估。
g 了不少做 benchmark 的文档,但是说的都比较皮毛,尤其对于对整款机器的测评,更是少之又少。为此,我写了一个小系列,从服务器的各个方面给出一个比较综合的评估方案。注意,仅仅是评估的方案,基本不涉及最终的测试结果,对目前主流的机架式服务器具有通用性。

不少做 benchmark 都是把目光集中在处理性、内存、磁盘、网卡的性能上,却忽略了一个非常重要的方面,那就是服务器可管理性。因此,这一篇主要涉及的就是服务器的可管理性。至于处理器、内存、磁盘、网卡这几个细分领域,网上的资料比我写的好的多,我只会做一些总结,提供一些比较通用的 benchmark 工具。

从管理这个角度来细分的话,可以分为下面几个方面,以下是我当年跟某厂商交流的大方向也是要解决的一些问题。解决了下面这些问题,服务器 OS 底层管理应该就不是什么大问题了。我简单的整理一下,同时,我也回答了一部分的问题,没回答的主要是不同厂商差异化引起的,这个各个厂商有不同的方案,很好解决。

1. 零部件
* BIOS 里面重要选项的设置、表达的意思以及使用的场景,是否有针对 BIOS 的测试报告(BIOS 的这个我曾经浏览了你们随机附带的光盘,里面有一个 3000+ 的文档,我发现里面关于 BIOS 的介绍比较肤浅,所以并不能获得有用的信息)
* RAID 卡,LSI 里面的重要参数的设置、使用场景,是否有针对 LSI 不同设置选项对系统产生的影响的测试
* 其他包括处理器、内存、PCIE 在内的主要硬件的介绍,你们内部是否有很对不同型号零部件的测试
* 远程管理卡的使用配置问题


2. 监控、维修
* 硬件的监控(ipmitool, megacli, sas2ircu),比如 LSI 的,我们之前会用 megaraid 来做监控,其他的一些部件我们会用 IPMI 来做监控。是否有更好的方式来及时的发现硬件的问题,比如硬盘
* ipmitool 对几个重要方面(inband, outofband)的支持完整性,是否都能很好的支持
* 几个核心的零部件,包括硬盘(SSD),RAID 卡(BBU),内存,CPU、主板。如何诊断这些部件出现问题,在 Linux 下面有什么权威的工具(ISM-cli-tools,可以做成 U 盘启动)、软件来判断、诊断问题


3. 自动化
* 有没有类似 DELL 的 OpenMange、DTK 等工具,可以自动的建立修改删除 RAID,另外远程卡的配置是否有比较自动化的方式。厂商出厂之前人肉帮我们都设置好是一回事,我们希望有更自动化的方式来完成

4. 其他
* 10G 网卡,fusion-io 等相对高端设备的介绍、使用、测试等等


5. 功耗
* 这个是必须要考虑的问题,可以看官方的 specs 得到一个最大值,可以自己分不同的等级跑一些压力测试,从而得到不同压力下的功耗问题

以上是在大规模上架服务器之前需要解决的问题,很不幸的是,在正常情况下,从我们接触到的厂商来看,由于沟通上(信息传递)的问题或者由于技术上的问题,他们并不能给出令人满意的答复。对于这类传统的跟互联网稍微沾点边的公司,大部分都由一些混日子的客户经理等角色组成,这也是为什么每年某些公司像批发商品一样一下子招一批应届生的原因,大部分进去之后都是充当这类的角色。不要觉得不可思议,我们是作为大客户的角色,上面的这些基本问题都不能很好的解决,可以想象一下,对于其他的客户,他们是怎样的一种态度以及实力。所以上面这些问题的解决是需要靠你自己,所幸有 google,因此真正的实施起来也不是很复杂,只不过需要一些时间来熟悉他们罢了。

接下来的几篇会涉及处理器、内存磁盘以及其他(非技术层面)这几个方面,网卡(《如何评估一台服务器(网卡)》)的测试以及优化在之前的已经写过一个完整系列,在这里就省略不写了。需要的可以看这里: