ngin Finding Everything About Nginx Here

NGINX开发杀手锏-线程池

发表于 2015-06-25 阅读数 7135

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倍