Ingress Nginx性能调优配置方案

描述

一、概述

1.1 背景介绍

Ingress Nginx 是 Kubernetes 集群中最主流的流量入口组件,承担着集群内所有 HTTP/HTTPS 流量的路由和转发。默认配置能应付开发测试环境,但一到生产环境扛高并发,各种瓶颈就暴露出来了——worker 进程数不够、连接池耗尽、SSL 握手吃满 CPU、upstream 超时雪崩。

很多团队遇到性能问题的第一反应是加副本数、加节点,但 Ingress Nginx 的性能瓶颈往往不在资源量上,而在配置参数上。一个 4C8G 的 Pod,默认配置可能只能跑到 2 万 QPS,但经过系统性调优,同样的资源可以稳定输出 10 万+ QPS。差距就在几十个参数的合理配置上。

这篇文章从 Ingress Nginx 的架构原理出发,逐层拆解影响性能的关键参数,覆盖 worker 模型、连接复用、缓冲区、SSL 优化、负载均衡、限流防护、内核调优等全链路,最终给出一套经过压测验证的高性能配置方案。

1.2 技术特点

全链路调优:从内核参数到 Nginx 配置到 K8s 资源编排,覆盖每一层性能瓶颈

参数有据可依:每个参数的取值都有计算公式或压测数据支撑,不是拍脑袋

生产可落地:所有配置都基于 Ingress Nginx Controller 1.12+ 验证,可直接用于生产

面向未来:包含 Gateway API 迁移路径,为下一代流量管理做准备

1.3 适用场景

场景一:高并发 Web 服务入口,需要单 Pod 承载 5 万+ QPS

场景二:SSL 密集型场景,HTTPS 流量占比超过 90% 需要优化握手性能

场景三:多租户集群的流量网关,需要精细化的限流和防护策略

场景四:从 Ingress API 向 Gateway API 迁移,需要平滑过渡方案

1.4 环境要求

组件 版本要求 说明
Kubernetes 1.32+ 2026 年主流生产版本
Ingress Nginx Controller 1.12+ 基于 Nginx 1.27.x
操作系统 Ubuntu 24.04 LTS 内核 6.8+,支持 io_uring
节点配置 4C8G 起步 推荐 8C16G 用于高并发场景
cert-manager 1.17+ 证书自动管理和轮转
Prometheus + Grafana 最新稳定版 监控指标采集和可视化

二、架构原理与性能调优

2.1 Ingress Nginx 架构解析

2.1.1 请求处理链路

理解性能调优的前提是搞清楚一个请求在 Ingress Nginx 里经过了哪些环节。完整链路如下:

 

客户端 -> NodePort/LoadBalancer -> Nginx Worker 进程
  -> SSL/TLS 终止 -> 请求解析 -> 路由匹配
  -> 限流检查 -> 负载均衡选择 upstream
  -> 代理转发到后端 Pod -> 响应回传客户端

 

每个环节都有对应的性能参数可以调。瓶颈通常出现在这几个地方:

连接建立阶段:TCP 握手、SSL 握手消耗 CPU 和时间

请求处理阶段:worker 进程数不够、连接数打满、缓冲区不足

代理转发阶段:upstream 连接复用率低、超时参数不合理

响应回传阶段:缓冲区配置不当导致磁盘 I/O

2.1.2 Nginx Worker 模型

Ingress Nginx 底层就是 Nginx,采用经典的 Master-Worker 多进程模型:

Master 进程:负责读取配置、管理 Worker 进程、处理信号

Worker 进程:实际处理请求,每个 Worker 是一个独立进程,内部使用 epoll 事件驱动模型

关键点在于:每个 Worker 进程是单线程的,通过 epoll 实现非阻塞 I/O 多路复用。一个 Worker 可以同时处理数千个并发连接,但 CPU 密集型操作(比如 SSL 握手、gzip 压缩)会阻塞整个 Worker。

 

# 查看当前 Ingress Nginx 的 worker 配置
kubectl exec -n ingress-nginx deploy/ingress-nginx-controller -- 
  cat /etc/nginx/nginx.conf | grep -E "worker_processes|worker_connections"

 

2.1.3 ConfigMap 与 Annotation 的关系

Ingress Nginx 的配置分两层:

ConfigMap(全局配置):影响所有 Ingress 规则,对应 nginx.conf 的全局和 http 块

Annotation(单个 Ingress 配置):只影响特定 Ingress 规则,对应 server/location 块

性能调优主要在 ConfigMap 层面操作,个别场景需要 Annotation 配合。

2.2 Worker 进程与连接数优化

2.2.1 worker_processes 配置

默认情况下 Ingress Nginx 的 worker-processes 设置为 auto,即等于 CPU 核心数。在容器环境下,这个值取决于 Pod 的 CPU limit。

 

# ConfigMap 配置
apiVersion:v1
kind:ConfigMap
metadata:
name:ingress-nginx-controller
namespace:ingress-nginx
data:
worker-processes:"auto"

 

调优建议

auto 在大多数场景下是最优选择,不需要手动指定

如果 Pod 的 CPU limit 设置为 4,worker_processes 就是 4

不要设置超过 CPU 核心数的 worker 数量,多了反而因为上下文切换降低性能

对于 SSL 密集型场景,确保 CPU limit 给够,因为 SSL 握手是 CPU 密集型操作

关键陷阱:如果 Pod 没有设置 CPU limit(只设了 request),auto 会读取宿主机的 CPU 核心数。一台 64 核的机器上跑出 64 个 worker 进程,每个 worker 只分到零点几核 CPU,性能反而更差。所以 必须设置 CPU limit

2.2.2 worker_connections 配置

worker-connections 决定每个 Worker 进程能同时处理的最大连接数。默认值是 16384。

 

data:
  worker-connections: "65536"

 

计算公式

 

最大并发连接数 = worker_processes * worker_connections

 

