一、概述
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 配置 kubectlexec-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 复用率 kubectlexec-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 30stest@ 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 requestsin30.00s, 1.23GBread 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 连接状态 kubectlexec-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 使用率 kubectlexec-n ingress-nginx deploy/ingress-nginx-controller -- top -bn1 -p $(pgrep -d','nginx) # 查看 TCP 连接状态分布 kubectlexec-n ingress-nginx deploy/ingress-nginx-controller -- ss -s # 查看 Prometheus 指标 kubectlexec-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 错误日志 kubectlexec-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 的最大压力模式更能反映真实场景下的性能表现
-
模型
+关注
关注
1文章
3810浏览量
52253 -
nginx
+关注
关注
0文章
193浏览量
13203 -
kubernetes
+关注
关注
0文章
273浏览量
9530
原文标题:Ingress Nginx 性能调优:单机 10 万 QPS 的配置秘籍
文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
Ingress Nginx性能调优配置方案
评论