nginx配置
增加如下nginx配置:
1 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' |
request_time:nginx从接收到客户端第一个字节到发送到客户端最后一个字节的时间
upstream_connect_time:nginx建立到上游连接的时间
upstream_header_time:nginx从建立到上游连接到收到上游响应头的时间
upstream_response_time:nginx从建立到上游连接到接收完响应的时间
看一下nginx中对这三个值的计算逻辑:
1 | 函数:ngx_http_upstream_connect |
流程为从开始建立连接记录一个start_time,然后可以发送请求的时候用当前时间减去start_time计算upstream_connect_time,收到响应头后通过当前时间减去start_time计算upstream_header_time,结束上游请求的时候用当前时间减去start_time计算upstream_response_time(注意如上变量有相应的nginx版本要求)
upstream_header_time-upstream_connect_time可以理解为从发送请求开始到响应的时间
upstream_response_time-upstream_header_time如果很大,可以理解为响应数据量很大,耗时比较多
继续实验,将php脚本sleep 1s,然后用wrk压测
1 | wrk -c 20 -t 20 --latency http://localhost:8800/index.php |
php-fpm配置如下:
1 | pm.max_children = 8 |
观察nginx日志如下:
1 | 127.0.0.1 - - [11/Sep/2019:11:53:03 +0800] "GET /index.php HTTP/1.1" 200 14 1.000 0.001 1.001 1.001 "-" "-" "-" |
可以观察出如下规律:
- 11:53:03开始到11:53:06响应时间从1s逐步增加到3s,之后下降稳定到2s多
- upstream_connect_time在us级别,request_time主要消耗在upstream的处理上.但上游每个请求实际耗时1s,说明其他请求在排队等待处理
- 出现一批499,根本没有收到响应
看一下php-fpm的日志:
1 | [11-Sep-2019 11:53:05] WARNING: [pool default] server reached pm.max_children setting (8), consider raising it |
11:53:05的时候打了一条warning,建议提高max_children.后续可以研究php-fpm是升到8个children之后打的日志还是升之前打的日志.根据nginx日志推测,2s之后才开始升到8个children.
nginx499源码流程
nginx源码版本如下:
1 | [root@rh ~ ]# ~/nginx-1.17.3/objs/nginx -v |
在ngx_http_upstream_init_request函数中,会做如下设置:
1 | r->read_event_handler = ngx_http_upstream_rd_check_broken_connection; |
即将客户端和nginx的读写回调函数分别设置为ngx_http_upstream_rd_check_broken_connection和ngx_http_upstream_wr_check_broken_connection,而这两个函数都是调用ngx_http_upstream_check_broken_connection.顾名思义,该函数检测客户端断开的连接,检测到之后会记录499.
首先看看事件处理模块在ngx_epoll_process_events中会有如下代码:
1 | #if (NGX_HAVE_EPOLLRDHUP) |
在使用 2.6.17 之后版本内核的服务器系统中,对端连接断开触发的 epoll 事件会包含 EPOLLIN | EPOLLRDHUP,如果有EPOLLRDHUP事件之后会设置event的pending_eof为1
然后在ngx_http_upstream_check_broken_connection中有如下代码:
1 | #if (NGX_HAVE_EPOLLRDHUP) |
ngx_http_upstream_finalize_request中会做资源回收清理以及关闭上游的fd,然后继续调用 ngx_http_finalize_request(r, rc);
调用链如下:
1 | (gdb) bt |
小结
本文关注nginx如何检测客户端连接从而生成499的access log以及upstream的一些状态指标的计算逻辑.产生499时首先可以通过request time查看处理时间,如果小于客户端设置的超时时间,说明可能是网络等原因导致客户端主动断开.如果request time等于客户端设置的超时时间,那么就得从服务端查找原因.