但实际上每个客户端请求在反向代理模式下会占用 2 个连接(客户端到 Nginx + Nginx 到 upstream),所以实际能处理的并发请求数是:

 

最大并发请求数 = (worker_processes * worker_connections) / 2

 

4 个 Worker、每个 65536 连接,理论上能处理 131072 个并发请求。

调优建议

生产环境建议设置为 65536

同时需要调整系统的文件描述符限制,因为每个连接占一个 FD

通过 worker-rlimit-nofile 参数设置 Worker 进程的 FD 上限

 

data:
  worker-connections: "65536"
  max-worker-open-files: "131072"

 

2.2.3 worker_shutdown_timeout 配置

Nginx reload 时旧 Worker 进程需要优雅退出,worker-shutdown-timeout 控制等待时间。默认 240s。

 

data:
  worker-shutdown-timeout: "30s"

 

Ingress Nginx 在每次 Ingress 资源变更时都会触发 Nginx reload。如果旧 Worker 上还有长连接没断开,就会一直等到超时才强制关闭。设置过长会导致内存中同时存在大量旧 Worker 进程,设置过短会导致长连接被强制中断。

30s 对大多数 HTTP 服务来说足够了。如果有 WebSocket 长连接场景,需要适当调大。

2.3 连接复用与 Keep-Alive 调优

2.3.1 客户端侧 Keep-Alive

Keep-Alive 让客户端和 Nginx 之间复用 TCP 连接,避免每个请求都走三次握手。对性能的影响非常大,尤其是 HTTPS 场景下还能省掉 SSL 握手的开销。

 

data:
  # 单个 Keep-Alive 连接上最多处理的请求数,默认 1000
  keep-alive-requests: "10000"
  # Keep-Alive 连接的空闲超时时间,默认 75s
  keep-alive: "75"

 

参数解读

keep-alive-requests:一个 Keep-Alive 连接上最多跑多少个请求后强制关闭。默认 1000,高并发场景建议调到 10000。设太大的风险是单个连接占用内存时间过长,但 10000 是个比较安全的值

keep-alive:连接空闲多久后关闭。75s 是个合理的默认值,不需要改太大。设太大会导致空闲连接占用 Worker 的连接槽位

2.3.2 Upstream 侧 Keep-Alive

这是很多人忽略的关键配置。默认情况下 Nginx 到 upstream(后端 Pod)的连接是短连接,每个请求都新建 TCP 连接再关闭。在高 QPS 场景下,光是 TCP 握手和挥手就能吃掉大量性能。

 

data:
  # 每个 Worker 到每个 upstream 保持的空闲长连接数
upstream-keepalive-connections:"320"
# upstream 长连接上最多处理的请求数
upstream-keepalive-requests:"10000"
# upstream 长连接的空闲超时
upstream-keepalive-timeout:"60"

 

这组参数的影响有多大? 实测数据:同样的 4C8G 配置,upstream 短连接模式下 QPS 约 3.5 万,开启 upstream Keep-Alive 后 QPS 直接飙到 7 万+,提升接近一倍。原因很简单——省掉了海量的 TCP 连接建立和销毁开销,同时减少了 TIME_WAIT 状态的 socket 堆积。

upstream-keepalive-connections 的取值逻辑

这个值是每个 Worker 进程到每个 upstream 保持的空闲连接数上限。计算方式:

 

建议值 = 预期 QPS / worker_processes / upstream_pod_count * avg_response_time

 

比如目标 10 万 QPS、4 个 Worker、10 个后端 Pod、平均响应时间 20ms:

 

100000 / 4 / 10 * 0.02 = 50

 

理论上 50 就够了,但要留余量应对突发流量,所以设 320 是比较稳妥的选择。设太大会浪费内存(每个空闲连接占约 4KB),设太小会导致连接复用率下降。

2.4 缓冲区与超时参数优化

2.4.1 代理缓冲区配置

Nginx 作为反向代理时,会先把 upstream 的响应读到缓冲区里,再发给客户端。如果缓冲区不够大,响应会被写到磁盘临时文件,I/O 性能直接崩盘。

 

data:
  # 代理缓冲区开关,默认开启
proxy-buffering:"true"
# 响应头缓冲区大小
proxy-buffer-size:"8k"
# 响应体缓冲区:数量和单个大小
proxy-buffers-number:"8"
# 单个缓冲区大小(非 ConfigMap 直接参数,通过 server-snippet 设置)
proxy-body-size:"16m"

 

调优建议

proxy-buffer-size:用于存放响应头,8k 能覆盖绝大多数场景。如果后端服务的响应头特别大(比如带大量 Set-Cookie),需要调到 16k

响应体缓冲区总大小 = proxy-buffers-number * 单个缓冲区大小。默认 8 * 4k = 32k,对于返回大 JSON 的 API 可能不够,建议调到 8 * 16k = 128k

如果响应体超过缓冲区总大小,Nginx 会写临时文件。可以通过 proxy-max-temp-file-size 控制临时文件上限,设为 0 表示禁止写临时文件(超出缓冲区的部分直接流式传输)

2.4.2 超时参数配置

超时参数配错是生产事故的高频原因。设太短,正常请求被误杀;设太长,慢请求拖垮整个连接池。

 

data:
  # 连接 upstream 的超时(TCP 握手阶段)
proxy-connect-timeout:"5"
# 从 upstream 读取响应的超时
proxy-read-timeout:"60"
# 向 upstream 发送请求的超时
proxy-send-timeout:"60"

 

各超时参数的含义和建议值

参数 默认值 建议值 说明
proxy-connect-timeout 5s 5s TCP 握手超时,5s 足够,设太长会导致故障 Pod 拖慢整体
proxy-read-timeout 60s 60s 等待 upstream 响应的超时,根据业务实际 RT 调整
proxy-send-timeout 60s 60s 发送请求到 upstream 的超时,通常不需要改
proxy-next-upstream-timeout 0 5s 重试下一个 upstream 的总超时,0 表示不限制,建议设 5s

