NGINX开发杀手锏-线程池
nginx以高性能著称,在其内部运转的过程中,没有任何阻塞操作(极端情况还是存在),跟外部的通讯(比如fastcgi)以完全异步的方式进行。在线程池引入之前,我们已经觉得这足够完美。但是线程池的出现,让nginx在性能方面上了一个新的高度。本文将通过一个例子展现这个杀手锏。
1、需求:
我们想让nginx直接跟mysql通讯,你可以选择drizzle,这是异步的方式。本文我们为展现线程池带来的好处,用阻塞的方式与mysql进行通讯,所以选择libmysqlclient这个长久且稳定的库来操作mysql。
2、建立环境:
nginx:192.168.1.100
mysql:192.168.1.101
wrk1:192.168.1.102
wrk2:192.168.1.103
a、编译测试模块
> ./configure --with-threads --add-module=/xxx/nginx-http-mysql-module && make
b、配置
server {
listen 80 ;
#以下是mysql连接信息,请自行调整
mysql_host 192.168.100.101;
mysql_user ***;
mysql_pass ***;
mysql_db ***;
mysql_query "select * from car";
location /mwb {
mysql_with_block;
}
location /mwt {
mysql_with_thread;
}
}
模块下载地址:nginx-http-mysql-module.tar.gz
3、测试
我选择wrk这个测试工具来进行压测。为了让测试更加接近真实,我选择两台客户端机器,第一台不断的制造压测,第二台用普通的方式进行测试。之所以这样是因为如果nginx服务器因为libmysqlclient阻塞了,第二台的qps的就很少。如果ngx服务器不会因为libmysqlclient阻塞,那第二台的qps会表现不错。
a、访问阻塞压测:
wrk1: > wrk -t12 -c400 -d100s http://192.168.1.100/mwb
wrk2: > wrk -t12 -c400 -d30s http://192.168.1.100/mwb
nginx服务器
top - 23:18:23 up 3:24, 4 users, load average: 0.19, 0.17, 0.11
Tasks: 100 total, 2 running, 95 sleeping, 3 stopped, 0 zombie
Cpu(s): 1.1%us, 45.9%sy, 0.0%ni, 41.8%id, 0.0%wa, 2.6%hi, 8.6%si, 0.0%st
Mem: 1922432k total, 677352k used, 1245080k free, 87704k buffers
Swap: 4128760k total, 0k used, 4128760k free, 386840k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
21931 nobody 20 0 433m 3876 1444 R 55.9 0.2 0:50.05 nginx
wrk1机器
Running 2m test @ http://192.168.100.134/mwb
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 376.91ms 288.22ms 1.98s 65.05%
Req/Sec 41.80 68.62 707.00 92.33%
44629 requests in 1.67m, 8.81MB read
Socket errors: connect 0, read 25, write 17, timeout 1629
Non-2xx or 3xx responses: 11546
Requests/sec: 445.90
Transfer/sec: 90.11KB
wrk2机器
Running 30s test @ http://192.168.100.134/mwb
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 0.00us 0.00us 0.00us -nan%
Req/Sec 0.00 0.00 0.00 -nan%
0 requests in 30.02s, 0.00B read
Requests/sec: 0.00
Transfer/sec: 0.00B
b、访问线程池压测:
wrk1: > wrk -t12 -c400 -d100s http://192.168.1.100/mwt
wrk2: > wrk -t12 -c400 -d30s http://192.168.1.100/mwt
nginx服务器
top - 23:24:56 up 3:30, 5 users, load average: 3.00, 0.75, 0.31
Tasks: 99 total, 2 running, 95 sleeping, 2 stopped, 0 zombie
Cpu(s): 0.7%us, 93.4%sy, 0.0%ni, 0.0%id, 0.0%wa, 0.7%hi, 5.3%si, 0.0%st
Mem: 1922432k total, 687728k used, 1234704k free, 88016k buffers
Swap: 4128760k total, 0k used, 4128760k free, 391292k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
22010 nobody 20 0 882m 5564 1452 R 96.5 0.3 0:28.20 nginx
wrk1机器
[root@localhost ~]# wrk -t12 -c400 -d100s http://192.168.100.134/mwt
Running 2m test @ http://192.168.100.134/mwt
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 455.77ms 388.01ms 2.00s 80.91%
Req/Sec 61.15 53.08 310.00 69.47%
51479 requests in 1.67m, 9.17MB read
Socket errors: connect 0, read 15, write 0, timeout 1249
Non-2xx or 3xx responses: 8037
Requests/sec: 514.30
Transfer/sec: 93.80KB
wrk2机器
[root@localhost ~]# wrk -t12 -c400 -d30s http://192.168.100.134/mwt
Running 30s test @ http://192.168.100.134/mwt
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 734.96ms 177.00ms 2.00s 87.92%
Req/Sec 47.40 50.75 310.00 83.23%
10943 requests in 30.09s, 1.79MB read
Socket errors: connect 0, read 8, write 0, timeout 513
Non-2xx or 3xx responses: 862
Requests/sec: 363.63
Transfer/sec: 60.91KB
测试总结:
开启线程池后,nginx的cpu得到更充分利用,第二台机器没有因为第一台的不断访问而受到处理阻碍,跟我们预期的一样,性能得到可观的提升。
4、解释
nginx引入线程池后本质上解决了什么呢?主线程不会被阻塞。它将阻塞的操作转移到了其它的线程,但又能得到回调通知的处理。所以在处理并发的能力上很接近异步的方式。可以说,这让nginx开发业务模块有了更多的选择,毕竟阻塞式的库比异步的容易实现,而且开源的也更丰富。相信不久以后,会有更多的nginx模块冒出来,拭目以待吧。需要说明的是,线程池是为了解决‘阻塞’,如果您的应用没有这个问题,引入线程池反而增加了不必要的开销。
5、线程池是如何实现的
如果想了解线程池的分析,在ngx内部如何实现,以及如何开发基于线程池的模块。阅读 nginx源码分析之线程池。
推荐阅读:NGINX使用线程池提升性能9x倍
转自:http://nglua.com/articles/12.html