nginx-ingress性能优化

性能优化

ingress-nginx 集群作为 kubernetes 集群内外通信的流量网关,需要优化性能满足业务需求,我们在 nginx 和内核配置层面做了相应的优化工作。

宿主机中断优化

ingress-nginx 物理机执行 top 命令发现每个 CPU 的 si 指标不均衡,针对此问题 我们开启了网卡多队列机制 以及中断优化。

开启网卡多队列:

  •  
  •  
ethtool -l eth0  // 查看网卡可以支持的多队列配置ethtool -L eth0 combined 8 // 开启网卡多队列机制

中断打散优化:

  •  
  •  
  •  
service irqbalance stop  // 首先关闭irqbalance系统服务sh set_irq_affinity -X all eth0  // Intel提供中断打散脚本:https://github.com/majek/ixgbe/blob/master/scripts/set_irq_affinity

我们针对内核参数也做了优化工作以提升 nginx 性能,主要基于 nginx 官方提供的性能优化方案:https://www.nginx.com/blog/tuning-nginx/

(1)调整连接队列大小

nginx 进程监听 socket 套接字的 连接队列大小默认为 511 ,在高并发场景下 默认的队列大小不足以快速处理业务流量洪峰,连接队列过小会造成队列溢出、部分请求无法建立 TCP 连接,因此我们调整了 nginx 进程连接队列大小。

  •  
sysctl -w net.core.somaxconn=32768

nginx 进程充当反向代理时 会作为客户端与 upstream 服务端建立 TCP 连接,此时会占用临时端口,Linux 默认的端口使用范围是 32768-60999,在高并发场景下,默认的源端口过少会造成端口资源耗尽,nginx 无法与 upstream 服务端建立连接,因此我们调整了默认端口使用范围。

  •  
sysctl -w net.ipv4.ip_local_port_range="1024 65000"

nginx 进程充当反向代理时 会作为服务端与接入层 nginx 建立 TCP 连接,同时作为客户端与 upstream 服务端建立 TCP 连接,即 1 个 HTTP 请求在 nginx 侧会耗用 2 条连接,也就占用 2 个文件描述符。在高并发场景下,为了同时处理海量请求,我们调整了最大文件描述符数限制。

  •  
sysctl -w fs.file-max=1048576

nginx 进程充当反向代理时 会作为客户端与 upstream 服务端建立 TCP 连接,连接会超时回收和主动释放,nginx 侧作为 TCP 连接释放的发起方,会存在 TIME_WAIT 状态的 TCP 连接,这种状态的 TCP 连接会长时间 (2MSL 时长) 占用端口资源,当 TIME_WAIT 连接过多时 会造成 nginx 无法与 upstream 建立连接。

处理 TIME_WAIT 连接通常有 2 种解决办法:

  •  
  •  
net.ipv4.tcp_tw_reuse:复用TIME_WAIT状态的socket用于新建连接net.ipv4.tcp_tw_recycle:快速回收TIME_WAIT状态连接

由于 tcp_tw_recycle 的高危性,4.12 内核已经废弃此选项,tcp_tw_reuse 则相对安全,nginx 作为 TCP 连接的发起方,因此启用此选项。

  •  
sysctl -w net.ipv4.tcp_tw_reuse=1

以上内核参数都使用 kubernetes 提供的 initContainer 机制进行设置。

initContainers:

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
initContainers:      - name: sysctl        image: alpine:3.10        securityContext:          privileged: true        command:        - sh        - -c        - sysctl -w net.core.somaxconn=32768; sysctl -w net.ipv4.ip_local_port_range='1024 65000'; sysctl -w fs.file-max=1048576; sysctl -w net.ipv4.tcp_tw_reuse=1

nginx连接数

 

nginx 作为服务端与接入层 nginx 建立 TCP 连接,同时作为客户端与 upstream 服务端建立 TCP 连接,由此两个方向的 TCP 连接数都需要调优。

(1)nginx 充当服务端,调整 keep-alive 连接超时和最大请求数

ingress-nginx 使用 keep-alive 选项设置 接入层 nginx 和 ingress nginx 之间的连接超时时间(默认超时时间为 75s)。

使用 keep-alive-requests 选项设置 接入层 nginx 和 ingress nginx 之间 单个连接可承载的最大请求数(默认情况下单连接处理 100 个请求之后就会断开释放)。

在高并发场景下,我们调整了这两个选项值,对应到 ingress-nginx 全局 configmap 配置。

  •  
  •  
keep-alive: "75"keep-alive-requests: "10000"

(2)nginx 充当客户端,调整 upstream-keepalive 连接超时和最大空闲连接数