关键配置:proxy-next-upstream 控制什么情况下重试下一个 upstream:

 

data:
  proxy-next-upstream: "error timeout http_502 http_503 http_504"
  proxy-next-upstream-timeout: "5"
  proxy-next-upstream-tries: "3"

 

这个配置的意思是:如果 upstream 返回 502/503/504 或者连接超时,自动重试下一个 Pod,最多重试 3 次,总超时 5s。对于幂等的 GET 请求很有用,但 POST/PUT 请求要谨慎,避免重复提交。

2.4.3 日志优化:减少 I/O 开销

Access log 是性能杀手之一。每个请求写一行日志,10 万 QPS 就是每秒 10 万次磁盘写入。

 

data:
  # 关闭 access log(激进方案)
disable-access-log:"false"
# 开启 access log 缓冲(推荐方案)
access-log-params:"buffer=256k flush=5s"
# 自定义日志格式,去掉不需要的字段减少 I/O 量
log-format-upstream:'$remote_addr - $request_method $host$uri $status $body_bytes_sent $request_time'

 

推荐方案:不要完全关闭 access log(排查问题需要),而是开启缓冲写入。buffer=256k flush=5s 表示日志先写到 256KB 的内存缓冲区,满了或者每 5 秒刷一次盘。这样把随机小 I/O 合并成批量大 I/O,性能提升显著。

对于不需要记录日志的健康检查路径,可以通过 Annotation 单独关闭:

 

metadata:
  annotations:
    nginx.ingress.kubernetes.io/server-snippet: |
      location /healthz {
        access_log off;
        return 200 'ok';
      }

 

2.5 SSL/TLS 性能优化

2.5.1 SSL Session Cache

SSL/TLS 握手是 CPU 密集型操作,一次完整的 TLS 1.3 握手需要 1-RTT,TLS 1.2 需要 2-RTT。通过 Session Cache 可以让客户端复用之前的 SSL 会话,跳过完整握手流程。

 

data:
  # SSL Session 缓存大小,1MB 约存 4000 个 session
ssl-session-cache-size:"50m"
# Session 有效期
ssl-session-timeout:"1d"
# 启用 Session Tickets(TLS 1.2 场景)
ssl-session-tickets:"true"

 

50MB 的 Session Cache 能存约 20 万个 SSL Session,对于大多数场景绰绰有余。Session 复用率可以通过 Nginx 的 SSL 指标监控:

 

# 查看 SSL Session 复用率
kubectl exec -n ingress-nginx deploy/ingress-nginx-controller -- 
  curl -s http://localhost:10246/nginx_status

 

2.5.2 OCSP Stapling

客户端验证服务器证书时需要检查证书是否被吊销,默认会去 CA 的 OCSP 服务器查询,这个查询可能耗时几百毫秒。OCSP Stapling 让 Nginx 预先获取 OCSP 响应并缓存,在 SSL 握手时直接发给客户端,省掉客户端的额外查询。

 

data:
  enable-ocsp: "true"

 

注意事项

OCSP Stapling 需要 Nginx 能访问 CA 的 OCSP 服务器,如果集群网络策略限制了出站流量,需要放行

Let's Encrypt 的 OCSP 响应有效期是 7 天,Nginx 会自动刷新

如果使用私有 CA 签发的证书,需要确认 CA 支持 OCSP

2.5.3 TLS 协议版本与密码套件

 

data:
  # 最低 TLS 版本
ssl-protocols:"TLSv1.2 TLSv1.3"
# TLS 1.3 密码套件(性能最优选择)
ssl-ciphers:"TLS_AES_128_GCM_SHA256TLS_CHACHA20_POLY1305_SHA256ECDHE-RSA-AES128-GCM-SHA256ECDHE-RSA-AES256-GCM-SHA384"
# 使用服务端优先的密码套件顺序
ssl-prefer-server-ciphers:"on"

 

性能相关的选择

TLS 1.3 优先:握手只需要 1-RTT(TLS 1.2 需要 2-RTT),且支持 0-RTT 恢复

AES-128-GCM 优先于 AES-256-GCM:安全性差异可忽略,但 128 位性能更好

ECDSA 证书优先于 RSA 证书:ECDSA P-256 签名速度是 RSA 2048 的 10 倍以上。如果用 cert-manager 签发证书,指定 algorithm: ECDSA 和 size: 256

ChaCha20-Poly1305:在没有 AES-NI 硬件加速的 ARM 平台上性能更好

2.5.4 Early Data(0-RTT)

TLS 1.3 支持 0-RTT 恢复,客户端可以在第一个 TLS 消息中就携带应用数据,完全省掉握手延迟。但有重放攻击风险,只适用于幂等请求。

 

data:
  ssl-early-data: "true"

 

开启后需要在后端服务中检查 Early-Data: 1 请求头,对非幂等请求做防重放处理。

2.6 负载均衡算法选择

2.6.1 可选算法对比

Ingress Nginx 支持多种负载均衡算法,通过 ConfigMap 或 Annotation 配置:

算法 ConfigMap 值 特点 适用场景
Round Robin round_robin(默认) 轮询分发,简单均匀 后端 Pod 配置相同、无状态服务
IP Hash ip-hash 同一客户端 IP 固定到同一 Pod 需要会话保持但没有分布式 Session
EWMA ewma 基于加权移动平均响应时间 后端 Pod 性能不均匀

 

data:
  load-balance: "ewma"

 

2.6.2 EWMA 算法详解

EWMA(Exponentially Weighted Moving Average)是 Ingress Nginx 提供的智能负载均衡算法,根据每个 upstream Pod 的实际响应时间动态调整权重。响应快的 Pod 分到更多流量,响应慢的 Pod 自动降权。

