Nginx-性能優化

前言

Nginx 性能優化,主要是減少磁盤 io

  • 請求頭、請求體、響應體都在緩衝區操作。
  • 文件信息的讀取

另外一方面減少網絡 io。

  • gzip 壓縮。前端資源也可以提前進行 gzip 壓縮,這樣請求的時候就不用再壓縮了,減少對 cpu 的損耗。
  • 強緩存。減少對後端的靜態資源的請求。

http 鏈接的儘快釋放,減少請求的堆積。

linux 內核優化。這部分主要是查閱資料加上自己的理解。內容來自 《深入理解 Nginx 模塊開發與架構設計》。

調整參數之後可以使用 abjmeter 進行壓測,根據壓測結果來進一步調優。

Nginx 一定要在保證安全訪問的情況下做性能優化。

linux 內核優化

可以修改  /etc/sysctl.conf 來修改內核參數。參數調整僅供參考

  • 查看 tcp 相關係統參數
 sysctl -a | grep 'net.ipv4.tcp' | grep -v grep
fs.file-max = 999999
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_keepalive_time = 15
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.tcp_rmem = 4096 32768 262144
net.ipv4.tcp_wmem = 4096 32768 262144
net.ipv4.tcp_max_orphans = 262144
net.core.netdev_max_backlog = 262144
net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.core.rmem_max = 2097152
net.core.wmem_max = 2097152
net.core.somaxconn = 262144
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog=262144

修改之後執行以下命令,使配置生效。

sysctl -p

上面的參數意義解釋如下:

  • fs.file-max:999999

    這個參數表示進程(比如一個worker進程)可以同時打開的最大句柄數,這 個參數直接限制最大併發連接數,需根據實際情況配置。

  • net.ipv4.tcp_tw_reuse:

    這個參數設置爲1,表示允許將TIME-WAIT狀態的socket重新用於新的 TCP連接,這對於服務器來說很有意義,因爲服務器上總會有大量TIME-WAIT狀態的連接。

  • net.ipv4.tcp_keepalive_time:

    這個參數表示當keepalive啓用時,TCP發送keepalive消息的頻度。默認是2小時,若將其設置得小一些,可以更快地清理無效的連接。

  • net.ipv4.tcp_fin_timeout:

    這個參數表示當服務器主動關閉連接時,socket保持在FIN-WAIT-2狀態的最大時間。

  • net.ipv4.tcp_max_tw_buckets:

    這個參數表示操作系統允許TIME_WAIT套接字數量的最大值, 如果超過這個數字,TIME_WAIT套接字將立刻被清除並打印警告信息。該參數默認爲 180000,過多的TIME_WAIT套接字會使Web服務器變慢。

  • net.ipv4.ip_local_port_range:

    這個參數定義了在UDP和TCP連接中本地(不包括連接的遠端) 端口的取值範圍。

  • net.ipv4.tcp_rmem:

    這個參數定義了TCP接收緩存(用於TCP接收滑動窗口)的最小 值、默認值、最大值。

  • net.ipv4.tcp_wmem:

    這個參數定義了TCP發送緩存(用於TCP發送滑動窗口)的最小 值、默認值、最大值。

  • net.ipv4.tcp_max_orphans

    選項用於記錄那些尚未收到客戶端確認信息的連接請求的最大值。對於有128MB內存的系統而言,此參數的默認值是1024,對小內存的系統則是128。

  • net.core.netdev_max_backlog:

    當網卡接收數據包的速度大於內核處理的速度時,會有一個隊列 保存這些數據包。這個參數表示該隊列的最大值。

  • net.core.net.core.rmem_default:

    這個參數表示內核套接字接收緩存區默認的大小。

  • net.core.wmem_default:

    這個參數表示內核套接字發送緩存區默認的大小。

  • net.core.rmem_max:

    這個參數表示內核套接字接收緩存區的最大大小。

  • net.core.wmem_max:

    這個參數表示內核套接字發送緩存區的最大大小。

滑動窗口的大小與套接字緩存區會在一定程度上影響併發連接的數目。

每個 TCP連接都會爲維護TCP滑動窗口而消耗內存,這個窗口會根據服務器的處理速度收縮或擴 張。

參數wmem_max的設置,需要平衡物理內存的總大小、Nginx併發處理的最大連接數量 (由nginx.conf中的worker_processes和worker_connections參數決定)而確定。

