Nginx高級篇-性能優化

前言

消息爆炸的時代,對於速度的追逐已成了大家的標配。爲了讓自己的網站有更好的訪問體驗,網頁加載控制在 3s 內,決定了網友願不願等你。靜態文件的緩存優化了網頁加載,超時機制會讓 Client 與 Server 的響應不會長時間阻塞,GZIP 壓縮提升 IO 效率、減少我們發送的數據量,限流來預防 DOS 攻擊,TCP 參數調優提升傳輸效率。如何加速網頁加載,提升網站訪問的性能?

Nginx 的系統結構

Nginx 包含一個單一的 master 進程和多個 worker 進程。所有的這些進程都是單線程,並且設計爲同時處理成千上萬個連接。worker 進程是處理連接的地方,它用於處理客戶端請求。master 進程負責讀取配置文件、處理套接字、派生 worker 進程、打開日誌文件等。總之, master 進程是一個可以通過處理信號響應來管理請求的進程。

CentOS7 下載安裝 Nginx

準備好一臺裸機,裝好 CentOS7 系統

1、添加源

默認情況 Centos7 中無 Nginx 的源,最近發現 Nginx 官網提供了 Centos 的源地址。因此可以如下執行命令添加源:

sudo rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
2、安裝 Nginx

通過 yum search nginx 看是否已經添加源成功。
如果成功則執行下列命令安裝 Nginx。

sudo yum install -y nginx
3、Nginx 開機自動運行
sudo systemctl start nginx.service
sudo systemctl enable nginx.service

常規參數講解

進入 /etc/nginx 文件夾,編輯 nginx.conf ,可以看到下面的參數。簡單介紹下:

# nginx進程數,建議按照cpu數目來指定,一般跟cpu核數相同或爲它的倍數。
worker_processes 8;

#爲每個進程分配cpu,上例中將8個進程分配到8個cpu,當然可以寫多個,或者將一個進程分配到多個cpu。
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;

# 作用於event的I/O多路複用模型
use epoll;

#收到新連接通知後接受儘可能多的連接,作用於event
multi_accept on;

epoll 接口作爲 poll 接口的變體在 Linux 內核 2.5 中被引入。相比 select 實現的多路複用 I/O 模型,epoll 最大的好處在於它不會隨着被監控描述符數目的增長而導致效率急速下降。

動靜分離

將靜態文件存儲到 /usr/share/nginx/html 文件夾中,配置靜態文件攔截規則。單個項目可以直接放在 /usr/share/nginx/html 根目錄下,如果是多個項目,則要根據項目的根目錄創建文件夾來保存靜態文件。

enter image description here

配置攔截規則如下:

location ~ .*\.(eot|svg|ttf|woff|jpg|jpeg|gif|png|ico|cur|gz|svgz|mp4|ogg|ogv|webm) {
	#所有靜態文件直接讀取硬盤
	root /usr/share/nginx/html;
	expires 30d; #緩存30天
}

location ~ .*\.(js|css)?${
	#所有靜態文件直接讀取硬盤
	root /usr/share/nginx/html;
	expires      12h;
}

結果:https://www.ygoclub.com 這個網站的訪問速度從 2s 下降到 300-400ms,大部分內容都將從靜態文件目錄或者硬盤中讀取。

enter image description here

緩存配置

配置三步走:

  • 客戶端、代理請求緩存
  • 設置緩存空間,存儲緩存文件
  • 在 location 中使用緩存空間
  • 打開文件的緩存配置
#客戶端請求主體的緩衝區大小
client_body_buffer_size 512k;
#客戶端請求頭部的緩衝區大小,這個可以根據系統分頁大小來設置
client_header_buffer_size 4k;
client_max_body_size 512k;
large_client_header_buffers 2 8k;
proxy_buffer_size 16k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;
#指定在何種情況下一個失敗的請求應該被髮送到下一臺後端服務器
proxy_next_upstream http_502 http_504 http_404 error timeout invalid_header;