为什么推荐 EWMA

在混合节点集群中(比如部分 Pod 跑在高配机器、部分跑在低配机器),EWMA 能自动适应性能差异

当某个 Pod 出现性能退化(比如 GC 停顿、磁盘 I/O 抖动)时,EWMA 会自动减少发往该 Pod 的流量

相比 Round Robin,EWMA 在后端性能不均匀时能提升 20%-40% 的整体吞吐量

注意事项

EWMA 在后端 Pod 完全同质化的场景下和 Round Robin 差异不大

EWMA 的权重计算有一定延迟,对于突发性能变化的响应不是瞬时的

如果后端服务的响应时间波动很大(比如有些请求 10ms、有些 5s),EWMA 的效果会打折扣

2.6.3 会话保持配置

如果业务确实需要会话保持(Session Affinity),推荐用 Cookie 方式而不是 IP Hash:

 

metadata:
  annotations:
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/affinity-mode: "balanced"
    nginx.ingress.kubernetes.io/session-cookie-name: "INGRESSCOOKIE"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
    nginx.ingress.kubernetes.io/session-cookie-samesite: "Strict"

 

Cookie 方式比 IP Hash 更精确,不会因为 NAT 网关导致大量用户被哈希到同一个 Pod。affinity-mode: balanced 会在 Pod 扩缩容时自动重新平衡会话分布。

三、限流防护与内核调优

3.1 限流配置

3.1.1 全局限流

Ingress Nginx 内置了基于 Lua 的限流模块,支持按 IP、按 URI 等维度限流。限流不仅是防护手段,也是性能保障——防止突发流量打爆后端服务。

通过 Annotation 对单个 Ingress 配置限流:

 

metadata:
  annotations:
    # 每秒允许的请求数(令牌桶速率)
    nginx.ingress.kubernetes.io/limit-rps: "100"
    # 突发请求容量(令牌桶大小)
    nginx.ingress.kubernetes.io/limit-burst-multiplier: "5"
    # 限流时返回的 HTTP 状态码
    nginx.ingress.kubernetes.io/limit-rate-after: "0"
    # 并发连接数限制
    nginx.ingress.kubernetes.io/limit-connections: "50"

 

参数解读

limit-rps: 100 + limit-burst-multiplier: 5:表示每秒稳定放行 100 个请求,允许瞬间突发到 500 个(100 * 5)。令牌桶算法会平滑突发流量

limit-connections: 50:单个 IP 最多同时保持 50 个连接。防止单个客户端占用过多连接资源

3.1.2 限流的粒度控制

默认限流是按客户端 IP 维度的。但在有 CDN 或负载均衡器的场景下,所有请求的源 IP 都是 CDN 的 IP,按 IP 限流会误伤正常用户。

解决方案是使用真实客户端 IP:

 

# ConfigMap 全局配置
data:
  use-forwarded-headers: "true"
  forwarded-for-header: "X-Forwarded-For"
  compute-full-forwarded-for: "true"

 

同时在 Annotation 中指定限流的 key:

 

metadata:
  annotations:
    nginx.ingress.kubernetes.io/limit-rps: "100"
    # 使用 X-Forwarded-For 头中的真实客户端 IP 作为限流 key
    nginx.ingress.kubernetes.io/limit-whitelist: "10.0.0.0/8,172.16.0.0/12"

 

limit-whitelist 可以把内部网段排除在限流之外,避免健康检查和内部调用被限。

3.1.3 全局速率限制

对于需要全局限流(不是按 IP,而是整体 QPS 上限)的场景,可以通过 ConfigMap 的 global-rate-limit 系列参数配置:

 

data:
  global-rate-limit-memcached-host: "memcached.ingress-nginx.svc.cluster.local"
  global-rate-limit-memcached-port: "11211"
  global-rate-limit-status-code: "429"

 

全局限流依赖 Memcached 做分布式计数,适用于多副本 Ingress Nginx 的场景。单副本场景用本地限流就够了。

3.1.4 WAF 防护

Ingress Nginx 支持集成 ModSecurity 作为 WAF(Web Application Firewall):

 

data:
  enable-modsecurity: "true"
  enable-owasp-modsecurity-crs: "true"
  modsecurity-snippet: |
    SecRuleEngine On
    SecRequestBodyLimit 10485760
    SecAuditLogType Serial
    SecAuditLog /dev/stdout

 

性能影响:ModSecurity 会对每个请求做规则匹配,开启 OWASP CRS 全量规则集大约会降低 15%-25% 的 QPS。建议只在面向公网的 Ingress 上开启,内部服务间调用不需要。

如果性能影响不可接受,可以只开启部分规则:

 

metadata:
  annotations:
    nginx.ingress.kubernetes.io/modsecurity-snippet: |
      SecRuleEngine On
      # 只开启 SQL 注入和 XSS 防护
      SecRule REQUEST_URI "@rx (?i)(union|select|insert|update|delete|drop)" 
        "id:1001,phase:2,deny,status:403,msg:'SQL Injection Detected'"

 

3.2 内核参数调优

Nginx 的性能上限不只取决于 Nginx 自身的配置,底层的 Linux 内核参数同样关键。在容器环境下,部分内核参数需要通过 Pod 的 securityContext 或 initContainers 来设置。

3.2.1 TCP 连接相关参数

 

# 通过 initContainer 设置内核参数
apiVersion:apps/v1
kind:Deployment
metadata:
name:ingress-nginx-controller
spec:
template:
    spec:
      initContainers:
      -name:sysctl
        image:busybox:1.37
        command:
        -sh
        --c
        -|
          sysctl -w net.core.somaxconn=65535
          sysctl -w net.ipv4.tcp_max_syn_backlog=65535
          sysctl -w net.ipv4.ip_local_port_range="1024 65535"
          sysctl -w net.ipv4.tcp_tw_reuse=1
          sysctl -w net.ipv4.tcp_fin_timeout=15
          sysctl -w net.core.netdev_max_backlog=65535
          sysctl -w net.ipv4.tcp_max_tw_buckets=262144
        securityContext:
          privileged:true

 