當然,如果僅僅 爲了提高併發量使服務器不出現Out Of Memory問題而去降低滑動窗口大小,那麼並不合 適,因爲滑動窗口過小會影響大數據量的傳輸速度。

rmem_default、wmem_default、 rmem_max、wmem_max這4個參數的設置需要根據我們的業務特性以及實際的硬件成本來綜 合考慮。

  • net.core.somaxconn

    選項表示當每個網絡接口接收數據包的速率比內核處理這些包的速率快時,允許發送到隊列的數據包的最大數目。

  • net.ipv4.tcp_syncookies:

    設置爲 1。該參數與性能無關,用於解決TCP的SYN攻擊。

  • net.ipv4.tcp_max_syn_backlog:

    這個參數表示TCP三次握手建立階段接收SYN請求隊列的最大 長度,默認爲1024,將其設置得大一些可以使出現Nginx繁忙來不及accept新連接的情況時, Linux不至於丟失客戶端發起的連接請求。

內存及磁盤資料優化

client_header_buffer_size 1k;

作爲靜態資源訪問 1k 足夠了。

客戶端請求頭部的緩衝區大小,默認 1k,當請求接口的時候,根據請求頭數據設置 4k 整數倍。

4k 爲系統內存頁大小,命令 getconf PAGESIZE 內存頁大小

large_client_header_buffers

image-20200329190558284

client_body_in_single_buffer

設置爲 on,http 包一律寫入到內存 buffer 中,如果包體超過  client_body_buffer_size  的大小,還是會寫入到磁盤文件中。

client_body_buffer_size

x64 默認 16K。定義接受請求體內存緩衝區大小,請求先寫入到緩存區,超過在寫入臨時文件中。

client_max_body_size 100m;

設置客戶端請求體最大允許大小,默認 1m。檢查的是 Content-Length。設置爲 0 不檢查。針對具體 location 配置。防止被請求攻擊,在需要調大的地方設置,不要全局設置。

sendflie on;

文件內容讀取減少了內核態到用戶態的拷貝,直接從內核態到網卡設備,提高了發送效率。

open_file_cache

緩存文件的存儲信息。max 表示最大存儲數量,超過這個數量,採用 LRU 淘汰

inactive 指定時間段,該時間段內沒有被訪問過的元素,會被淘汰

open_file_cache max=65535 inactive=20s;

open_file_cache_min_uses

默認爲 1。與 open_file_cache 的 inactive 配合使用,如果在 inactive 指定的時間內,訪問次數超過 open_file_cache_min_uses 指定的次數,不會淘汰緩存。

調大文件句柄限制

linux 一切皆文件,但是進程打開的文件數會有限制。可針對用戶和進程來限制文件句柄數。

  • 文件句柄,可以針對用戶,進程設置

    • 全局設置 /etc/security/limits.conf
* hard nofile 65535
* soft nofile 65535
root hard nofile 65535
- nginx 進程配置
worker_rlimit_nofile 20480;

日誌優化

可適當減少日誌操作。比如訪問靜態資料的日誌記錄,如果你感覺不重要,可以取消日誌記錄。這樣請求資源的時候就會減少日誌的磁盤 io。

# 關閉日誌
access_log off;
# 禁用文件未找到的錯誤到日誌中去
log_not_found off;

反向代理優化

如果你用 nginx 作爲代理服務器,也要減少磁盤 io 的讀取。

proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 16 64k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;
proxy_set_header Host $http_host;
proxy_set_header X-REAL-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

Nginx 優化配置

# 配置 worker 進程所屬用戶,用戶組
user nginx nginx;

# 配置 worker 進程數量,爲避免 cpu 切換損耗,配置和系統內核數一樣即可,或者 auto
worker_processes auto;

# 配置 cpu 親和,auto 代表自動綁定
worker_cpu_affinity auto;

# nginx 進程打開文件描述符數目,此值覆蓋 ulimit -n 的值。
worker_rlimit_nofile 65535;

