nginx c10m


原文链接: nginx c10m

原文地址 http://www.ipcpu.com/2018/06/nginx-high-connection/

tinkerbeast/c10M: Research into the c10M problem with respect to the Linux kernel.
高并发状态下 nginx 的配置 (20 万并发).md

一、概述

最近业务量比较大,nginx 出现了十六七万将近二十万并发(ESTABLISH 连接数)的情况,所以对 20 万以下并发,nginx 需要注意哪些配置进行了整理:

二、操作系统基础优化

网上一大堆,基本就是改 sysctl.conf,需要注意的是

# 端口范围设定
sysctl -w net.ipv4.ip_local_port_range='1024 65535'

# 端口快速回收
sysctl -w net.ipv4.tcp_tw_recycle=1
sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -w net.ipv4.tcp_timestamps=1

# 文件打开数量的处理
sysctl -w fs.file-max=10485760
ulimit -n 1048576
echo 'ulimit -n 1048576' >> ~/.bash_profile

net.ipv4.tcp_max_tw_buckets = 940000
net.ipv4.tcp_tw_recycle=0
net.ipv4.ip_local_port_range = 1024 65000
#端口范围尽量大一些

三、nf_conntrack 的配置

如果启用了 nf_conntrack,并且配置的数值较小,那么会遇到

nf_conntrack: table full, dropping packet

如果可能的话,建议关闭 nf_conntrack,设置 NOTRACK 或者调大数值。
做 openstack 云计算的同事推荐配置

nf_conntrack_max = 4194304 
nf_conntrack_buckets = 1048576
nf_conntrack_tcp_timeout_time_wait = 60

也可以参照本站以前的文章:
https://www.ipcpu.com/2015/06/nf_conntrack-table-full/

四、文件打开数配置

如果你的文件打开数是 65535,那么应该先遇到的错误是”Too many open files”

 error: 2018/06/15 17:03:51 [crit] 3325#0: accept4() failed (24: Too many open files)

需要调整操作系统的 / etc/security/limits.conf 以及附属文件。
在 nginx 层面有 2 个参数也需要调整

worker_rlimit_nofile 512000;
##@@worker进程的最大打开文件数限制。
worker_connections 151200;
##@@worker进程可以保持的最大并发连接。官方文档明确标出,作为代理使用时,这个值包含"nginx与客户端的连接"和"nginx与upstream的连接"。

网上有个公式:
max_clients = worker_processes * worker_connections / 2;
(部分文档是除以 4,是考虑浏览器并发数为 2)
这个参数解决了,基本上七八万的 ESTABLISH 是没问题了。

五、端口耗尽的问题

如果并发数继续往上增长,可能出现如下错误:

2018/06/16 08:37:35 [crit] 27744#0: *137027418 connect() to 10.140.2.47:443 failed (99: Cannot assign requested address) while connecting to upstream, client: 10.140.2.200, server: 0.0.0.0:9443, upstream: "10.140.2.47:443", bytes from/to client:0/0, bytes from/to upstream:0/0

很明显端口耗尽,没有可以资源了。
这里的端口耗尽,并不是指 1-65535 端口,而是 socket 五元组,如下

对于客户端访问 nginx 的连接来说,

源 IP 和源端口都是随机的,目的 IP(nginx 本机 IP)和目的端口(nginx 本机服务端口)是固定的,这样理论上来说,是没有限制的。

对于 nginx 访问 upstream 来说,

源 IP 固定(nginx 本机 IP),源端口随机,目的 IP 和目的端口(upstream 地址)需要看 upstream 的数量,总数就是 6 万随机端口乘以 upstream 的个数。

如果 upstream 的个数很少,那就会出现端口耗尽,例如 5 个 upstream 地址,那么总数就是 6 万 * 5=30 万(实际只有 80-90%)大约 25 万。

我们在 nginx 服务器上使用 “ss -n” 也发现确实是按照五元组使用的,例如下面的 13958 本机端口就是用了两次,产生了两个 socket 连接。

ESTAB 0 0 172.28.4.173:13958 172.28.4.161:3000               
ESTAB 0 0 172.28.4.173:13958 172.28.4.162:3000 

那么如何解决端口耗尽的问题呢?
一方面可以在 upstream 机器上增加 IP 地址或者端口,
另一方面也可以在 nginx 主机上增加 IP 地址,然后使用 nginx 的 proxy_bind 指定源地址。

五、系统内存

在操作系统层面每个 TCP 连接会占用 3k-10k 的内存,以 20 万来计算,需要 2G 内存。nginx 程序本身还要消耗内存,特别是 nginx 反向代理 POST 请求比较多的情况,20 万连接情况下推荐 16G 内存配置。

六、深度追问

TCP 连接会不会占用文件描述符?

处在 ESTABLISH 状态的 TCP 连接,是会占用文件描述符的。而处在 TIME_WAIT 等非连接状态的 TCP 连接不会占用。
注意:CLOSE_WAIT 状态也会占用文件描述符(怎么看?lsof !)

关于 TIME_WAIT 数量过大会有什么影响?

这个担心是多余的,我目前机器上 TIME_WAIT 数量在 60 万左右,tcp_max_tw_buckets 设置的是 94 万,由于 TIME_WAIT 占用内存很小,并且不占用文件描述符,目前没发现有什么问题。唯一需要担心的就是 TIME_WAIT 耗尽了 nginx 访问 upstream 时候的五元组,这个担心可以通过在 nginx 主机上增加 IP 地址解决(同端口耗尽)。

关于 upstream 中的 keepalive 选项,什么意思?

线上的 nginx 代理服务器 upstream 中的 keepalive 选项设置为 64,但实际运行过程中和后端单台服务器产生了一万多 ESTAB 连接。查看了 nginx 官方文档,发现这个值是最大的 idle(空闲) 数据,只有用完的连接才会回收。

The connections parameter sets the maximum number of idle keepalive connections to upstream servers that are preserved in the cache of each worker process. When this number is exceeded, the least recently used connections are closed.

参考资料

https://work-jlsun.github.io/2016/09/01/tunning-nginx-performance.html
http://nginx.org/en/docs/http/ngx_http_upstream_module.html
https://www.cs.utah.edu/~mflatt/past-courses/cs5460/lecture17.pdf

`