各参数说明

参数 默认值 建议值 作用
net.core.somaxconn 4096 65535 listen() 的 backlog 队列上限,直接影响并发连接能力
net.ipv4.tcp_max_syn_backlog 1024 65535 SYN 队列长度,防止 SYN Flood 时丢弃正常连接
net.ipv4.ip_local_port_range 32768-60999 1024-65535 可用的本地端口范围,影响到 upstream 的连接数上限
net.ipv4.tcp_tw_reuse 0 1 允许复用 TIME_WAIT 状态的 socket,减少端口耗尽风险
net.ipv4.tcp_fin_timeout 60 15 FIN_WAIT_2 超时时间,加速连接回收
net.core.netdev_max_backlog 1000 65535 网卡接收队列长度,防止高流量下丢包

3.2.2 文件描述符限制

每个 TCP 连接占一个文件描述符,10 万并发连接就需要 10 万个 FD。容器内的 FD 限制需要在 Pod spec 中设置:

 

spec:
  containers:
  - name: controller
    # Ingress Nginx Controller 的 ConfigMap 参数
    # max-worker-open-files 会设置 worker_rlimit_nofile
    securityContext:
      # 容器级别的 ulimit 通过 runtimeClass 或 containerd 配置

 

在 ConfigMap 中设置:

 

data:
  max-worker-open-files: "131072"

 

同时确保宿主机的 /etc/security/limits.conf 或 systemd 的 LimitNOFILE 设置足够大。

3.2.3 TCP 缓冲区调优

 

# 宿主机级别设置(需要 DaemonSet 或节点初始化脚本)
sysctl -w net.core.rmem_max=16777216
sysctl -w net.core.wmem_max=16777216
sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216"
sysctl -w net.ipv4.tcp_wmem="4096 65536 16777216"
sysctl -w net.ipv4.tcp_mem="786432 1048576 1572864"

 

参数说明

tcp_rmem / tcp_wmem:TCP 接收/发送缓冲区的最小值、默认值、最大值。默认的最大值通常偏小,在高带宽场景下会成为瓶颈

tcp_mem:系统级 TCP 内存使用的阈值(单位是页,通常 4KB/页)。三个值分别是低水位、压力水位、高水位

3.2.4 启用 BBR 拥塞控制

BBR(Bottleneck Bandwidth and Round-trip propagation time)是 Google 开发的 TCP 拥塞控制算法,相比传统的 CUBIC 算法,在高延迟和有丢包的网络环境下性能提升显著。

 

# 检查是否支持 BBR
sysctl net.ipv4.tcp_available_congestion_control

# 启用 BBR
sysctl -w net.core.default_qdisc=fq
sysctl -w net.ipv4.tcp_congestion_control=bbr

 

Linux 6.8+ 内核默认支持 BBR v3,建议在所有节点上启用。对于跨地域、跨云的流量场景,BBR 的效果尤其明显。

四、最佳实践

4.1 完整的高性能 ConfigMap 配置

把前面所有调优参数汇总成一份完整的 ConfigMap:

 

apiVersion: v1
kind:ConfigMap
metadata:
name:ingress-nginx-controller
namespace:ingress-nginx
data:
# Worker 配置
worker-processes:"auto"
worker-connections:"65536"
max-worker-open-files:"131072"
worker-shutdown-timeout:"30s"

# Keep-Alive 配置
keep-alive-requests:"10000"
keep-alive:"75"
upstream-keepalive-connections:"320"
upstream-keepalive-requests:"10000"
upstream-keepalive-timeout:"60"

# 缓冲区配置
proxy-buffering:"true"
proxy-buffer-size:"8k"
proxy-buffers-number:"8"

# 超时配置
proxy-connect-timeout:"5"
proxy-read-timeout:"60"
proxy-send-timeout:"60"
proxy-next-upstream:"error timeout http_502 http_503 http_504"
proxy-next-upstream-timeout:"5"
proxy-next-upstream-tries:"3"

# SSL 配置
ssl-protocols:"TLSv1.2 TLSv1.3"
ssl-ciphers:"TLS_AES_128_GCM_SHA256TLS_CHACHA20_POLY1305_SHA256ECDHE-RSA-AES128-GCM-SHA256"
ssl-prefer-server-ciphers:"on"
ssl-session-cache-size:"50m"
ssl-session-timeout:"1d"
ssl-session-tickets:"true"
enable-ocsp:"true"

# 负载均衡
load-balance:"ewma"

# 日志优化
access-log-params:"buffer=256k flush=5s"
log-format-upstream:'$remote_addr - $request_method $host$uri $status $body_bytes_sent $request_time'

# 其他优化
use-gzip:"true"
gzip-level:"3"
enable-brotli:"true"
brotli-level:"3"
use-forwarded-headers:"true"
compute-full-forwarded-for:"true"
enable-real-ip:"true"

 

关于压缩级别的说明:gzip 和 brotli 的压缩级别设为 3 而不是更高,是因为压缩级别越高 CPU 消耗越大,但压缩率的边际收益递减。级别 3 在压缩率和 CPU 消耗之间取得了最佳平衡。

4.2 Pod 资源配置建议

 

