部署高负载场景的Nginx Ingress Controller

如果您的Nginx Ingress Controller经常面临高负载,可以从集群网络插件、节点规格和Controller配置等方面进行调整以提高性能。本文介绍如何配置高性能Nginx Ingress Controller。

重要

本文中的配置方法仅供您参考思路,具体是否使用某个配置,以及各项参数与规格的选择,请您实际结合Controller负载进行选择。

容器网络插件

集群的容器网络插件(CNI Plugin)配置会影响集群内网络通信性能,进而影响Nginx Ingress Controller的性能表现。推荐您使用Terway作为容器网络插件。如果您对网络性能有更高要求,可以考虑使用Terway独占ENI模式,但该模式会导致单节点Pod上限较少。关于Terway的更多信息,请参见使用Terway网络插件

节点规格选择

Nginx Ingress Controller所属Pod的网络性能受节点规格限制。例如,节点PPS30万时,ControllerPodPPS上限即为30万。建议选择以下高性能ECS规格:

  • 计算型实例:ecs.c6e.8xlarge(3264GB,600PPS)

  • 网络型实例:ecs.g6e.8xlarge(32128GB,600PPS)

关于ECS实例规格的更多信息,请参见实例规格族

Nginx Ingress Controller组件配置

负载均衡实例规格

Nginx Ingress Controller使用一个CLB实例对外接收请求,CLB实例的规格会影响Controller的性能。您可在Nginx Ingress Controller所属的Service中使用Annotations指定CLB规格。

编辑负载均衡实例规格

  1. 执行以下命令,编辑Nginx Ingress Controller所属Service。

    kubectl edit service -n kube-system nginx-ingress-lb
  2. Service中添加service.beta.kubernetes.io/alibaba-cloud-loadbalancer-specAnnotation。

    apiVersion: v1
    kind: Service
    metadata:
      annotations:
        ...
        service.beta.kubernetes.io/alibaba-cloud-loadbalancer-spec: "slb.s3.large" # 指定CLB规格
      name: nginx-ingress-lb
      namespace: kube-system
      ...
    spec:
      ...
    
    重要

    CLB规格的性能与计费,请参见实例规格。更高规格的实例会产生更多费用。

Pod独占节点

由于Nginx的基础开销,在资源总量相同的情况下,单个高规格Pod(例如32核)的性能表现优于多个低规格Pod(例如两个16核的Pod)。因此,在保证高可用的前提下,您可使用少量高规格Pod而不是多个更低规格的Pod。

例如,您可创建一个高规格但仅有少量节点的节点池,并通过污点与容忍度配置使其中的每个节点被单个Controller Pod独占。这样的部署方式可以使Nginx Ingress Controller最大化利用资源,并且不受集群内其他应用的影响。

配置Controller Pod独占节点示例

  1. 在集群中创建一个新的节点池,并为节点池选择下列配置。具体操作,请参见创建和管理节点池

    • 选择期望节点数3。

    • 选择操作系统Alibaba Cloud Linux 3

    • 配置节点标签污点(Taints)

      • 污点(Taints)中添加ingress-podyesEffectNoExecute

      • 节点标签中添加ingress-nodeyes

    • 选择CPU PolicyStatic

  2. 执行以下命令,编辑Controller所属的Deployment。

    kubectl edit deploy nginx-ingress-controller -n kube-system
  3. Deployment进行如下更改:

    1. 设置replicas3,与节点池的节点数相同。

      spec:
        replicas: 3
    2. nginx-ingress-controller containerrequestslimits进行修改,设置CPU32核,内存为64G。

      containers:
        - args:
          ...
          resources:
            limits:
              cpu: "32"
              memory: 64Gi
            requests:
              cpu: "32"
              memory: 64Gi
    3. 设置节点亲和性和容忍性,使Pod只会调度到拥有ingress-node:yes标签的节点上,并可以容忍ingress-pod:yes污点。

      nodeSelector:
        kubernetes.io/os: linux
        ingress-node: "yes"
      tolerations:
      - effect: NoExecute
        key: ingress-pod
        operator: Equal
        value: "yes"
    4. 请确保Deployment中有以下反亲和性配置,该配置保证每个节点最多有一个Nginx Ingress Controller Pod。

      podAntiAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchExpressions:
            - key: app
            operator: In
            values:
            - ingress-nginx
         topologyKey: kubernetes.io/hostname

关闭指标采集

Nginx Ingress Controller默认采集指标供其他组件使用,但采集消耗一定的CPU资源,如果不需要获取指标,建议关闭采集。通过在Nginx启动参数中添加--enable-metrics=false,即可关闭所有指标采集。

v1.9.3以上版本的Nginx Ingress Controller还添加了一些自定义指标采集参数。例如,添加--exclude-socket-metrics后,即可停止采集Socket相关指标。关于启动参数的更多信息,请参见cli-arguments

