上週線上服務扛不住流量,運維羣裏一頓排查,最後發現是內核參數沒調。

默認配置跑個開發環境還行,生產環境就是在給自己挖坑。

把這次調優過程記錄一下,都是踩過的坑。

背景

我們有台服務器,配置不差:

  • 32核CPU
  • 64G內存
  • 萬兆網卡

但是一到高峯期,CPU才30%,連接數就上不去了,大量請求超時。

看了一圈監控,發現是網絡瓶頸,但網卡帶寬明明還有餘量。

問題定位

現象

# 查看連接狀態
ss -s
Total: 52341
TCP:   48234 (estab 12000, closed 35000, orphaned 0, timewait 34500)

# 發現大量TIME_WAIT
ss -ant | awk '{print $1}' | sort | uniq -c | sort -rn
  34523 TIME-WAIT
  12034 ESTAB
   1234 SYN-RECV
    423 LISTEN

3萬多個TIME_WAIT,正常嗎?

短連接場景下其實很常見,但這麼多確實有問題。

根因分析

# 查看當前內核參數
sysctl net.ipv4.tcp_max_tw_buckets
# 輸出:net.ipv4.tcp_max_tw_buckets = 180000

sysctl net.core.somaxconn
# 輸出:net.core.somaxconn = 128

sysctl net.ipv4.tcp_max_syn_backlog
# 輸出:net.ipv4.tcp_max_syn_backlog = 1024

問題找到了:

  • somaxconn 才128,這是監聽隊列的最大長度
  • tcp_max_syn_backlog 才1024,SYN隊列太小

高併發下,新連接進來排隊都排不下,直接被丟棄了。

調優方案

一、網絡連接相關

# /etc/sysctl.conf

# 1. 監聽隊列最大長度(默認128太小)
net.core.somaxconn = 65535

# 2. SYN隊列長度
net.ipv4.tcp_max_syn_backlog = 65535

# 3. 允許的最大跟蹤連接條目
net.netfilter.nf_conntrack_max = 1000000

# 4. TIME_WAIT狀態的socket數量(按需調整)
net.ipv4.tcp_max_tw_buckets = 200000

# 5. TIME_WAIT複用(僅限客户端發起連接時)
net.ipv4.tcp_tw_reuse = 1

# 6. 開啓SYN cookies防護
net.ipv4.tcp_syncookies = 1

# 7. 減少FIN_WAIT2狀態時間
net.ipv4.tcp_fin_timeout = 30

二、TCP緩衝區相關

# 接收緩衝區(最小、默認、最大)單位字節
net.ipv4.tcp_rmem = 4096 87380 16777216

# 發送緩衝區
net.ipv4.tcp_wmem = 4096 65536 16777216

# 系統級別的內存頁面分配
net.ipv4.tcp_mem = 786432 1048576 1572864

# 單個socket最大緩衝區
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216

三、文件描述符相關

# 系統級最大文件描述符
fs.file-max = 1000000

# 單進程最大文件描述符(需要配合ulimit)
# 在 /etc/security/limits.conf 中設置:
# *         soft    nofile      1000000
# *         hard    nofile      1000000

四、應用生效

# 臨時生效
sysctl -p

# 驗證
sysctl net.core.somaxconn
# 輸出:net.core.somaxconn = 65535

調優前後對比

壓測數據

用wrk壓測同一個接口:

wrk -t12 -c1000 -d60s http://localhost:8080/api/test

調優前:

Requests/sec:   8234.56
Latency:        avg 234ms, max 3.2s
Socket errors:  connect 3421, read 234, write 0, timeout 523

調優後:

Requests/sec:  23456.78
Latency:        avg 42ms, max 234ms
Socket errors:  connect 0, read 0, write 0, timeout 0

QPS從8000提升到23000,延遲從234ms降到42ms,錯誤歸零。

生產環境表現

高峯期同樣流量:

  • CPU使用率:從30%提升到65%(資源用起來了)
  • 連接錯誤率:從5%降到0.01%
  • P99延遲:從800ms降到120ms

常見場景參數模板

場景一:高併發Web服務

# 適合Nginx、Tomcat等Web服務器

net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 60
net.ipv4.tcp_keepalive_probes = 3

# Nginx還需要改配置
# worker_connections 65535;
# 並且在listen後加 backlog=65535

場景二:數據庫服務器

# 適合MySQL、PostgreSQL等

# 內存相關(根據實際內存調整)
vm.swappiness = 10
vm.dirty_ratio = 10
vm.dirty_background_ratio = 5

# 文件系統
fs.file-max = 1000000
fs.aio-max-nr = 1048576

# 網絡(數據庫通常連接數不會太高但要穩定)
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 4096

場景三:代理/網關服務

# 適合Nginx反向代理、API網關

# 代理需要大量連接,前端連接+後端連接
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535

# 端口範圍要大(代理會用很多端口連後端)
net.ipv4.ip_local_port_range = 1024 65535

# TIME_WAIT複用很重要
net.ipv4.tcp_tw_reuse = 1

# 連接跟蹤表要大
net.netfilter.nf_conntrack_max = 2000000
net.netfilter.nf_conntrack_tcp_timeout_established = 1200

一些坑

坑1:改了不生效

# 檢查是否真的改了
sysctl -a | grep somaxconn

# 如果是容器環境,宿主機和容器的參數是隔離的
# 部分參數需要在宿主機改

坑2:Nginx的backlog

改了系統參數,Nginx也要配合改:

server {
    listen 80 backlog=65535;
    # ...
}

不然Nginx用的還是默認值511。

坑3:改了參數服務起不來

# 有些參數相互依賴,比如
net.core.netdev_max_backlog = 65535
# 要配合網卡驅動支持,不然可能有問題

建議一個個改,改完驗證,別一次改一堆。

坑4:容器環境

Docker/K8s環境下:

  • 大部分網絡參數要在宿主機改
  • fs.file-max在容器裏可能改不了
  • 需要用--sysctl參數或者securityContext
# K8s Pod配置
spec:
  containers:
  - name: app
    securityContext:
      sysctls:
      - name: net.core.somaxconn
        value: "65535"

監控建議

調完參數不是結束,要持續監控:

# 連接狀態分佈
ss -ant | awk '{print $1}' | sort | uniq -c

# 丟包情況
netstat -s | grep -E "dropped|overflow"

# 連接跟蹤表使用情況
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max

寫個腳本定期採集,出問題才知道往哪查。

異地運維小技巧

我們有幾台服務器在異地機房,調參數的時候需要遠程操作。

之前用跳板機,現在用星空組網把幾台服務器組到一個虛擬網絡裏,直接SSH就能連,調參數方便多了。

總結

Linux內核參數調優核心就幾個方向:

方向

關鍵參數

常見問題

監聽隊列

somaxconn, tcp_max_syn_backlog

高併發連接失敗

TIME_WAIT

tcp_tw_reuse, tcp_fin_timeout

端口耗盡

緩衝區

tcp_rmem, tcp_wmem

大文件傳輸慢

連接跟蹤

nf_conntrack_max

防火牆導致丟包

文件描述符

file-max, nofile

too many open files

記住幾個原則:

  1. 先定位問題再調參數,別瞎調
  2. 改完要驗證,壓測或者灰度
  3. 留好回滾方案
  4. 持續監控,別調完就忘了

有內核調優經驗的歡迎評論區交流~