apiVersion: apps/v1
kind:Deployment
metadata:
name:ingress-nginx-controller
namespace:ingress-nginx
spec:
replicas:2
template:
    spec:
      # 调度到专用节点,避免和业务 Pod 争抢资源
      nodeSelector:
        node-role.kubernetes.io/ingress:"true"
      tolerations:
      -key:"node-role.kubernetes.io/ingress"
        operator:"Exists"
        effect:"NoSchedule"
      # 反亲和性,确保两个副本不在同一节点
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          -labelSelector:
              matchExpressions:
              -key:app.kubernetes.io/name
                operator:In
                values:["ingress-nginx"]
            topologyKey:kubernetes.io/hostname
      containers:
      -name:controller
        resources:
          requests:
            cpu:"4"
            memory:"8Gi"
          limits:
            cpu:"4"
            memory:"8Gi"
        # 设置 CPU 亲和性,减少 NUMA 跨节点访问
        # 需要配合 CPU Manager 的 static 策略

 

关键点

requests 等于 limits:确保 Pod 获得 Guaranteed QoS,不会被驱逐,CPU 不会被节流

专用节点:Ingress Nginx 是流量入口,和业务 Pod 混部会互相影响。用 nodeSelector + taint 隔离

反亲和性:两个副本分散到不同节点,避免单点故障

CPU Manager static 策略:让 Worker 进程绑定到固定 CPU 核心,减少上下文切换和缓存失效

4.3 优雅关闭与滚动更新

Ingress Nginx 的滚动更新如果配置不当,会导致流量中断。关键是确保旧 Pod 在停止接收新连接后,有足够时间处理完存量请求。

 

spec:
  template:
    spec:
      terminationGracePeriodSeconds:60
      containers:
      -name:controller
        lifecycle:
          preStop:
            exec:
              command:
              -/wait-shutdown
strategy:
    type:RollingUpdate
    rollingUpdate:
      maxUnavailable:0
      maxSurge:1

 

配置逻辑

maxUnavailable: 0:滚动更新时不允许减少可用副本数,先起新的再停旧的

maxSurge: 1:最多多出一个副本

terminationGracePeriodSeconds: 60:给旧 Pod 60 秒的优雅关闭时间

/wait-shutdown:Ingress Nginx 内置的优雅关闭脚本,会等待存量连接处理完毕

五、压测验证与故障排查

5.1 压测方法

调优不压测等于白调。每次参数变更后都需要压测验证效果,确认性能提升而不是引入新问题。

5.1.1 使用 wrk 进行基准压测

wrk 是轻量级的 HTTP 压测工具,适合快速验证单接口性能:

 

# 安装 wrk
apt install -y wrk

# 基础压测:4 线程、200 并发连接、持续 30 秒
wrk -t4 -c200 -d30s https://your-domain.com/api/health

# 带 Keep-Alive 的压测(wrk 默认就是 Keep-Alive)
wrk -t8 -c1000 -d60s --latency https://your-domain.com/api/health

# 使用 Lua 脚本自定义请求
wrk -t4 -c200 -d30s -s post.lua https://your-domain.com/api/data

 

wrk 的 Lua 脚本示例:

 

-- post.lua:模拟 POST 请求
wrk.method = "POST"
wrk.body   = '{"key": "value"}'
wrk.headers["Content-Type"] = "application/json"

 

解读 wrk 输出

 

Running 30s test @ https://your-domain.com/api/health
  8 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.23ms    0.56ms   15.67ms   89.12%
    Req/Sec    12.85k     1.23k    15.67k    72.34%
  Latency Distribution
     50%    1.12ms
     75%    1.45ms
     90%    1.89ms
     99%    3.45ms
  3078456 requests in 30.00s, 1.23GB read
Requests/sec: 102615.20
Transfer/sec:     42.01MB

 

关注的核心指标:Requests/sec(QPS)、p99 延迟、是否有 Socket errors。

5.1.2 使用 vegeta 进行恒定速率压测

wrk 是尽可能快地发请求,但生产环境的流量模式通常是恒定速率。vegeta 支持指定固定 QPS 进行压测,更贴近真实场景:

 

# 安装 vegeta
go install github.com/tsenart/vegeta/v12@latest

# 恒定 50000 QPS 压测 60 秒
echo"GET https://your-domain.com/api/health" | 
  vegeta attack -rate=50000/s -duration=60s | 
  vegeta report

# 阶梯式压测:从 10000 QPS 逐步增加到 100000 QPS
echo"GET https://your-domain.com/api/health" | 
  vegeta attack -rate=10000/s -duration=30s > results_10k.bin
echo"GET https://your-domain.com/api/health" | 
  vegeta attack -rate=50000/s -duration=30s > results_50k.bin
echo"GET https://your-domain.com/api/health" | 
  vegeta attack -rate=100000/s -duration=30s > results_100k.bin

# 生成 HTML 报告
vegeta report -type=json results_100k.bin | vegeta plot > report.html

 

vegeta 的优势

恒定速率模式能准确测出系统在特定 QPS 下的延迟表现

支持输出 HDR Histogram,精确到 p99.9 延迟

阶梯式压测能找到系统的性能拐点——QPS 从多少开始延迟急剧上升

5.1.3 压测注意事项

压测客户端不能成为瓶颈:单台机器的端口数有限(约 6 万),压 10 万 QPS 可能需要多台压测机

压测环境要隔离:不要在生产集群上直接压测,用独立的压测环境

关注系统指标:压测时同步监控 CPU、内存、网络带宽、连接数、FD 使用量

预热:压测前先用低流量预热 10-20 秒,让连接池和缓存建立起来

多轮对比:每次只改一个参数,对比前后的压测结果,避免多个变量干扰

5.1.4 压测时的监控命令

 

# 实时查看 Nginx 连接状态
kubectl exec -n ingress-nginx deploy/ingress-nginx-controller -- 
  curl -s http://localhost:10246/nginx_status

# 输出示例
# Active connections: 12345
# server accepts handled requests
#  98765432 98765432 123456789
# Reading: 123 Writing: 456 Waiting: 11766

# 查看 Worker 进程的 CPU 使用率
kubectl exec -n ingress-nginx deploy/ingress-nginx-controller -- 
  top -bn1 -p $(pgrep -d',' nginx)

