在Kubernetes集群中,Ingress对集群服务(Service)中外部可访问的API对象进行管理,提供七层负载均衡能力。Nginx Ingress Controller负责实现Ingress的功能,根据规则配置负载均衡并提供访问入口。在高负载场景下,CPU资源和网络连接数的不足会影响应用的性能。本文介绍如何通过部署Nginx Ingress Controller来支撑高负载应用。
前提条件
已确保ACK集群中的Nginx Ingress Controller组件运行正常。
已通过kubectl连接集群。具体操作,请参见通过kubectl连接Kubernetes集群。
部署说明
部署高负载场景下的Nginx Ingress Controller需要考虑以下三个方面。
硬件选型
在高并发场景下,Ingress对CPU资源和网络连接数占用都非常高,建议您选择增强型ECS实例,例如:
计算型实例:ecs.c6e.8xlarge(32 Core 64 GB,600万PPS)
网络型实例:ecs.g6e.8xlarge(32 Core 128 GB,600万PPS)
关于ECS实例规格的更多信息,请参见实例规格族。
K8s配置
设置Ingress Pod独占节点资源,添加污点和节点标签:
kubectl label nodes $node_name ingress-pod="yes" kubectl taint nodes $node_name ingress-pod="yes":NoExecute
设置CPU Policy为
static
。推荐调整ingress-controller service对应的SLB规格为超强型(slb.s3.large)。
推荐集群使用Terway网络插件及配置独占ENI。
Ingress配置
设置Ingress Pod为Guaranteed类型。
设置nginx-ingress-controller container的资源限制
requests
和limits
:30Core 40GiB。设置initContainer init-sysctl的资源限制
requests
和limits
:100m 70MiB。
调整Deployment Replicas数为新增节点数。
设置ConfigMap的
worker-processes
数为28(预留部分给系统使用)。调整ConfigMap的
keepalive
链接最大请求数。关闭日志访问记录。
步骤一:添加节点
选择指定集群,创建新的节点池并添加2台节点。
创建节点池需要配置的主要参数如下所示。具体操作,请参见创建和管理节点池。
选择操作系统为Alibaba Cloud Linux3。
配置节点标签和污点(Taints)。
设置污点(Taints)为
ingress-pod
,值为yes
,Effect为NoExecute。设置节点标签为
ingress-pod
值为yes
。
选择CPU Policy为Static。
步骤二:配置Nginx Ingress Controller
执行kubectl edit deploy nginx-ingress-controller -n kube-system
命令打开Ingress Controller的配置文件,根据以下内容更新Ingress Controller的配置:
删除Pod反亲和性配置。
podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - ingress-nginx topologyKey: kubernetes.io/hostname
配置InitContainer的
requests
和limits
。resources: limits: cpu: 100m memory: 70Mi requests: cpu: 100m memory: 70Mi
修改nginx-ingress-controller container的
requests
和limits
都为30Core 40GiB。resources: limits: cpu: "30" memory: 40Gi requests: cpu: "30" memory: 40Gi
设置节点亲和性和容忍性。
nodeSelector: ingress-pod: "yes" tolerations: - effect: NoExecute key: ingress-pod operator: Equal value: "yes"
调整Replicas数为新增节点数。
关闭Metrics采集,修改启动参数,添加
--enable-metrics=false
。说明如果不需要获取Metrics信息,建议关闭Metrics采集。对于v1.9.3以上版本的Nginx Ingress Controller,您还可以通过配置启动参数
--exclude-socket-metrics
来排除相关的指标, 例如nginx_ingress_controller_ingress_upstream_latency_seconds
。这样做可以帮助减轻对系统性能的影响。containers: - args: - /nginx-ingress-controller - --configmap=$(POD_NAMESPACE)/nginx-configuration - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services - --udp-services-configmap=$(POD_NAMESPACE)/udp-services - --annotations-prefix=nginx.ingress.kubernetes.io - --publish-service=$(POD_NAMESPACE)/nginx-ingress-lb - --enable-metrics=false - --v=1
步骤三:配置Nginx Ingress ConfigMap
使用
kubectl edit cm -n kube-system nginx-configuration
更新ConfigMap,可参考以下代码示例:apiVersion: v1 kind: ConfigMap metadata: name: nginx-configuration namespace: kube-system data: allow-backend-server-header: "true" enable-underscores-in-headers: "true" generate-request-id: "true" ignore-invalid-headers: "true" log-format-upstream: $remote_addr - [$remote_addr] - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_length $request_time [$proxy_upstream_name] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status $req_id $host [$proxy_alternative_upstream_name] max-worker-connections: "65536" proxy-body-size: 20m proxy-connect-timeout: "3" proxy-read-timeout: "5" proxy-send-timeout: "5" reuse-port: "true" server-tokens: "false" ssl-redirect: "false" upstream-keepalive-timeout: "900" worker-processes: "28" # 设置启动的Nginx进程数,请根据您的node节点规格进行实际调整,建议调整为cpu核数-2。 worker-cpu-affinity: auto upstream-keepalive-connections: "300" upstream-keepalive-requests: "1000" # 设置单个长连接最多可以发送多个。 keep-alive: "900" keep-alive-requests: "10000"
采用文件方式记录访问日志并对日志轮转。
默认的日志访问记录输出到/dev/stdout,在高并发场景下,会占用大量CPU,故采用文件方式记录访问日志并对日志设置轮转。
以SSH方式登录部署ingress-controller Pod的ECS节点。具体操作,请参见通过密钥认证登录Linux实例。
在/etc/crontab文件结尾添加以下内容:
*/15 * * * * root /root/nginx-log-rotate.sh
说明此处以每隔15分钟对日志轮转一次为例,可根据实际需求进行调整。
在/root目录下添加文件nginx-log-rotate.sh。
Docker集群
#!/bin/bash # 最多保留日志文件个数,可根据需求进行调整。 keep_log_num=5 ingress_nginx_container_ids=$(docker ps | grep nginx-ingress-controller | grep -v pause | awk '{print $1}') if [[ -z "$ingress_nginx_container_ids" ]]; then echo "error: failed to get ingress nginx container ids" exit 1 fi # 随机睡眠5~10秒。 sleep $(( RANDOM % (10 - 5 + 1 ) + 5 )) for id in $ingress_nginx_container_ids; do docker exec $id bash -c "cd /var/log/nginx; if [[ \$(ls access.log-* | wc -l) -gt $keep_log_num ]]; then rm -f \$(ls -t access.log-* | tail -1); fi ; mv access.log access.log-\$(date +%F:%T) ; kill -USR1 \$(cat /tmp/nginx/nginx.pid)" done
containerd集群
#!/bin/bash # 最多保留日志文件个数,可根据需求进行调整。 keep_log_num=5 ingress_nginx_container_ids=$(crictl ps | grep nginx-ingress-controller | grep -v pause | awk '{print $1}') if [[ -z "$ingress_nginx_container_ids" ]]; then echo "error: failed to get ingress nginx container ids" exit 1 fi # 随机睡眠5~10秒。 sleep $(( RANDOM % (10 - 5 + 1 ) + 5 )) for id in $ingress_nginx_container_ids; do crictl exec $id bash -c "cd /var/log/nginx; if [[ \$(ls access.log-* | wc -l) -gt $keep_log_num ]]; then rm -f \$(ls -t access.log-* | tail -1); fi ; mv access.log access.log-\$(date +%F:%T) ; kill -USR1 \$(cat /tmp/nginx/nginx.pid)" done
执行以下命令,对nginx-log-rotate.sh文件添加可执行权限。
chmod 755 /root/nginx-log-rotate.sh
步骤四: 可选配置调优
以下为内核相关参数、应用设置、压缩功能和HTTPS性能优化的建议配置。
内核相关参数调优
在对内核参数进行调优之前,务必确保对这些参数有深刻的理解,并慎重操作。
调整TIME_WAIT
为了优化Nginx Ingress的性能,可以通过调整系统参数来开启TIME_WAIT复用,并减少FIN_WAIT2和TIME_WAIT状态的超时时间。
net.ipv4.tcp_fin_timeout=15
:减少FIN_WAIT2状态的超时时间,以更快释放连接资源。net.netfilter.nf_conntrack_tcp_timeout_time_wait=30
:缩短TIME_WAIT状态下的连接保持时间,加速资源释放。
配置操作
通过以下命令编辑Nginx Ingress Controller的Deployment。
kubectl edit deployments -n kube-system nginx-ingress-controller
在
init container
部分新增sysctl -w net.ipv4.tcp_fin_timeout=15
和sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30
参数,保存并退出。initContainers: - command: # 新增sysctl -w net.ipv4.tcp_fin_timeout=15和sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30参数。 - /bin/sh - -c - | if [ "$POD_IP" != "$HOST_IP" ]; then mount -o remount rw /proc/sys sysctl -w net.core.somaxconn=65535 sysctl -w net.ipv4.ip_local_port_range="1024 65535" sysctl -w kernel.core_uses_pid=0 sysctl -w net.ipv4.tcp_fin_timeout=15 sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30 fi
应用层配置调优
您可以通过以下命令和配置对业务从应用层面配置调优。
使用以下命令编辑Nginx Ingress Controller的ConfigMap。
kubectl edit cm -n kube-system nginx-configuration
根据下述配置参数,结合您的实际业务场景进行配置调优。
配置项
配置参数
描述
下游
keepalive
keep-alive: "60"
指定
keepalive
连接的超时时间,单位为秒。keep-alive-requests: "10000"
指定
keepalive
请求的最大数量。上游
keepalive
upstream-keepalive-connections: "1000"
最大
keepalive
连接数。upstream-keepalive-requests: "2147483647"
允许的最大
keepalive
请求数。upstream-keepalive-time: 1h
上游
keepalive
连接的最大保持时间。upstream-keepalive-timeout: "150"
指定上游
keepalive
连接的空闲超时时间,单位为秒。单个Worker最大连接
max-worker-connections: "65536"
单个Worker支持的最大连接数。
超时配置
说明可根据实际业务场景调整,按需配置。
proxy-connect-timeout: "3"
建立TCP连接的超时时间,单位为秒。
proxy-read-timeout: "5"
读取数据的超时时间,单位为秒。
proxy-send-timeout: "5"
发送数据的超时时间,单位为秒。
优化重试机制
说明当后端服务异常情况下,多级重试的过多请求可能加重后端服务的负载引发雪崩问题。更多详情请参见Ingress-nginx官方文档。
proxy-next-upstream-tries:"3"
失败后的重试次数,默认为3次,包括1次初始请求和2次重试。
proxy-next-upstream:"off"
指定重试条件,设置为off则关闭重试功能。
proxy-next-upstream-timeout
指定请求重试的超时时间,单位为秒,根据实际应用场景进行调整。
启用Brotli压缩
压缩是一种通过牺牲CPU时间来节省大量网络带宽的通用方法,能够提升吞吐量。Brotli是Google开发的一种压缩算法。相较于常用的
gzip
压缩算法(Nginx Ingress Controller默认使用gzip
),Brotli的压缩率据称要高出20%~30%。Ingress-nginx中启用Brotli压缩,需要配置以下参数,更多详情请参见Ingress-nginx官方文档。enable-brotli
: 是否启用Brotli压缩算法,取值为true
或false
。brotli-level
: 压缩级别,范围是1到11,默认是4。级别越高,CPU性能消耗越大。brotli-types
: 指定使用Brotli即时压缩的MIME类型。
您可以使用以下命令启用Brotli压缩。
kubectl edit cm -n kube-system nginx-configuration
配置示例:
enable-brotli: "true" brotli-level: "6" brotli-types: "text/xml image/svg+xml application/x-font-ttf image/vnd.microsoft.icon application/x-font-opentype application/json font/eot application/vnd.ms-fontobject application/javascript font/otf application/xml application/xhtml+xml text/javascript application/x-javascript text/plain application/x-font-truetype application/xml+rss image/x-icon font/opentype text/css image/x-win-bitmap"
HTTPS性能优化
为了提升HTTPS的性能,可以使用
kubectl edit cm -n kube-system nginx-configuration
命令编辑ConfigMap,并配置以下参数:SSL 会话缓存、OCSP Stapling、TLS 1.3 早期数据以及调整密码套件优先级。SSL会话缓存与超时
设置SSL 共享会话缓存的大小以及重用缓存中存储的会话参数的时间,可以减少SSL握手的开销。
ConfigMap配置:
ssl-session-cache-size:"10m" ssl-session-timeout:"10m"
对应Nginx侧的
nginx.conf
配置,可以根据实际场景需求调整。ssl_session_cache shared:SSL:120m; # 1m 4000个。 ssl_session_timeout 1h; # 会话超时时间为1小时。
启用OCSP Stapling
使用OCSP Stapling可以减少客户端证书验证的时间。
enable-ocsp: "true"
支持TLS 1.3早期数据(0-RTT)
启用TLS 1.3的0-RTT功能可以允许客户端在握手完成之前就发送数据,从而减少连接建立的延迟。
ssl-early-data: "true" ssl-protocols: "TLSv1.3"
调整Cipher优先级(无需手动调优)
通过调整加密套件的优先级,可以有效降低延迟。Nginx Ingress Controller的默认配置已进行了优化。
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384'; ssl_prefer_server_ciphers on; # 优先使用服务器端的Cipher配置。