#設置緩存空間,存儲緩存文件
proxy_cache_path /data/nginx-cache levels=1:2 keys_zone=nginx-cache:20m max_size=50g inactive=168h;

#在location中使用緩存空間,pathname是項目的目錄,請自定義
location /pathname { 
	proxy_set_header X-Real-IP $remote_addr;
	proxy_cache nginx-cache;
	proxy_cache_valid 200 304 302 5d;
	proxy_cache_valid any 5d;
	proxy_cache_key '$host:$server_port$request_uri';
	add_header X-Cache '$upstream_cache_status from $host';
	proxy_set_header X-Real-IP $remote_addr;
	proxy_pass http://localhost/pathname;
}

#打開文件的緩存配置
#爲打開文件指定緩存,默認是沒有啓用的,max 指定緩存數量,建議和打開文件數一致,inactive 是指經過多長時間文件沒被請求後刪除緩存。
open_file_cache max=65535 inactive=60s;

#文件描述符一直是在緩存中打開的,如果有一個文件在inactive時間內一次沒被使用,它將被移除。
open_file_cache_min_uses 1;

#指定多長時間檢查一次緩存的有效信息。
open_file_cache_valid 80s;

上述配置的結果,我們可以看到生成了很多緩存文件在 /data/nginx-cache 文件夾下面。

enter image description here

我們打開其中一個文件看看,會發現一些蹊蹺,這裏存儲了請求頭的信息。當我們處理一個 HTTP 請求的時候,它會先從這裏讀取。

enter image description here

連接超時

長時間佔着連接資源不釋放,最終會導致請求的堆積,Nginx 處理請求效率大大降低。所以我們對連接的控制都要注意設置超時時間,通過超時機制自動回收資源、避免資源浪費。

#客戶端、服務端設置
server_names_hash_bucket_size 128;
server_names_hash_max_size 512;
# 長連接超時配置
keepalive_timeout  65;
client_header_timeout 15s;
client_body_timeout 15s;
send_timeout 60s;

#代理設置
#與後端服務器建立連接的超時時間。注意這個一般不能大於75秒
proxy_connect_timeout 30s;
proxy_send_timeout 120s;
#從後端服務器讀取響應的超時
proxy_read_timeout 120s;

GZIP 壓縮

在我們進行 gzip 打包壓縮之前,最好將一些靜態文件先進行壓縮爲 min 文件,請求的時候合併爲同一文件。再通過 gzip 壓縮後,你會發現網站加載又加速了。

#開啓gzip,減少我們發送的數據量
gzip on;
#允許壓縮的最小字節數
gzip_min_length 1k;
#4個單位爲16k的內存作爲壓縮結果流緩存
gzip_buffers 4 16k;
#設置識別HTTP協議版本,默認是1.1
gzip_http_version 1.1;
#gzip壓縮比,可在1~9中設置,1壓縮比最小,速度最快,9壓縮比最大,速度最慢,消耗CPU
gzip_comp_level 4;
#壓縮的類型
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; 
#給代理服務器用的,有的瀏覽器支持壓縮,有的不支持,所以避免浪費不支持的也壓縮,所以根據客戶端的HTTP頭來判斷,是否需要壓縮
gzip_vary on;
#禁用IE6以下的gzip壓縮,IE6的某些版本對gzip的壓縮支持很不好
gzip_disable "MSIE [1-6].";

訪問限流

我們構建網站是爲了讓用戶訪問它們,我們希望用於合法訪問。所以不得不採取一些措施限制濫用訪問的用戶。這種濫用指的是從同一IP每秒到服務器請求的連接數。因爲這可能是在同一時間內,世界各地的多臺機器上的爬蟲機器人多次嘗試爬取網站的內容。

#限制用戶連接數來預防DOS攻擊
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;
#限制同一客戶端ip最大併發連接數
limit_conn perip 2;
#限制同一server最大併發連接數
limit_conn perserver 20;
#限制下載速度,根據自身服務器帶寬配置
limit_rate 300k; 