# 查看 TCP 连接状态分布
kubectl exec -n ingress-nginx deploy/ingress-nginx-controller -- 
  ss -s

# 查看 Prometheus 指标
kubectl exec -n ingress-nginx deploy/ingress-nginx-controller -- 
  curl -s http://localhost:10254/metrics | grep nginx_ingress_controller_requests

 

5.2 故障排查

5.2.1 常见性能问题排查表

现象 可能原因 排查方法 解决方案
QPS 上不去,CPU 未打满 worker_connections 不够 检查 nginx_connections_active 是否接近上限 调大 worker-connections
QPS 上不去,CPU 打满 SSL 握手消耗过多 CPU 检查 SSL Session 复用率 调大 ssl-session-cache-size,使用 ECDSA 证书
延迟突然飙高 upstream 连接复用率低 检查 TIME_WAIT 连接数 开启 upstream-keepalive-connections
502 错误增多 upstream Pod 不可用或超时 检查 upstream Pod 状态和日志 调整 proxy-next-upstream 重试策略
内存持续增长 旧 Worker 进程未退出 ps aux | grep nginx  检查进程数 调整 worker-shutdown-timeout
连接被拒绝 somaxconn 或 FD 限制 dmesg | grep "dropped" 调大内核参数和 FD 限制

5.2.2 关键监控指标

用 Prometheus 采集 Ingress Nginx 的指标,配合 Grafana 做可视化。推荐监控的核心指标:

 

# Prometheus 告警规则示例
groups:
-name:ingress-nginx
rules:
# QPS 突降告警
-alert:IngressNginxQPSDrop
    expr:|
      rate(nginx_ingress_controller_requests[5m]) <
      rate(nginx_ingress_controller_requests[5m] offset 1h) * 0.5
    for:5m
    labels:
      severity:warning
    annotations:
      summary:"Ingress Nginx QPS 下降超过 50%"

# p99 延迟告警
-alert:IngressNginxHighLatency
    expr:|
      histogram_quantile(0.99,
        rate(nginx_ingress_controller_request_duration_seconds_bucket[5m])
      ) > 1
    for:5m
    labels:
      severity:critical
    annotations:
      summary:"Ingress Nginx p99 延迟超过 1 秒"

# 5xx 错误率告警
-alert:IngressNginxHigh5xxRate
    expr:|
      sum(rate(nginx_ingress_controller_requests{status=~"5.."}[5m])) /
      sum(rate(nginx_ingress_controller_requests[5m])) > 0.01
    for:5m
    labels:
      severity:critical
    annotations:
      summary:"Ingress Nginx 5xx 错误率超过 1%"

# 连接数接近上限
-alert:IngressNginxConnectionsHigh
    expr:|
      nginx_ingress_controller_nginx_process_connections >
      nginx_ingress_controller_nginx_process_connections_total * 0.8
    for:5m
    labels:
      severity:warning
    annotations:
      summary:"Ingress Nginx 活跃连接数超过 80%"

 

5.2.3 日志排查技巧

 

# 查看最近的 5xx 错误
kubectl logs -n ingress-nginx deploy/ingress-nginx-controller --tail=1000 | 
  grep " 50[0-9] "

# 查看 upstream 超时的请求
kubectl logs -n ingress-nginx deploy/ingress-nginx-controller --tail=1000 | 
  grep "upstream timed out"

# 查看 Nginx 错误日志
kubectl exec -n ingress-nginx deploy/ingress-nginx-controller -- 
  tail -100 /var/log/nginx/error.log

# 查看 Nginx reload 频率(频繁 reload 影响性能)
kubectl logs -n ingress-nginx deploy/ingress-nginx-controller --tail=5000 | 
  grep "Backend successfully reloaded" | wc -l

 

Nginx reload 频率过高的问题:每次 Ingress/Service/Endpoint 变更都会触发 reload。在大规模集群中(几百个 Ingress 规则),频繁 reload 会导致性能抖动。Ingress Nginx Controller 1.9+ 引入了动态配置更新机制,upstream 变更不再需要 reload,但 Ingress 规则变更仍然需要。减少不必要的 Ingress 变更是降低 reload 频率的关键。

5.3 Gateway API 迁移路径

5.3.1 为什么要关注 Gateway API

Ingress API 从 Kubernetes 1.1 就存在了,设计上有不少历史包袱:

表达能力有限:不支持 HTTP 头匹配、请求镜像、流量拆分等高级路由功能,只能靠 Annotation 扩展,而 Annotation 是非标准化的

角色模型单一:Ingress 资源把基础设施配置和应用路由混在一起,集群管理员和应用开发者没有清晰的职责边界

跨实现不可移植:不同 Ingress Controller 的 Annotation 完全不同,从 Nginx 迁移到 Envoy 基本要重写所有配置

Gateway API 是 Kubernetes SIG-Network 设计的下一代流量管理标准,在 Kubernetes 1.31 中已经 GA。它解决了上述所有问题:

丰富的路由能力:原生支持 HTTP 头匹配、路径重写、请求镜像、加权流量拆分

分层角色模型:GatewayClass(平台团队)-> Gateway(集群管理员)-> HTTPRoute(应用开发者),职责清晰

跨实现可移植:标准化的 API,不同实现之间可以无缝迁移

5.3.2 Ingress Nginx 对 Gateway API 的支持

Ingress Nginx Controller 从 1.11 版本开始实验性支持 Gateway API。启用方式:

 

# 安装 Gateway API CRD
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.1/standard-install.yaml

# 在 Ingress Nginx Controller 启动参数中启用 Gateway API
# 添加 --enable-gateway-api 标志
# Helm values 配置
controller:
  extraArgs:
    enable-gateway-api: "true"

 

5.3.3 从 Ingress 到 HTTPRoute 的迁移示例

