背景
小米容器雲平台,在構建雲廠商集群時,需要通過HAProxy將雲廠商LB流量從宿主機轉到容器中,但對於HAProxy的性能沒有把握。參考網上的一篇HAProxy壓測文章,文章中提到HAProxy establish狀態連接可以達到 400w,所以以此為目標,進行壓測。
參考文章:文章地址
關鍵點
TCP計數器ListenOverflows大量增加
查看方法
cat /proc/net/netstat | awk '/TcpExt/ { print $21,$22 }'
原因
系統調用listen函數(int listen(int sockfd, int backlog);)的隊列長度由min(backlog ,內核參數 net.core.somaxconn ) 決定,對應socket的listen 隊列已滿的情況下,在新增一個連接時的情況,ListenOverflows計數器加 1 。
解決方案
調整系統參數 net.core.somaxconn = 65535 #默認為128
HAProxy 耗盡cpu問題
現象
HAProxy綁定4核cpu、8核cpu、16核cpu,壓測的時候,都會出現CPU 100%被使用的情況。
追查過程
1. 通過 mpstat -P ALL 1 命令查看cpu 都用在哪里,可以看到cpu都絕大部分用在 sys態上。
2. 通過 strace -p pid -c 查看HAProxy 進程那個系統調用占用cpu 最多,看到cpu 都用在了 connect系統調用上。
3. HAProxy連接后端會使用connect系統調用,查看HAProxy配置,發現HAProxy連接后端就只有兩個后端,即這種情況: vegeta(40台壓測機器)-》HAProxy-》httptest(2台HAProxy后端),其中 HAProxy連接后端最多只能有63000個端口左右,大量的連接積壓在HAProxy機器上,導致cpu被耗盡了。
解決方案
大量增加HAProxy的后端,解決HAProxy后端過少的瓶頸。
網卡 drop 數據包
現象
壓測的時候,ifconfig發現網卡eth0 RX 出現 droppped。
解決方案
1. 調大網卡Ring buffer
查看:ethtool -g eth0
設置Ring buffer到上限:ethtool -G eth0 rx 4096;ethtool -G eth0 tx 4096
2. 調網卡隊緩存隊列
net.core.netdev_max_backlog = 2000000 #默認為1000,內核參數配置時,有具體的解釋
最新穩定版HAProxy性能
系統自帶版本 1.5.18
編譯HAProxy 最新穩定版本(1.7.5 )
wget http://www.haproxy.org/download/1.7/src/haproxy-1.7.5.tar.gz
tar -xzvf haproxy-1.7.5.tar.gz
cd haproxy-1.7.5/
make TARGET=linux2628 USE_CPU_AFFINITY=1
壓測時資源使用情況
mem:
最新新版:10G
系統自帶版本:102G,由於內存不夠,使用了swap,
引起cpu iowait占大量增加,導致cpu idle為0。
cpu idle:
最新新版:35%
系統自帶版本:0%
結論
相同壓力下,新版HAProxy使用內存大量減少。
環境搭建
HAProxy
機器
1台,24 cpu、128G內存的i1 機器
系統版本
centos 7.2
安裝系統自帶HAProxy:yum install haproxy
sysctl.conf 配置
### 系統中所允許的文件句柄的最大數目
fs.file-max = 12553500
### 單個進程所允許的文件句柄的最大數目
fs.nr_open = 12453500
### 內核允許使用的共享內存大 Controls the maximum number of shared memory segments, in pages
kernel.shmall = 4294967296
###單個共享內存段的最大值 Controls the maximum shared segment size, in bytes
kernel.shmmax = 68719476736
### 內核中消息隊列中消息的最大值 Controls the maximum size of a message, in bytes
kernel.msgmax = 65536
### 系統救援工具
kernel.sysrq = 0
### 在每個網絡接口接收數據包的速率比內核處理這些包的速率快時,允許送到緩存隊列的數據包的最大數目
net.core.netdev_max_backlog = 2000000
### 默認的TCP數據接收窗口大小(字節)
net.core.rmem_default = 699040
### 最大的TCP數據接收窗口(字節)
net.core.rmem_max = 50331648
### 默認的TCP數據發送窗口大小(字節)
net.core.wmem_default = 131072
### 最大的TCP數據發送窗口(字節)
net.core.wmem_max = 33554432
### 定義了系統中每一個端口最大的監聽隊列的長度,這是個全局的參數
net.core.somaxconn = 65535
### TCP/UDP協議允許使用的本地端口號
net.ipv4.ip_local_port_range = 15000 65000
net.ipv4.ip_nonlocal_bind = 1
### 對於本端斷開的socket連接,TCP保持在FIN-WAIT-2狀態的時間(秒)
net.ipv4.tcp_fin_timeout = 7
### TCP發送keepalive探測消息的間隔時間(秒),用於確認TCP連接是否有效
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_max_orphans = 3276800
### 對於還未獲得對方確認的連接請求,可保存在隊列中的最大數目
net.ipv4.tcp_max_syn_backlog = 655360
net.ipv4.tcp_max_tw_buckets = 6000000
### 確定TCP棧應該如何反映內存使用,每個值的單位都是內存頁(通常是4KB)
### 第一個值是內存使用的下限;第二個值是內存壓力模式開始對緩沖區使用應用壓力的上限;第三個值是內存使用的上限.
net.ipv4.tcp_mem = 94500000 915000000 927000000
### 為自動調優定義socket使用的內存。
### 第一個值是為socket接收緩沖區分配的最少字節數;
### 第二個值是默認值(該值會被rmem_default覆蓋),緩沖區在系統負載不重的情況下可以增長到這個值;
### 第三個值是接收緩沖區空間的最大字節數(該值會被rmem_max覆蓋)
net.ipv4.tcp_rmem = 32768 699040 50331648
### 為自動調優定義socket使用的內存。
### 第一個值是為socket發送緩沖區分配的最少字節數;
### 第二個值是默認值(該值會被wmem_default覆蓋),緩沖區在系統負載不重的情況下可以增長到這個值;
### 第三個值是發送緩沖區空間的最大字節數(該值會被wmem_max覆蓋)
net.ipv4.tcp_wmem = 32768 131072 33554432
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_synack_retries = 2
### 表示是否打開TCP同步標簽(syncookie),同步標簽可以防止一個套接字在有過多試圖連接到達時引起過載
### 內核必須打開了CONFIG_SYN_COOKIES項進行編譯,
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_syn_retries = 2
### 表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉
net.ipv4.tcp_tw_recycle = 1
### 允許將TIME-WAIT sockets重新用於新的TCP連接,默認為0,表示關閉
net.ipv4.tcp_tw_reuse = 1
### 啟用RFC 1323定義的window scaling,要支持超過64KB的TCP窗口,必須啟用該值(1表示啟用),
### TCP窗口最大至1GB,TCP連接雙方都啟用時才生效,默認為1
net.ipv4.tcp_window_scaling = 1
### 最大限度使用物理內存
vm.swappiness = 0
HAProxy配置
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 600s
user haproxy
group haproxy
daemon
#tune.ssl.default-dh-param 2048
maxconn 4000000
nbproc 23
cpu-map 1 1
cpu-map 2 2
cpu-map 3 3
cpu-map 4 4
cpu-map 5 5
cpu-map 6 6
cpu-map 7 7
cpu-map 8 8
cpu-map 9 9
cpu-map 10 10
cpu-map 11 11
cpu-map 12 12
cpu-map 13 13
cpu-map 14 14
cpu-map 15 15
cpu-map 16 16
cpu-map 17 17
cpu-map 18 18
cpu-map 19 19
cpu-map 20 20
cpu-map 21 21
cpu-map 22 22
cpu-map 23 23
stats bind-process 23
defaults
log global
mode tcp
option tcplog
option dontlognull
maxconn 4000000
timeout connect 5000
timeout client 60000
timeout server 60000
# Template Customization
frontend http-in
bind :8200
stats enable
mode http
option httplog
stats auth admin:admin
stats uri /haproxy_stats
listen port-30000
bind :30000
mode tcp
option tcplog
balance roundrobin
server staging1 ……
……
HAProxy后端服務
機器
10台,8 cpu、32G內存的3U8機器
系統版本
centos 7.2
程序
簡寫一個API server
壓測機器
機器
80台,8/32 cpu,32/128G內存的機器,機器配置不好統一,所以用80台機器做壓測,解決壓測端性能、內核參數機器參差不齊的問題。
程序
vegeta https://github.com/tsenart/vegeta
總結
壓測效果復合預期
壓測效果基本符合預期,最終establish狀態連接達到696W,占用10G內存,CPU使用66%(暫時沒有ssl需求,所以沒有壓測ssl卸載),具體如圖:
關鍵知識點
TCP連接, srcIp:srcPort -》 dstIp:dstPort srcPort最多63k,並發流量超過63k的時候,應用進程會占用大量cpu。注意壓測機器,同樣受此限制。