Nginx Ingress 高併發實踐

概述

Nginx Ingress Controller 基於 Nginx 實現了 Kubernetes Ingress API,Nginx 是公認的高性能網關,但若是不對其進行一些參數調優,就不能充分發揮出高性能的優點。以前咱們在 Nginx Ingress on TKE 部署最佳實踐 一文中講了 Nginx Ingress 在 TKE 上部署最佳實踐,涉及的部署 YAML 其實已經包含了一些性能方面的參數優化,只是沒有說起,本文將繼續展開介紹針對 Nginx Ingress 的一些全局配置與內核參數調優的建議,可用於支撐咱們的高併發業務。html

內核參數調優

咱們先看下如何對 Nginx Ingress 進行內核參數調優,設置內核參數的方法能夠用 initContainers 的方式,後面會有示例。linux

調大鏈接隊列的大小

進程監聽的 socket 的鏈接隊列最大的大小受限於內核參數 net.core.somaxconn,在高併發環境下,若是隊列太小,可能致使隊列溢出,使得鏈接部分鏈接沒法創建。要調大 Nginx Ingress 的鏈接隊列,只須要調整 somaxconn 內核參數的值便可,但我想跟你分享下這背後的相關原理。nginx

進程調用 listen 系統調用來監聽端口的時候,還會傳入一個 backlog 的參數,這個參數決定 socket 的鏈接隊列大小,其值不得大於 somaxconn 的取值。Go 程序標準庫在 listen 時,默認直接讀取 somaxconn 做爲隊列大小,但 Nginx 監聽 socket 時沒有讀取 somaxconn,而是有本身單獨的參數配置。在 nginx.conf 中 listen 端口的位置,還有個叫 backlog 參數能夠設置,它會決定 nginx listen 的端口的鏈接隊列大小。git

