首页 > 代码库 > 记一次压力测试和对nginx/tomcat配置的调整

记一次压力测试和对nginx/tomcat配置的调整

是一个web系统,前端使用nginx做为反向代理,处理https,并将请求转发给后端的tomcat服务。 

压力测试工具选择了jmeter。 首先简单介绍一下jmeter。 它是apache的一个开源项目,基于java swing开发的GUI界面。 
jmeter提供了许多高级的功能,但我们仅仅使用了jmeter最简单的功能。在简单的jmeter使用中,我们涉及到这么几个概念:测试计划,线程组,测试任务,和Listener。看下面的图: 
jmeter

在一个名为“测试”的测试计划下, 我们建立了一个线程组。 这个线程组可以设置线程数,创建时间(在多长时间内创建出这么多个线程),每个线程任务循环执行次数。 然后为这个线程组指派了一个http请求任务。 这个任务可以指定协议(http或https),服务器, url,参数等。

接下来为这个http请求任务添加了一个aggregate graph类型的listener。 我们需要看最终的测试结果, 这个listener就是为我们记录并展示结果的。

一切设置就绪之后,点击主界面上边的“启动”按钮,就可以在aggregate graph中观看测试结果了。 
我们所测试的后端tomcat,执行了一次mysql数据库的查询请求,并执行了一次通过http协议请求内网其它服务器的远程请求。

尝试着调整并发压力测试的线程数,发现吞QPS留在600/sec,始终无法提升, 而此时cpu的消耗只有40%左右,显然cpu还未到瓶颈。 而https处理和这样的web server,根据经验瓶颈一般出现在cpu上,为什么cpu还未到达瓶颈,qps就上不去了呢。

接下来我们在nginx的access log中增加了 $request_time这一项, 在tomcat服务中也打了日志观测执行时间。 发现nginx的时间远大于tomcat的处理时间。 原来瓶颈点在nginx这里。 
尝试优化一下nginx的参数,第一个看到的是,由于这是一台测试机,nginx采用的大部分配置都是默认设置,worker_processes参数被设置为1. 把这个数字调整为4的时候, QPS提升到了 1200, cpu利用率达到了99%. 看来这个就是这台测试机硬件配置的极限了。

那么单个worker_processes的时候,为什么cpu利用率上不去,java进程尚未充分利用硬件资源,而nginx先到达瓶颈呢? 对比测试一下, 当访问硬盘上一个静态html页面的时候, 单个worker进程qps可以达到9000+。静态资源和proxy_pass的差别在于读取本地磁盘文件(可能有内存缓存),和向后端建立socket连接。团队里的技术大牛通过strace跟踪了一下,也未找出明显的问题根源,推测是在向后端建立连接的地方会出现排队等待现象。

在我们压测的过程中, 通过netstat命令可以看到有很多nginx向tomcat发起的连接。 这些连接都是短连接,每次用完即关闭。于是想到nginx向后端源服务器能否建立长连接的问题。查看了一下文档,nginx从1.1.4版本开始,支持proxy_pass的时候向后端源服务器建立长连接。

根据官网的描述,若采用长连接,必须在proxy_pass的时候使用upstream的方式, 直接把后端源写在proxy_pass后边是不行的。 具体的配置方式如下: 
定义upstream: 
upstream lich { 
server 127.0.0.1:8081; 
keepalive 128; 
}

proxy_pass的地方: 
proxy_pass http://lich; 
proxy_http_version 1.1; 
proxy_set_header Connection "";

官方文档在这里:http://nginx.org/en/docs/http/ngx_http_upstream_module.html 
官方文档中说:proxy_http_version和proxy_set_header这两个配置是需要加上的。
不建议使用http 1.0通过Connection:Keep-Alive的方式。

配置完成之后重新测试,qps略微有一点提升。 但并不明显。 为了验证长连接是否生效, 同样通过 netstat命令查看连接。 发现连接到后端8081端口的nginx开启的临时端口不停的发生变化, 这证明了仍然是在采用短链接的方式。 那么是谁先关闭连接的呢。 

通过tcpdump抓包发现, 首先发出 Fin 包的是tomcat。 也就是说, tomcat主动关闭的连接。

 

原来在tomcat的配置文件中, 有关于keepalive的几个参数。 包括每一个连接完成多少个http请求之后就关闭等。 详细的参数可以参见tomcat的文档。详细的文档应该看这里:https://tomcat.apache.org/tomcat-7.0-doc/config/http.html

对tomcat的connector进行了一些调整(包括maxKeepAliveRequests和keepAliveTimeout两个参数,都设置成-1)之后, 再看连接,已经不会频繁断开并重建了。 QPS也提升到了900+.

尽管如此, nginx仍然是瓶颈,worker_processes设置为4个的时候,cpu可以利用到100%, QPS可以达到1200.

最后再做一个对比, 当jmeter绕过nginx,不走https而直接访问http的端口8081时,qps可以达到1500+。对比一下,对https的开销大概有个概念。

记一次压力测试和对nginx/tomcat配置的调整