高效數據傳輸配置

#開啓文件的高效傳輸模式。tcp_nopush和tcp_nodelay可防止網絡及磁盤i/o阻塞,提升nginx工作效率;
sendfile on;
#數據包不會馬上傳送出去,等到數據包最大時,一次性的傳輸出去,這樣有助於解決網絡堵塞。
tcp_nopush on;
#只要有數據包產生,不管大小多少,就儘快傳輸
tcp_nodelay on;

內核參數的優化

編輯 /etc/sysctl.conf 文件,根據需要調整參數配置。

#如果想把timewait降下了就要把tcp_max_tw_buckets值減小,默認是180000
net.ipv4.tcp_max_tw_buckets = 5000

#開啓重用功能,允許將TIME-WAIT狀態的sockets重新用於新的TCP連接
net.ipv4.tcp_tw_reuse = 1

#系統中最多有多少個TCP套接字不被關聯到任何一個用戶文件句柄上。如果超過這個數字,孤兒連接將即刻被複位並打印出警告信息。這個限制僅僅是爲了防止簡單的DoS攻擊
net.ipv4.tcp_max_orphans = 262144

#當keepalive起用的時候,TCP發送keepalive消息的頻度。缺省是2小時。我們可以調短時間跨度
net.ipv4.tcp_keepalive_time = 30

日誌配置

日誌文件對於我們日常運維至關重要,如果沒有日誌排查問題,你將很難判斷異常的所在,要解決問題無異於大海撈針。日誌的保存時必要的,不可缺少的,我們來看下怎麼配置有利於排查問題?

  • 關鍵字:其中關鍵字 access_log,error_log 不能改變
  • error_log 錯誤日誌級別:[debug | info | notice | warn | error | crit | alert | emerg],級別越高記錄的信息越少。不要配置 info 等級較低的級別,會帶來大量的磁盤 I/O 消耗。

error_log 生產場景一般是 warn | error | crit 這三個級別之一

#定義日誌模板
log_format 日誌模板名稱 日誌格式;

#訪問日誌
access_log   path      format        gzip[=level]              [buffer=size]          [flush=time];
關鍵字     存放的路徑   日誌格式模板   gzip壓縮,level指壓縮級別   存放緩存日誌的緩存大小   保存在緩存中的最長時間

#錯誤日誌
error_log  <FILE>    <LEVEL>;
關鍵字     日誌文件   錯誤日誌級別

#示例
log_format main '$remote_addr - $remote_user [$time_local] "$request"'
                        '$status $body_bytes_sent "$http_referer"'
                        '"$http_user_agent" "$http_x_forwarded_for"';
access_log  /Users/jackson/Desktop/www.ygoclub.com-access.log  main gzip flush=5m;
error_log  /Users/jackson/Desktop/www.ygoclub.com-error.log  error;

打開 /Users/jackson/Desktop/www.ygoclub.com-error.log 日誌文件,我們可以看到很多找不到文件的異常。日誌輔助我們找到了問題,只要將文件補充上去就解決了。

enter image description here

實戰配置

1.整體配置
worker_processes  1;
pid  /var/run/nginx.pid;