ingress-nginx 使用 upstream-keepalive-connections 选项 设置 ingress nginx 和 upstream pod 之间 最大空闲连接缓存数(默认情况下最多缓存 32 个空闲连接)。

使用 upstream-keepalive-timeout 选项 设置 ingress nginx 和 upstream pod 之间的连接超时时间(默认超时时间为 60s)。

使用 upstream-keepalive-requests 选项 设置 ingress nginx 和 upstream pod 之间 单个连接可承载的最大请求数(默认情况下单连接处理 100 个请求之后就会断开释放)。

在高并发场景下,我们也调整了这 3 个选项值,使得 nginx 尽可能快速处理 HTTP 请求(尽量少释放并重建 TCP 连接),同时控制 nginx 内存使用量。

  •  
  •  
  •  
upstream-keepalive-connections: "200"upstream-keepalive-requests: "10000"upstream-keepalive-timeout: "100"

网关超时

 

ingress nginx 与 upstream pod 建立 TCP 连接并进行通信,其中涉及 3 个超时配置,我们也相应进行调优。

proxy-connect-timeout 选项 设置 nginx 与 upstream pod 连接建立的超时时间,ingress nginx 默认设置为 5s,由于在 nginx 和业务均在内网同机房通信,我们将此超时时间缩短到 1s。

proxy-read-timeout 选项 设置 nginx 与 upstream pod 之间读操作的超时时间,ingress nginx 默认设置为 60s,当业务方服务异常导致响应耗时飙涨时,异常请求会长时间夯住 ingress 网关,我们在拉取所有服务正常请求的 P99.99 耗时之后,将网关与 upstream pod 之间读写超时均缩短到 3s,使得 nginx 可以及时掐断异常请求,避免长时间被夯住。

  •  
  •  
  •  
proxy-connect-timeout: "1"proxy-read-timeout: "3"proxy-send-timeout: "3"

如果某个业务需要单独调整读写超时,可以设置

ingress annotation(nginx.ingress.kubernetes.io/proxy-read-timeout 和 nginx.ingress.kubernetes.io/proxy-send-timeout)进行调整。

4稳定性建设

ingress-nginx 作为 kubernetes 集群内外通信的流量网关,而且多服务共享 ingress 集群,因此 ingress 集群必须保证极致的高可用性,我们在稳定性建设方面做了大量工作,未来会持续提升 ingress 集群稳定性。

健康检查

接入层 nginx 将 ingress nginx worker IP 作为 upstream,早期接入层 nginx 使用默认的被动健康检查机制,当 kubernetes 集群某个服务异常时,这种健康检查机制会影响其他正常业务请求。

例如:接入层 nginx 将请求转发到 ingress nginx 集群的 2 个实例。

  •  
  •  
  •  
  •  
upstream ingress-backend {    server 10.192.168.1 max_fails=3 fail_timeout=30s;    server 10.192.168.2 max_fails=3 fail_timeout=30s;}

如果某个业务 A 出现大量 HTTP error,接入层 nginx 在默认的健康检查机制之下会将 ingress nginx 实例屏蔽,但是此时业务 B 的请求是正常的,理应被 ingress nginx 正常转发。

针对此问题,我们配合接入层 nginx 使用 nginx_upstream_check_module 模块来做主动健康检查,使用 /healthz 接口来反馈 ingress-nginx 运行的健康状况,这种情况下接入层 nginx 不依赖于实际业务请求做 upstream ip 健康检查,因此 kubernetes 集群每个业务请求彼此独立,不会互相影响。

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
upstream ingress-backend {      server 10.192.168.1 max_fails=0 fail_timeout=10s;      server 10.192.168.2 max_fails=0 fail_timeout=10s;      check  interval=1000 rise=2 fall=2 timeout=1000 type=http default_down=false;      check_keepalive_requests 1;      check_http_send "GET /healthz HTTP/1.0\r\n\r\n";      check_http_expect_alive http_2xx;      zone ingress-backend 1M;}

优化重试机制

nginx 提供了默认的 upstream 请求重试机制,默认情况下,当 upstream 服务返回 error 或者超时,nginx 会自动重试异常请求,并且没有重试次数限制。由于接入层 nginx 和 ingress nginx 本质都是 nginx,两层 nginx 都启用了默认的重试机制,异常请求时会出现大量重试,最差情况下会导致集群网关雪崩。我们和接入层 nginx 一起解决了这个问题:接入层 nginx 必须使用 proxy_next_upstream_tries 严格限制重试次数,ingress nginx 则使用 proxy-next-upstream="off"直接关闭默认的重试机制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值