events {
# 用這個模型來高效處理異步事件
use epoll;

# 設置爲 on worker 進程輪流接受新鏈接,官方推薦設置爲 off.高負載的情況下設置爲 on.
accept_mutex on;

# worker進程是否同時接受連接所有新請求。默認爲off,表示一次只接受一個新的請求。官方推薦 off
multi_accept on;

# 配置 一個 woker 進程處理的連接數
worker_connections 65535;
}
http {
# 關閉日誌
access_log off;
# 隱藏響應頭中的有關操作系統和web server(Nginx)版本號的信息,這樣對於安全性是有好處的。
server_tokens off;
sendfile on;
# 設置爲非零值時,可限制單個 sendfile() 調用時傳輸的數據量。如果沒有限制,一個快速 連接可能會完全佔用工作進程。
sendfile_max_chunk 5m;
# tcp_nopush 和 tcp_nodeny 可以一起生效
# 等數據包累計到一定大小發送,啓用 sendfile 生效
tcp_nopush on;
# 該選項僅在連接轉換到 keep-alive ,長連接狀態時啓用。讓 tcp 儘快發包。
tcp_nodelay on;
# 爲了儘快釋放連接,可以設置小點. 15 至 30
keepalive_timeout 15;

# 客戶端請求頭部的緩衝區大小,默認 1k,當請求接口的時候需要設置 4k 整數倍.內存設置爲系統內存頁大小,命令 getconf PAGESIZE 內存頁大小
client_header_buffer_size 4k;

large_client_header_buffers 8 8k;

# 根據需求設置,接口請求可以設置大些
client_body_buffer_size 128k;

# 設置客戶端請求體最大允許大小,默認 1m。檢查的是 Content-Length。設置爲 0 不檢查。針對具體 location 配置
client_max_body_size 1m;


# 下面這個參數將爲打開文件指定緩存,默認是沒有啓用的,max指定緩存數量,建議和打開文件數一致,
# inactive是指經過多長時間文件沒被請求後刪除緩存。
open_file_cache max=262140 inactive=20s;
# 下面這個是指多長時間檢查一次緩存的有效信息。
open_file_cache_valid 30s;
# open_file_cache指令中的inactive參數時間內文件的最少訪問次數,低於這個數,緩存清除
open_file_cache_min_uses 1;
open_file_cache_errors on;

reset_timedout_connection on;
client_body_timeout 10;
send_timeout 2;

# 限制每個 ip 的連接數
limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m;

# 限制每個 ip 每秒的請求數
limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=10r/s;

gzip on;
# 在響應頭中增加,Vary: Accept-Encoding
gzip_vary on;
# gzip壓縮級別1-9,數字越大壓縮效果越好,壓縮時間也就越長CPU越高
gzip_comp_level 5;
# 申請內存時大小,如果源文件 9k,超過了 8K,那會申請 16*8K。
gzip_buffers 8 128k;
gzip_min_length 5K;
gzip_proxied any;
gzip_disable msie6;
gzip_http_version 1.1;
# 文本(js、text、css、xml、json)壓縮比較好,圖片已經進行過壓縮,在壓縮,效果不是很明顯,還浪費 cpu
gzip_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml+rss application/rss+xml application/atom+xml image/svg+xml;

# 安全相關 header
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Feature-Policy "autoplay 'none'; camera 'none'" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;


server {
listen 80 backlog=262144;

limit_conn conn_limit_per_ip 10;
limit_req zone=req_limit_per_ip burst=10 nodelay;
# assets, media
location ~* \.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv)$ {
# 強緩存,時間爲一年,瀏覽器和 cdn 中間件可以緩存
add_header Cache-Control "max-age=31536000";
etag off;
access_log off;
# 禁用文件未找到的錯誤到日誌中去
log_not_found off;
}

# svg, fonts
location ~* \.(?:svgz?|ttf|ttc|otf|eot|woff2?)$ {
# 強緩存,時間爲一年,瀏覽器和 cdn 中間件可以緩存
add_header Cache-Control "max-age=31536000";
etag off;
access_log off;
# 禁用文件未找到的錯誤到日誌中去
log_not_found off;
}
}

}

資料參考

http-security-headers

https://www.keycdn.com/blog/http-security-headers

Nginx Performance Tuning – Tips & Tricks

https://www.nginx.com/blog/performance-tuning-tips-tricks/

《深入理解 Nginx 模塊開發與架構設計》


歡迎關注我的微信公衆號【Mflyyou】獲取持續更新。
github.com/zhangpanqin/MFlyYou 收集技術文章及我的系列文章,歡迎 Star。


本文分享自微信公衆號 - Mflyyou(Mflyyou)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章