server {
    listen  80  backlog=1024;
    ...

若是不設置,backlog 在 linux 上默認爲 511:github

backlog=number
   sets the backlog parameter in the listen() call that limits the maximum length for the queue of pending connections. By default, backlog is set to -1 on FreeBSD, DragonFly BSD, and macOS, and to 511 on other platforms.

也就是說,即使你的 somaxconn 配的很高,nginx 所監聽端口的鏈接隊列最大卻也只有 511,高併發場景下可能致使鏈接隊列溢出。api

不過這個在 Nginx Ingress 這裏狀況又不太同樣,由於 Nginx Ingress Controller 會自動讀取 somaxconn 的值做爲 backlog 參數寫到生成的 nginx.conf 中: https://github.com/kubernetes/ingress-nginx/blob/controller-v0.34.1/internal/ingress/controller/nginx.go#L592性能優化

也就是說,Nginx Ingress 的鏈接隊列大小隻取決於 somaxconn 的大小,這個值在 TKE 默認爲 4096,建議給 Nginx Ingress 設爲 65535: sysctl -w net.core.somaxconn=65535併發

擴大源端口範圍

高併發場景會致使 Nginx Ingress 使用大量源端口與 upstream 創建鏈接,源端口範圍從 net.ipv4.ip_local_port_range 這個內核參數中定義的區間隨機選取,在高併發環境下,端口範圍小容易致使源端口耗盡,使得部分鏈接異常。TKE 環境建立的 Pod 源端口範圍默認是 32768-60999,建議將其擴大,調整爲 1024-65535: sysctl -w net.ipv4.ip_local_port_range="1024 65535"socket

TIME_WAIT 複用

若是短鏈接併發量較高,它所在 netns 中 TIME_WAIT 狀態的鏈接就比較多,而 TIME_WAIT 鏈接默認要等 2MSL 時長才釋放,長時間佔用源端口,當這種狀態鏈接數量累積到超過必定量以後可能會致使沒法新建鏈接。tcp

因此建議給 Nginx Ingress 開啓 TIME_WAIT 重用,即容許將 TIME_WAIT 鏈接從新用於新的 TCP 鏈接: sysctl -w net.ipv4.tcp_tw_reuse=1

調大最大文件句柄數

Nginx 做爲反向代理,對於每一個請求,它會與 client 和 upstream server 分別創建一個鏈接,即佔據兩個文件句柄,因此理論上來講 Nginx 能同時處理的鏈接數最可能是系統最大文件句柄數限制的一半。

系統最大文件句柄數由 fs.file-max 這個內核參數來控制,TKE 默認值爲 838860,建議調大: sysctl -w fs.file-max=1048576

配置示例

給 Nginx Ingress Controller 的 Pod 添加 initContainers 來設置內核參數:

initContainers:
      - name: setsysctl
        image: busybox
        securityContext:
          privileged: true
        command:
        - sh
        - -c
        - |
          sysctl -w net.core.somaxconn=65535
          sysctl -w net.ipv4.ip_local_port_range="1024 65535"
          sysctl -w net.ipv4.tcp_tw_reuse=1
          sysctl -w fs.file-max=1048576

全局配置調優

除了內核參數須要調優,Nginx 自己的一些配置也須要進行調優,下面咱們來詳細看下。

調高 keepalive 鏈接最大請求數

Nginx 針對 client 和 upstream 的 keepalive 鏈接,均有 keepalive_requests 這個參數來控制單個 keepalive 鏈接的最大請求數,且默認值均爲 100。當一個 keepalive 鏈接中請求次數超過這個值時,就會斷開並從新創建鏈接。

若是是內網 Ingress,單個 client 的 QPS 可能較大,好比達到 10000 QPS,Nginx 就可能頻繁斷開跟 client 創建的 keepalive 鏈接,而後就會產生大量 TIME_WAIT 狀態鏈接。咱們應該儘可能避免產生大量 TIME_WAIT 鏈接,因此,建議這種高併發場景應該增大 Nginx 與 client 的 keepalive 鏈接的最大請求數量,在 Nginx Ingress 的配置對應 keep-alive-requests,能夠設置爲 10000,參考: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#keep-alive-requests

一樣的,Nginx 與 upstream 的 keepalive 鏈接的請求數量的配置是 upstream-keepalive-requests,參考: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#upstream-keepalive-requests

可是,通常狀況應該沒必要配此參數,若是將其調高,可能致使負載不均,由於 Nginx 與 upstream 保持的 keepalive 鏈接太久,致使鏈接發生調度的次數就少了,鏈接就過於 "固化",使得流量的負載不均衡。

調高 keepalive 最大空閒鏈接數

Nginx 針對 upstream 有個叫 keepalive 的配置,它不是 keepalive 超時時間,也不是 keepalive 最大鏈接數,而是 keepalive 最大空閒鏈接數。

它的默認值爲 32,在高併發下場景下會產生大量請求和鏈接,而現實世界中請求並非徹底均勻的,有些創建的鏈接可能會短暫空閒,而空閒鏈接數多了以後關閉空閒鏈接,就可能致使 Nginx 與 upstream 頻繁斷連和建連,引起 TIME_WAIT 飆升。在高併發場景下能夠調到 1000,參考:https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#upstream-keepalive-connections

調高單個 worker 最大鏈接數

max-worker-connections 控制每一個 worker 進程能夠打開的最大鏈接數,TKE 環境默認 16384,在高併發環境建議調高,好比設置到 65536,這樣可讓 nginx 擁有處理更多鏈接的能力,參考:https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#max-worker-connections

配置示例

Nginx 全局配置經過 configmap 配置(Nginx Ingress Controller 會 watch 並自動 reload 配置):

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-ingress-controller
# nginx ingress 性能優化: https://www.nginx.com/blog/tuning-nginx/
data:
  # nginx 與 client 保持的一個長鏈接能處理的請求數量,默認 100,高併發場景建議調高。
  # 參考: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#keep-alive-requests
  keep-alive-requests: "10000"
  # nginx 與 upstream 保持長鏈接的最大空閒鏈接數 (不是最大鏈接數),默認 32,在高併發下場景下調大,避免頻繁建聯致使 TIME_WAIT 飆升。
  # 參考: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#upstream-keepalive-connections
  upstream-keepalive-connections: "200"
  # 每一個 worker 進程能夠打開的最大鏈接數,默認 16384。
  # 參考: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#max-worker-connections
  max-worker-connections: "65536"

總結

本文分享了對 Nginx Ingress 進行性能調優的方法及其原理的解釋,包括內核參數與 Nginx 自己的配置調優,更好的適配高併發的業務場景,但願對你們有所幫助。

參考資料

【騰訊雲原生】雲說新品、雲研新術、雲遊新活、雲賞資訊,掃碼關注同名公衆號,及時獲取更多幹貨!!

相關文章
相關標籤/搜索