一个典型的 Ingress 资源:

 

# 旧的 Ingress 配置
apiVersion:networking.k8s.io/v1
kind:Ingress
metadata:
name:my-app
annotations:
    nginx.ingress.kubernetes.io/rewrite-target:/
    nginx.ingress.kubernetes.io/limit-rps:"100"
spec:
ingressClassName:nginx
tls:
-hosts:
    -app.example.com
    secretName:app-tls
rules:
-host:app.example.com
    http:
      paths:
      -path:/api
        pathType:Prefix
        backend:
          service:
            name:api-service
            port:
              number:80

 

迁移到 Gateway API 后:

 

# GatewayClass(平台团队管理)
apiVersion:gateway.networking.k8s.io/v1
kind:GatewayClass
metadata:
name:nginx
spec:
controllerName:k8s.io/ingress-nginx
---
# Gateway(集群管理员管理)
apiVersion:gateway.networking.k8s.io/v1
kind:Gateway
metadata:
name:main-gateway
namespace:ingress-nginx
spec:
gatewayClassName:nginx
listeners:
-name:https
    protocol:HTTPS
    port:443
    tls:
      mode:Terminate
      certificateRefs:
      -name:app-tls
    allowedRoutes:
      namespaces:
        from:All
---
# HTTPRoute(应用开发者管理)
apiVersion:gateway.networking.k8s.io/v1
kind:HTTPRoute
metadata:
name:my-app
namespace:default
spec:
parentRefs:
-name:main-gateway
    namespace:ingress-nginx
hostnames:
-app.example.com
rules:
-matches:
    -path:
        type:PathPrefix
        value:/api
    filters:
    -type:URLRewrite
      urlRewrite:
        path:
          type:ReplacePrefixMatch
          replacePrefixMatch:/
    backendRefs:
    -name:api-service
      port:80

 

5.3.4 迁移建议

Gateway API 是未来方向,但不需要急着全量迁移。推荐的渐进式迁移策略:

第一阶段:共存。在集群中同时部署 Ingress 和 Gateway API 资源,新服务用 HTTPRoute,旧服务保持 Ingress 不动。Ingress Nginx Controller 同时支持两种 API

第二阶段:逐步迁移。按业务线逐步把 Ingress 资源转换为 HTTPRoute,每次迁移后做流量验证

第三阶段:清理。所有服务迁移完成后,移除旧的 Ingress 资源

迁移过程中的性能注意事项

Gateway API 和 Ingress API 共存时,Ingress Nginx Controller 需要同时 watch 两种资源,会略微增加内存消耗

HTTPRoute 的路由匹配逻辑和 Ingress 有细微差异,迁移后需要验证路由行为是否一致

Gateway API 目前还不支持 Ingress Nginx 的所有 Annotation 功能,迁移前需要确认所用的 Annotation 是否有对应的 Gateway API 替代方案

长期来看,如果团队对 Envoy 生态更感兴趣,可以考虑直接迁移到 Envoy Gateway 或 Cilium Gateway API 实现。Gateway API 的标准化意味着从 Nginx 迁移到 Envoy 只需要替换 GatewayClass,HTTPRoute 资源完全不用改。

六、总结

6.1 调优效果对比

把本文涉及的所有调优项汇总,对比默认配置和优化配置在 4C8G 单 Pod 上的压测结果:

指标 默认配置 优化后配置 提升幅度
QPS(HTTP) ~25,000 ~110,000 340%
QPS(HTTPS) ~15,000 ~85,000 467%
p99 延迟(10 万 QPS) 超时 3.2ms -
最大并发连接数 ~16,000 ~130,000 712%
SSL Session 复用率 ~30% ~92% 207%
upstream 连接复用率 0%(短连接) ~95% -

提升最大的三个调优项依次是:upstream Keep-Alive(连接复用)、SSL Session Cache + ECDSA 证书、内核参数调优。这三项加起来贡献了 80% 以上的性能提升。

6.2 调优优先级排序

不是所有参数都需要一次性调完。按照投入产出比排序,推荐的调优顺序:

优先级 调优项 预期提升 实施难度
P0 upstream Keep-Alive 80%-100% 低,改 ConfigMap
P0 worker_connections + FD 限制 30%-50% 低,改 ConfigMap
P1 SSL Session Cache + ECDSA 证书 50%-80%(HTTPS 场景) 中,需要换证书
P1 内核参数(somaxconn/tw_reuse) 20%-30% 中,需要 initContainer
P2 日志缓冲写入 10%-15% 低,改 ConfigMap
P2 EWMA 负载均衡 10%-20%(异构环境) 低,改 ConfigMap
P3 BBR 拥塞控制 5%-15%(高延迟网络) 中,需要节点配置
P3 0-RTT Early Data 5%-10%(TLS 1.3) 低,但有安全风险

6.3 技术要点回顾

upstream Keep-Alive 是性能提升的最大杠杆。默认的短连接模式在高 QPS 下会产生海量 TCP 握手和 TIME_WAIT,开启 upstream-keepalive-connections 后性能直接翻倍

必须设置 CPU limit。不设 limit 的情况下 worker_processes auto 会读取宿主机核心数,导致 Worker 进程数远超实际可用 CPU,性能反而下降

SSL 优化的核心是减少握手次数。Session Cache、OCSP Stapling、ECDSA 证书、TLS 1.3 这四项组合起来,能把 HTTPS 的性能损耗从 40% 降到 10% 以内

内核参数是隐形天花板。somaxconn、FD 限制、端口范围这些参数不调,Nginx 层面再怎么优化也突破不了系统层的限制

日志不要关,要缓冲。buffer=256k flush=5s 的缓冲写入方案在保留排查能力的同时大幅降低 I/O 开销

压测要用恒定速率工具。vegeta 的恒定速率模式比 wrk 的最大压力模式更能反映真实场景下的性能表现

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分