nginx: worker_connections are not enough & too many open files.
背景
昨天因为 azure v-net 的问题,将 api 服务迁移到了一台新的虚拟机上(ubuntu)。由于刚迁移完毕,所以今天着重观察了 api 在新机器上的表现。但是却发现,api 在业务高峰期一直达不到之前的请求量,但却没有报错。
问题排查与分析
想了一下,因为是通过 application insight 查看的请求数量和异常数量的统计数据,而数据记录到 application insight 的前提就是,请求必须到达应用程序层(api的部署方式为nginx反向代理到docker中的api),那么应该就是 nginx 处理能力不足导致很多请求并没有请求到应用程序,而是在nginx中就直接报错返回了。
所以果断查看 nginx 的错误日志,发现其中有大量的错误信息,而且还长的一样:
[alert] 19111#19111: 768 worker_connections are not enough
这应该就是 nginx 的配置问题了,赶紧查看nginx.conf
# ...
worker_processes auto;
# ...
events {
worker_connections 768;
# multi_accept on;
}
# ...
好巧,也是768,这算是对上了,就它了,直接改大点试试(改成了2048).
然后第二个高峰期请求量还是没上来... 再看 nginx 日志,还是有错误,而且错误又都长的一样:
[crit] 84004#84004: accept4() failed (24: Too many open files)
所以是改坏了咯? 看下文档上怎么说把。
worker_connections: Sets the maximum number of simultaneous connections that can be opened by a worker process. It should be kept in mind that this number includes all connections (e.g. connections with proxied servers, among others), not only connections with clients. Another consideration is that the actual number of simultaneous connections cannot exceed the current limit on the maximum number of open files, which can be changed by worker_rlimit_nofile.
worker_rlimit_nofile: Specifies the value for maximum file descriptors that can be opened by this process.
也就是说, worker_connections
代表每个 worker 进程可以并发处理的最大连接数。但这个连接数是包含所有连接的,并不是单纯的指跟客户端的连接,在 nginx 做反向代理用途的时候,还会包括与被代理的服务之间的连接数量。而且这个最大连接数不能超过 worker_rlimit_nofile
。
而 worker_rlimit_nofile
则代表一个 worker 进程可以打开的文件描述符的最大数量,这个设置可以在不重启 master 进程的情况向。由于系统本身也有关于 “允许打开的最大文件描述符数量” 的设置(通过 ulimit -n
命令查看,并通过 vim /etc/security/limits.conf
修改),所以我理解应该是 worker_processes
* worker_rlimit_nofile
< 指定用户的 ulimit -n
(比如我给 nofile
设置的值是65536):
#<domain> <type> <item> <value>
* soft nofile 40960
* hard nofile 65536
root soft nofile 40960
root hard nofile 65536
# End of file
可以看到两个设置都与 worker 进程数有关,而 worker 进程的数量又跟 worker_processes
设置有关,worker_processes
的理想值与 CPU 核心数 等很多因素有关,所以官方建议,如果不是非常明确,还是设置为 auto
好了。
那么这 worker_connections
和 worker_rlimit_nofile
两个数值设置为多少比较合适呢?
据说网上有个流传已久的公式:
max_clients = worker_processes * worker_connections / 常数
max_clients: 代表所有与nginx连接的连接数,不单包含浏览器或客户端产生的连接,也包含被代理的服务与nginx之间的连接,以及其他各种连接。
至于这个常数到底是多少,网上有很多种说法,但基本都认为,在 nginx 做 常规http服务器 和 反向代理服务器 时,常数的值并不一样:
- HTTP服务器
- 常数 1, 依据:以静态资源服务器为例,客户端每向 nginx 发起一个连接,就计算为一个client
- 常数 2, 依据:貌似是因为上古时代浏览器针对同一个域名默认只会同时打开两个连接
- 反向代理服务器
- 常数 2, 依据:两个连接分别用于客户端连接nginx和nginx连接被代理的服务
- 常数 4, 依据: 一些权威书籍
所以不妨按照这个公式先试下。
解决问题
说到这里,你们一定以为我就这么把问题解决了对不对?
然而,按照自己的情况设置相关参数之后,发现下一个高峰期依然没有特别明显的缓解,于是就很头疼...
后来在不经意间瞥了一眼服务器配置,发现是 D2 大小的服务器!心头一紧,赶紧把服务器大小更改成了 D2v2,第二天观察,问题解决。
所以,特此吐槽一下 azure: D2v2 比 D2 表面看起来配置是一样的,甚至,D2v2 比 D2 还要便宜将近 $20,可以如果读过文档你就会发现,D2v2 的性能竟然比 D2 提升了大约 35% !