关闭Metrics采集

  1. 执行以下命令,编辑Controller所属的Deployment。

    kubectl edit deploy nginx-ingress-controller -n kube-system
  2. 在容器配置部分添加--enable-metrics=false配置,即可关闭所有指标采集。--exclude-socket-metrics则可以停止Socket相关指标采集。

    containers:
    - args:
      - ...
      - --enable-metrics=false
      - --exclude-socket-metrics # 在--enable-metrics=true时有效

调整超时策略

您可通过减少FIN_WAIT2TIME_WAIT状态的超时时间,使Nginx Ingress Controller更快地关闭已完成数据发送的连接,降低资源占用。

Nginx Ingress Controller中,相关的配置为:

  • net.ipv4.tcp_fin_timeout:FIN_WAIT2状态的超时时间,默认为60秒。

  • net.netfilter.nf_conntrack_tcp_timeout_time_wait:TIME_WAIT状态下的连接保持时间,默认为60秒。

重要

FIN_WAIT2TIME_WAIT是容器内核的配置,修改后会显著影响Nginx Ingress Controller的表现。如果您需要对此进行修改,请确保您已经了解TCP连接相关原理,并在修改后持续观察连接状态和资源使用情况,确保调整安全有效。

调整超时策略

  1. 执行以下命令,编辑Controller所属的Deployment。

    kubectl edit deploy nginx-ingress-controller -n kube-system
  2. initContainers中新增sysctl -w net.ipv4.tcp_fin_timeoutsysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait

    initContainers:
          - command:  
            - /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 # FIN_WAIT2状态上限设置为15秒
              sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30 # TIME_WAIT状态上限设置为30秒
              fi

ConfigMap配置

Nginx Ingress Controller的全局配置保存在ConfigMap中。您可执行以下命令,编辑ConfigMap。

kubectl edit cm -n kube-system nginx-configuration

配置项说明

ConfigMap中的关键配置项说明如下。

配置项

配置参数

描述

下游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

指定请求重试的超时时间,单位为秒,根据实际应用场景进行调整。

配置日志自动轮转

Nginx Ingress Controller Pod默认将日志记录到/dev/stdout。随着日志文件逐渐增大,记录新日志耗费的资源也会更多。通过定时轮转日志,即将一个时间段中的日志保存到独立文件中,并清除原有日志记录的方法,可降低记录日志的资源消耗。

  1. SSH方式登录部署Nginx Ingress Controller PodECS节点。具体操作,请参见通过密钥认证登录Linux实例

  2. /root目录下添加文件nginx-log-rotate.sh

    containerd节点

    #!/bin/bash
    # 最多保留日志文件个数,可根据需求进行调整。
    keep_log_num=5
    
    #获取所有运行中的ingress-nginx容器ID
    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	
    

    Docker节点

    #!/bin/bash
    # 最多保留日志文件个数,可根据需求进行调整。
    keep_log_num=5
    
    #获取所有运行中的ingress-nginx容器ID
    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	
    	
  3. 执行以下命令,对nginx-log-rotate.sh文件添加可执行权限。

    chmod 755 /root/nginx-log-rotate.sh
  4. /etc/crontab文件结尾添加以下内容:

    */15 * * * *  root /root/nginx-log-rotate.sh
    说明

    此示例使用Cron表达式,每15分钟对日志轮转一次,您可根据实际需求进行调整。

启用Brotli压缩

压缩是一种通过牺牲CPU时间来节省大量网络带宽的通用方法,能够提升吞吐量。BrotliGoogle开发的一种压缩算法。相较于常用的gzip压缩算法(Nginx Ingress Controller默认使用gzip),Brotli在文本类数据(如网页资源)上的压缩率通常比 gzip 高约 15%~30%,但具体提升取决场景的详细情况。在Nginx Ingress中启用Brotli压缩,需要配置以下参数。

  • enable-brotli: 是否启用Brotli压缩算法,取值为 true 或 false

  • brotli-level: 压缩级别,范围是111,默认是4。级别越高,CPU性能消耗越大。

  • brotli-types: 指定使用Brotli即时压缩的MIME类型。

您可通过在ConfigMap中添加以下配置启用Brotli压缩:

data:
  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性能优化

为了提升Nginx ingress ControllerHTTPS的性能,可以配置以下参数:SSL 会话缓存、OCSP Stapling、TLS 1.3 早期数据以及调整密码套件优先级。

  • SSL会话缓存与超时

    设置SSL 共享会话缓存的大小以及重用缓存中存储的会话参数的时间,可以减少SSL握手的开销。

    • ConfigMap配置:

      data:
        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可以减少客户端证书验证的时间。

    data:
      enable-ocsp: "true"
  • 支持TLS 1.3早期数据(0-RTT)

    启用TLS 1.30-RTT功能可以允许客户端在握手完成之前就发送数据,从而减少连接建立的延迟。

    data:
      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配置。