events {
    worker_connections  2048;
	multi_accept on;
	use epoll;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
					  
	log_format main '{"@timestamp":"$time_iso8601",'   
	'"host":"$server_addr",'
	'"clientip":"$remote_addr",'
	'"size":$body_bytes_sent,'
	'"responsetime":$request_time,'
	'"upstreamtime":"$upstream_response_time",'
	'"upstreamhost":"$upstream_addr",'
	'"http_host":"$host",'
	'"url":"$uri",'
	'"xff":"$http_x_forwarded_for",'
	'"referer":"$http_referer",'
	'"agent":"$http_user_agent",'
	'"status":"$status"}';
	
	sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
	
    server_names_hash_bucket_size 128;
    server_names_hash_max_size 512;
    keepalive_timeout  65;
    client_header_timeout 15s;
    client_body_timeout 15s;
    send_timeout 60s;
	
	limit_conn_zone $binary_remote_addr zone=perip:10m;
	limit_conn_zone $server_name zone=perserver:10m;
	limit_conn perip 2;
	limit_conn perserver 20;
	limit_rate 300k; 

    proxy_cache_path /data/nginx-cache levels=1:2 keys_zone=nginx-cache:20m max_size=50g inactive=168h;
	
	client_body_buffer_size 512k;
	client_header_buffer_size 4k;
	client_max_body_size 512k;
	large_client_header_buffers 2 8k;
	proxy_connect_timeout 5s;
	proxy_send_timeout 120s;
	proxy_read_timeout 120s;
	proxy_buffer_size 16k;
	proxy_buffers 4 64k;
	proxy_busy_buffers_size 128k;
	proxy_temp_file_write_size 128k;
	proxy_next_upstream http_502 http_504 http_404 error timeout invalid_header;
	
	gzip on;
	gzip_min_length 1k;
	gzip_buffers 4 16k;
	gzip_http_version 1.1;
	gzip_comp_level 4;
	gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
	gzip_vary on;
	gzip_disable "MSIE [1-6].";

    include /etc/nginx/conf.d/*.conf;
}
2.負載均衡
upstream ygoapi{ 
  server 0.0.0.0:8082 fail_timeout=5 max_fails=3;
  server 0.0.0.0:8083 fail_timeout=5 max_fails=3;
  ip_hash;
}
3.HTTP 配置
#隱藏版本信息
server_tokens off;
server {
    listen       80;
    server_name  www.ygoclub.com;
    charset utf-8;
	
	#重定向HTTP請求到HTTPS
	return 301 https://$server_name$request_uri;
}
4.HTTPS 配置
  • 準備條件:需要先去下載 HTTPS 證書
server {
    listen 443;
    server_name www.ygoclub.com;
    ssl on;
    ssl_certificate cert/證書名稱.pem;
    ssl_certificate_key cert/證書名稱.key;
    ssl_session_timeout 5m;
    # SSL協議配置
    ssl_protocols SSLv2 SSLv3 TLSv1.2;
    ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
    ssl_prefer_server_ciphers on;
	
	valid_referers none blocked server_names
               *.ygoclub.com;
			   
	#日誌配置
    access_log  /Users/jackson/Desktop/www.ygoclub.com-access.log  main gzip=4 flush=5m;
    error_log  /Users/jackson/Desktop/www.ygoclub.com-error.log  error;
	
	location ~ .*\.(eot|svg|ttf|woff|jpg|jpeg|gif|png|ico|cur|gz|svgz|mp4|ogg|ogv|webm) {
		proxy_cache nginx-cache;
		proxy_cache_valid 200 304 302 5d;
		proxy_cache_key '$host:$server_port$request_uri';
		add_header X-Cache '$upstream_cache_status from $host';
		#所有靜態文件直接讀取硬盤
		root /usr/share/nginx/html;
		expires 30d; #緩存30天
	}

	location ~ .*\.(js|css)?$
	{
		proxy_cache nginx-cache;
		proxy_cache_valid 200 304 302 5d;
		proxy_cache_key '$host:$server_port$request_uri';
		add_header X-Cache '$upstream_cache_status from $host';
		#所有靜態文件直接讀取硬盤
		root /usr/share/nginx/html;
		expires      12h;
	}

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
    
	location /druid {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_cache nginx-cache;
        proxy_cache_valid 200 10m;
        proxy_pass http://ygoapi/druid;
	}
	
	location /api {
       proxy_set_header X-Real-IP $remote_addr;
       proxy_pass http://ygoapi/api;
	}
	
    # redirect server error pages to the static page /50x.html
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

關注公衆號,一起進步,一起成長。
在這裏插入圖片描述

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