如何構建高效能伺服器(以Nginx為例)
阿新 • • 發佈:2020-11-11
### 方法論
#### 軟體層面
##### 增大CPU利用率
- 使用全部CPU, worker程序數等於CPU
- 程序間不做無用的切換
- 繁忙時不主動讓出CPU
- worker程序之間不爭搶CPU
- CPU切換需要5us,如果大量程序需要切換,則CPU會浪費大量的時間切換,做無用功
- worker程序繫結CPU
> pidstat -w可以檢視某個程序的切換次數
- 不被其他程序搶佔資源
- 提高程序優先順序,獲得更大的CPU時間片
- 減少其他程序
- 減少驚群
場景:多個worker程序accept同一個埠時
- 預設accept_mutex on
多個worker程序爭搶鎖獲得連線,同時只有一個worker獲得連線
- accept_mutex off
一個連線請求喚醒所有worker程序,同時只有一個worker獲得連線,存在驚群問題,當worker程序數不多時,影響不大,少了爭鎖,高併發時可以提高系統響應能力
- SO_REUSEPORT
核心3.9+處理大併發連線新特性,開啟後,連線通過核心分配worker程序,效能最好
- 提高CPU快取命中率
繫結worker到指定CPU: worker_cpu_affinity cpumask...
##### 增大記憶體利用率
- 使用tcmalloc
減少記憶體碎片
併發能力高於glibc,併發數越多,效能越能體現(小記憶體分配)
google-perftools/.../tcmalloc.html
需要手動編譯到nginx
##### 增大IO利用率
- 對比
機械硬碟
- 價格低
- 儲存量大
- BPS大,適合順序讀寫
- IOPS小,不適合隨機讀寫
- 壽命長
固態應胖
- 價格高
- 儲存量小
- BPS大
- IOPS大
- 寫壽命短
- 優化讀取
- sendfile零拷貝
檔案直接從核心態的檔案到socket的傳遞
```
location /video/{
sendfile on;
aio on;
directio 8m;
}
```
- gzip_static
提前壓縮檔案,加快gzip報文的返回
- 記憶體盤/SSD盤
- 減少寫入
- empty_gif
使用返回一張1*1的空白圖片,以減少http的返回報文長度
- AIO
在磁碟讀寫時,程序可以處理其他事情
aio on|off|threads=[pool]
- 直接IO,減少一次快取的讀寫
directio size|off 超過size則使用直接io,適合大檔案
- 增大error_log級別
- error.log輸出到記憶體
error_log memory: 32m debug
日誌在32m的記憶體進行迴圈輸出,只能看到32m的除錯日誌,可以提高效能
- 關閉access_log
- 壓縮access_log
access_log path [format] [gzip]
- 是否開啟proxy buffering
- syslog替代本地io
使用UDP寫入代替io寫入,提高效能
- 執行緒池thread pool
當某些io會阻塞時,使用執行緒池
##### 增大網路寬頻利用率
- syn重試次數
net.ipv4.tcp_syn_retries = 6
- 本地埠可用範圍
net.ipv4.ip_local_port_range=32768 60999
可以放大
- 連線超時
proxy_connect_timeout
- 接收連線最大個數(syn未完成握手)
net.ipv4.tcp_max_syn_backlog = 262144
可以適當放大
- 已完成握手
net.core.somaxconn:系統最大backlog佇列長度
- 超出佇列可以接收報文直接回RST
net.ipv4.tcp_abort_on_overflow
- 未被核心處理的報文佇列長度
net.core.netdev_max_backlog
- syn/ack重試次數
net.ipv4.tcp_synack_retries
- 處理syn攻擊
net.ipv4.tcp_syncookies=1
> 當syn佇列滿後,新的syn不進入佇列,計算出cookie返回客戶端,客戶端攜帶cookie重新連線,伺服器驗證cookie,通過則建立連線。回導致TCP可選功能失效,例如擴充視窗/時間戳等
- 作業系統最大控制代碼
fs.file-max: 作業系統可以使用最大控制代碼數
使用fs.file-nr可以檢視當前已分配/正使用/上限
- 使用者最大控制代碼數
/etc/security/limits.conf
root soft nofile 63535
root har nofile 65535
- 程序限制最大控制代碼數
worker_rlimit_nofile number
- 程序最大連線數
worker_connections number
- Tcp Fast Open
當TCP再次連線時,通過攜帶cookie,減少一次syn/ack的rtt時間,達到快速建立TCP連線的目的
![nginxperformace-tfo](http://upload-images.jianshu.io/upload_images/24077087-868e65652b7fd562.PNG)
net.ipv4.tcp_fastopen 0|1|2|3
listen address [:port] [fastopen=number];
> fastopen=number為了防止帶資料的syn攻擊,限制最大長度,指定TFO連線佇列的最大長度
- TCP緩衝區
net.ipv4.tcp_rmen = 4096 87380 6291456
net.ipv4.tcp_wmen = 4096 87380 6291456
net.ipv4.tcp_men = 1541646 2055528 3083292
net.ipv4.tcp_moderate_rcvbuf=1開啟自動調節快取模式
listen address [:port] [recvbuf=size] [sndbuf=size]
net.ipv4.tcp_adv_win_scale = 1
應用快取 = buffer / (2^tcp_adv_win_scale)
接收視窗 = buffer - buffer/(2^tcp_adv_win_scale)
BDP = 頻寬* RTT/2
buffer=BDP
- Nagle演算法
網路中只存在一個未被確認的小報文ACK
目的:避免一個連線上存在大量的小報文,提高網路利用率
吞吐量優先:啟用Nagle tcp_nodelay off
低延時優先:禁用Nagle tcp_nodelay on
- 擁塞視窗
實際流量=擁塞視窗和接收視窗的最小值
- 慢啟動
指數擴充套件擁塞視窗cwnd = cwnd*2
- 擁塞避免
視窗大於threshold線性增大
- 擁塞發生
發生丟包,
RTO超時,threshold = cwnd/2, cwnd=1
Fast Retransmit: cwnd=cwnd/2, threshold=cwnd
- 快速恢復
當Fast Retransmit出現時,cwnd調整為threshold+3*MSS
- 優化慢啟動
增大初始cwnd=10
- TCP keep-alive
開啟keepalive可以探測到失去連線的socket,並即時關閉,節省系統資源
net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_keepalive_probes = 9
- timewait
net.ipv4.tcp_orphan_retries = 0
net.ipv4.tcp_fin_timeout = 60
net.ipv4.tcp_max_tw_buckets = 262144 最大timewait連線數,超出直接關閉連線
- lingering_close延遲關閉
當接收緩衝依然接收到客戶端的內容,伺服器如果馬上傳送RST關閉連線,會導致客戶端由於接收到RST而忽略http response
lingering_close off|on|always
reset_timedout_connection on|off; 當讀寫超時生效依法連線關閉,通過傳送RST馬上關閉連線,以釋放資源
- TLS/SLL優化握手
ssl_session_cache
- TLS/SSL會話票證tickets
Nginx將會話session中的資訊作為tickets加密傳送給客戶端,當客戶端再次建立連線時帶上tickets,Nignx驗證複用session
優點可以減少對稱加解密的次數,提高效能
缺點降低安全性,需要經常更換tickets金鑰
ssl_seesion_tickets on|off
ssl_session_ticket_key file
- 使用HTTP長連線
keepalive_request number;
- gzip壓縮
提高網路傳輸效率
gzip on|off
- 使用http2
##### 統計函式呼叫統計
google-perltool
pprof --text|pdf
goodle_perftools_profiles file
#### 硬體
- 網絡卡:萬兆網絡卡,例如10G/25G/40G
- 磁碟:固態硬碟,關注IOPS/BPS指標
- CPU:更快的主頻,更大的快取,更優的架構
- 記憶體:更快的訪問速度
#