天天看點

2W 字你全面認識 Nginx

點選上方 "程式設計技術圈"關注, 星标或置頂一起成長

背景回複“大禮包”有驚喜禮包!

每日英文

Some happened could not forget, even forget also only temporarily don't remember.

有些事發生了就不可能忘記, 即使忘記也隻是暫時的記不起。

每日掏心話

安靜,明白了一個人的時光,人生,總有太多期待一直失望,總有太多夢想一直落空,總有太多言語無人可訴。

責編:樂樂 | 來自:Lion連結:juejin.cn/post/6942607113118023710
           

程式設計技術圈(ID:study_tech)第 1234 次推文

往日回顧:拜托!不要用“ ! = null ”做判空了!

   正文   

Nginx 是開源、高性能、高可靠的 Web 和反向代理伺服器,而且支援熱部署,幾乎可以做到 7 * 24 小時不間斷運作,即使運作幾個月也不需要重新啟動,還能在不間斷服務的情況下對軟體版本進行熱更新。性能是 Nginx 最重要的考量,其占用記憶體少、并發能力強、能支援高達 5w 個并發連接配接數,最重要的是, Nginx 是免費的并可以商業化,配置使用也比較簡單。
Nginx 特點高并發、高性能;
子產品化架構使得它的擴充性非常好;
異步非阻塞的事件驅動模型這點和 Node.js 相似;
相對于其它伺服器來說它可以連續幾個月甚至更長而不需要重新開機伺服器使得它具有高可靠性;
熱部署、平滑更新;
完全開源,生态繁榮;
Nginx 作用Nginx 的最重要的幾個使用場景:靜态資源服務,通過本地檔案系統提供服務;
反向代理服務,延伸出包括緩存、負載均衡等;
API 服務, OpenResty ;
對于前端來說 Node.js 并不陌生, Nginx 和 Node.js 的很多理念類似, HTTP 伺服器、事件驅動、異步非阻塞等,且 Nginx 的大部分功能使用 Node.js 也可以實作,但 Nginx 和 Node.js 并不沖突,都有自己擅長的領域。Nginx 擅長于底層伺服器端資源的處理(靜态資源處理轉發、反向代理,負載均衡等), Node.js 更擅長上層具體業務邏輯的處理,兩者可以完美組合。用一張圖表示:

Nginx 安裝本文示範的是 Linux centOS 7.x 的作業系統上安裝 Nginx ,至于在其它作業系統上進行安裝可以網上自行搜尋,都非常簡單的。使用 yum 安裝 Nginx :yum install nginx -y安裝完成後,通過 rpm \-ql nginx 指令檢視 Nginx 的安裝資訊:# Nginx配置檔案
/etc/nginx/nginx.conf # nginx 主配置檔案
/etc/nginx/nginx.conf.default

# 可執行程式檔案
/usr/bin/nginx-upgrade
/usr/sbin/nginx

# nginx庫檔案
/usr/lib/systemd/system/nginx.service # 用于配置系統守護程序
/usr/lib64/nginx/modules # Nginx子產品目錄

# 幫助文檔
/usr/share/doc/nginx-1.16.1
/usr/share/doc/nginx-1.16.1/CHANGES
/usr/share/doc/nginx-1.16.1/README
/usr/share/doc/nginx-1.16.1/README.dynamic
/usr/share/doc/nginx-1.16.1/UPGRADE-NOTES-1.6-to-1.10

# 靜态資源目錄
/usr/share/nginx/html/404.html
/usr/share/nginx/html/50x.html
/usr/share/nginx/html/index.html

# 存放Nginx日志檔案
/var/log/nginx主要關注的檔案夾有兩個:
1. /etc/nginx/conf.d/ 是子配置項存放處, /etc/nginx/nginx.conf 主配置檔案會預設把這個檔案夾中所有子配置項都引入;2. /usr/share/nginx/html/ 靜态檔案都放在這個檔案夾,也可以根據你自己的習慣放在其他地方;Nginx 常用指令systemctl 系統指令:# 開機配置
systemctl enable nginx # 開機自動啟動
systemctl disable nginx # 關閉開機自動啟動

# 啟動Nginx
systemctl start nginx # 啟動Nginx成功後,可以直接通路主機IP,此時會展示Nginx預設頁面

# 停止Nginx
systemctl stop nginx

# 重新開機Nginx
systemctl restart nginx

# 重新加載Nginx
systemctl reload nginx

# 檢視 Nginx 運作狀态
systemctl status nginx

# 檢視Nginx程序
ps -ef | grep nginx

# 殺死Nginx程序
kill -9 pid # 根據上面檢視到的Nginx程序号,殺死Nginx程序,-9 表示強制結束程序Nginx 應用程式指令:nginx -s reload # 向主程序發送信号,重新加載配置檔案,熱重新開機
nginx -s reopen # 重新開機 Nginx
nginx -s stop # 快速關閉
nginx -s quit # 等待工作程序處理完成後關閉
nginx -T # 檢視目前 Nginx 最終的配置
nginx -t # 檢查配置是否有問題Nginx 核心配置配置檔案結構Nginx 的典型配置示例:# main段配置資訊
user  nginx; # 運作使用者,預設即是nginx,可以不進行設定
worker_processes  auto; # Nginx 程序數,一般設定為和 CPU 核數一樣
error_log  /var/log/nginx/error.log warn; # Nginx 的錯誤日志存放目錄
pid        /var/run/nginx.pid; # Nginx 服務啟動時的 pid 存放位置

# events段配置資訊
events {
    use epoll; # 使用epoll的I/O模型(如果你不知道Nginx該使用哪種輪詢方法,會自動選擇一個最适合你作業系統的)
    worker_connections 1024; # 每個程序允許最大并發數
}

# http段配置資訊
# 配置使用最頻繁的部分,代理、緩存、日志定義等絕大多數功能和第三方子產品的配置都在這裡設定
http { 
    # 設定日志模式
    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  /var/log/nginx/access.log main; # Nginx通路日志存放位置

    sendfile            on; # 開啟高效傳輸模式
    tcp_nopush          on; # 減少網絡封包段的數量
    tcp_nodelay         on;
    keepalive_timeout   65; # 保持連接配接的時間,也叫逾時時間,機關秒
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types; # 檔案擴充名與類型映射表
    default_type        application/octet-stream; # 預設檔案類型

    include /etc/nginx/conf.d/*.conf; # 加載子配置項
    
    # server段配置資訊
    server {
     listen       80; # 配置監聽的端口
     server_name  localhost; # 配置的域名
      
     # location段配置資訊
     location / {
      root   /usr/share/nginx/html; # 網站根目錄
      index  index.html index.htm; # 預設首頁檔案
      deny 172.168.22.11; # 禁止通路的ip位址,可以為all
      allow 172.168.33.44;# 允許通路的ip位址,可以為all
     }
     
     error_page 500 502 503 504 /50x.html; # 預設50x對應的通路頁面
     error_page 400 404 error.html; # 同上
    }
} 全局配置,對全局生效;
events 配置影響 Nginx 伺服器與使用者的網絡連接配接;
http 配置代理,緩存,日志定義等絕大多數功能和第三方子產品的配置;
server 配置虛拟主機的相關參數,一個 http 塊中可以有多個 server 塊;
location 用于配置比對的 uri ;
upstream 配置後端伺服器具體位址,負載均衡配置不可或缺的部分;
用一張圖清晰的展示它的層級結構:

配置檔案 main 段核心參數user指定運作 Nginx 的 woker 子程序的屬主和屬組,其中組可以不指定。user USERNAME [GROUP]

user nginx lion; # 使用者是nginx;組是lion
pid指定運作 Nginx master 主程序的 pid 檔案存放路徑。pid /opt/nginx/logs/nginx.pid # master主程序的的pid存放在nginx.pid的檔案worker_rlimit_nofile_number指定 worker 子程序可以打開的最大檔案句柄數。worker_rlimit_nofile 20480; # 可以了解成每個worker子程序的最大連接配接數量。
worker_rlimit_core指定 worker 子程序異常終止後的 core 檔案,用于記錄分析問題。worker_rlimit_core 50M; # 存放大小限制
working_directory /opt/nginx/tmp; # 存放目錄worker_processes_number指定 Nginx 啟動的 worker 子程序數量。搜尋公衆号後端架構師背景回複“架構整潔”,擷取一份驚喜禮包。worker_processes 4; # 指定具體子程序數量
worker_processes auto; # 與目前cpu實體核心數一緻worker_cpu_affinity将每個 worker 子程序與我們的 cpu 實體核心綁定。worker_cpu_affinity 0001 0010 0100 1000; # 4個實體核心,4個worker子程序

将每個 worker 子程序與特定 CPU 實體核心綁定,優勢在于,避免同一個 worker 子程序在不同的 CPU 核心上切換,緩存失效,降低性能。但其并不能真正的避免程序切換。worker_priority指定 worker 子程序的 nice 值,以調整運作 Nginx 的優先級,通常設定為負值,以優先調用 Nginx 。worker_priority -10; # 120-10=110,110就是最終的優先級Linux 預設程序的優先級值是120,值越小越優先;nice 定範圍為 -20 到 +19 。[備注] 應用的預設優先級值是120加上 nice 值等于它最終的值,這個值越小,優先級越高。worker_shutdown_timeout指定 worker 子程序優雅退出時的逾時時間。worker_shutdown_timeout 5s;timer_resolutionworker 子程序内部使用的計時器精度,調整時間間隔越大,系統調用越少,有利于性能提升;反之,系統調用越多,性能下降。timer_resolution 100ms;在 Linux 系統中,使用者需要擷取計時器時需要向作業系統核心發送請求,有請求就必然會有開銷,是以這個間隔越大開銷就越小。daemon指定 Nginx 的運作方式,前台還是背景,前台用于調試,背景用于生産。daemon off; # 預設是on,背景運作模式配置檔案 events 段核心參數useNginx 使用何種事件驅動模型。use method; # 不推薦配置它,讓nginx自己選擇

method 可選值為:select、poll、kqueue、epoll、/dev/poll、eventportworker_connectionsworker 子程序能夠處理的最大并發連接配接數。worker_connections 1024 # 每個子程序的最大連接配接數為1024accept_mutex
是否打開負載均衡互斥鎖。accept_mutex on # 預設是off關閉的,這裡推薦打開server_name 指令指定虛拟主機域名。server_name name1 name2 name3

# 示例:
server_name www.nginx.com;域名比對的四種寫法:精确比對:server_name www.nginx.com ;
左側通配:server_name *.nginx.com ;
右側統配:server_name www.nginx.* ;
正則比對:server_name ~^www\.nginx\.*$ ;
比對優先級:精确比對 > 左側通配符比對 > 右側通配符比對 > 正規表達式比對server_name 配置執行個體:1、配置本地 DNS 解析 vim /etc/hosts ( macOS 系統)# 添加如下内容,其中 121.42.11.34 是阿裡雲伺服器IP位址
121.42.11.34 www.nginx-test.com
121.42.11.34 mail.nginx-test.com
121.42.11.34 www.nginx-test.org
121.42.11.34 doc.nginx-test.com
121.42.11.34 www.nginx-test.cn
121.42.11.34 fe.nginx-test.club[注意] 這裡使用的是虛拟域名進行測試,是以需要配置本地 DNS 解析,如果使用阿裡雲上購買的域名,則需要在阿裡雲上設定好域名解析。
2、配置阿裡雲 Nginx ,vim /etc/nginx/nginx.conf# 這裡隻列舉了http端中的sever端配置

# 左比對
server {
 listen 80;
 server_name *.nginx-test.com;
 root /usr/share/nginx/html/nginx-test/left-match/;
 location / {
  index index.html;
 }
}

# 正則比對
server {
 listen 80;
 server_name ~^.*\.nginx-test\..*$;
 root /usr/share/nginx/html/nginx-test/reg-match/;
 location / {
  index index.html;
 }
}

# 右比對
server {
 listen 80;
 server_name www.nginx-test.*;
 root /usr/share/nginx/html/nginx-test/right-match/;
 location / {
  index index.html;
 }
}

# 完全比對
server {
 listen 80;
 server_name www.nginx-test.com;
 root /usr/share/nginx/html/nginx-test/all-match/;
 location / {
  index index.html;
 }
}3、通路分析當通路 www.nginx-test.com 時,都可以被比對上,是以選擇優先級最高的“完全比對”;
當通路 mail.nginx-test.com 時,會進行“左比對”;
當通路 www.nginx-test.org 時,會進行“右比對”;
當通路 doc.nginx-test.com 時,會進行“左比對”;
當通路 www.nginx-test.cn 時,會進行“右比對”;
當通路 fe.nginx-test.club 時,會進行“正則比對”;
root指定靜态資源目錄位置,它可以寫在 http 、 server 、 location 等配置中。root path

例如:
location /image {
 root /opt/nginx/static;
}

當使用者通路 www.test.com/image/1.png 時,實際在伺服器找的路徑是 /opt/nginx/static/image/1.png[注意] root 會将定義路徑與 URI 疊加, alias 則隻取定義路徑。alias它也是指定靜态資源目錄位置,它隻能寫在 location 中。location /image {
 alias /opt/nginx/static/image/;
}

當使用者通路 www.test.com/image/1.png 時,實際在伺服器找的路徑是 /opt/nginx/static/image/1.png[注意] 使用 alias 末尾一定要添加 / ,并且它隻能位于 location 中。location配置路徑。location [ = | ~ | ~* | ^~ ] uri {
 ...
}比對規則:= 精确比對;
~ 正則比對,區分大小寫;
~* 正則比對,不區分大小寫;
^~ 比對到即停止搜尋;
比對優先級:= > ^~ > ~ > ~* > 不帶任何字元。執行個體:server {
  listen 80;
  server_name www.nginx-test.com;
  
  # 隻有當通路 www.nginx-test.com/match_all/ 時才會比對到/usr/share/nginx/html/match_all/index.html
  location = /match_all/ {
      root /usr/share/nginx/html
      index index.html
  }
  
  # 當通路 www.nginx-test.com/1.jpg 等路徑時會去 /usr/share/nginx/images/1.jpg 找對應的資源
  location ~ \.(jpeg|jpg|png|svg)$ {
   root /usr/share/nginx/images;
  }
  
  # 當通路 www.nginx-test.com/bbs/ 時會比對上 /usr/share/nginx/html/bbs/index.html
  location ^~ /bbs/ {
   root /usr/share/nginx/html;
    index index.html index.htm;
  }
}location 中的反斜線location /test {
 ...
}

location /test/ {
 ...
}不帶 / 當通路 www.nginx-test.com/test 時, Nginx 先找是否有 test 目錄,如果有則找 test目錄下的 index.html ;如果沒有 test 目錄, nginx 則會找是否有 test 檔案。
帶 / 當通路 www.nginx-test.com/test 時, Nginx 先找是否有 test 目錄,如果有則找 test 目錄下的 index.html ,如果沒有它也不會去找是否存在 test 檔案。
return停止處理請求,直接傳回響應碼或重定向到其他 URL ;執行 return 指令後, location 中後續指令将不會被執行。return code [text];
return code URL;
return URL;

例如:
location / {
 return 404; # 直接傳回狀态碼
}

location / {
 return 404 "pages not found"; # 傳回狀态碼 + 一段文本
}

location / {
 return 302 /bbs ; # 傳回狀态碼 + 重定向位址
}

location / {
 return https://www.baidu.com ; # 傳回重定向位址
}rewrite
根據指定正規表達式比對規則,重寫 URL 。搜尋公衆号頂級架構師背景回複“offer”,擷取一份驚喜禮包。文法:rewrite 正規表達式 要替換的内容 [flag];

上下文:server、location、if

示例:rewirte /images/(.*\.jpg)$ /pic/$1; # $1是前面括号(.*\.jpg)的反向引用flag 可選值的含義:last 重寫後的 URL 發起新請求,再次進入 server 段,重試 location 的中的比對;
break 直接使用重寫後的 URL ,不再比對其它 location 中語句;
redirect 傳回302臨時重定向;
permanent 傳回301永久重定向;
server{
  listen 80;
  server_name fe.lion.club; # 要在本地hosts檔案進行配置
  root html;
  location /search {
   rewrite ^/(.*) https://www.baidu.com redirect;
  }
  
  location /images {
   rewrite /images/(.*) /pics/$1;
  }
  
  location /pics {
   rewrite /pics/(.*) /photos/$1;
  }
  
  location /photos {
  
  }
}按照這個配置我們來分析:
當通路 fe.lion.club/search 時,會自動幫我們重定向到 https://www.baidu.com。
當通路 fe.lion.club/images/1.jpg 時,第一步重寫 URL 為 fe.lion.club/pics/1.jpg ,找到 pics的 location ,繼續重寫 URL 為 fe.lion.club/photos/1.jpg ,找到 /photos 的 location 後,去 html/photos 目錄下尋找 1.jpg 靜态資源。
if 指令文法:if (condition) {...}

上下文:server、location

示例:
if($http_user_agent ~ Chrome){
  rewrite /(.*)/browser/$1 break;
}condition 判斷條件:$variable 僅為變量時,值為空或以0開頭字元串都會被當做 false 處理;
= 或 != 相等或不等;
~ 正則比對;
! ~ 非正則比對;
~* 正則比對,不區分大小寫;
-f 或 ! -f 檢測檔案存在或不存在;
-d 或 ! -d 檢測目錄存在或不存在;
-e 或 ! -e 檢測檔案、目錄、符号連結等存在或不存在;
-x 或 ! -x 檢測檔案可以執行或不可執行;
執行個體:server {
  listen 8080;
  server_name localhost;
  root html;
  
  location / {
   if ( $uri = "/images/" ){
     rewrite (.*) /pics/ break;
    }
  }
}當通路 localhost:8080/images/ 時,會進入 if 判斷裡面執行 rewrite 指令。autoindex使用者請求以 / 結尾時,列出目錄結構,可以用于快速搭建靜态資源下載下傳網站。autoindex.conf 配置資訊:server {
  listen 80;
  server_name fe.lion-test.club;
  
  location /download/ {
    root /opt/source;
    
    autoindex on; # 打開 autoindex,,可選參數有 on | off
    autoindex_exact_size on; # 修改為off,以KB、MB、GB顯示檔案大小,預設為on,以bytes顯示出⽂件的确切⼤⼩
    autoindex_format html; # 以html的方式進行格式化,可選參數有 html | json | xml
    autoindex_localtime off; # 顯示的⽂件時間為⽂件的伺服器時間。預設為off,顯示的⽂件時間為GMT時間
  }
}當通路 fe.lion.com/download/ 時,會把伺服器 /opt/source/download/ 路徑下的檔案展示出來,如下圖所示:
變量Nginx 提供給使用者的變量非常多,但是終究是一個完整的請求過程所産生資料, Nginx 将這些資料以變量的形式提供給使用者。下面列舉些項目中常用的變量:執行個體示範 var.conf :server{
 listen 8081;
 server_name var.lion-test.club;
 root /usr/share/nginx/html;
 location / {
  return 200 "
remote_addr: $remote_addr
remote_port: $remote_port
server_addr: $server_addr
server_port: $server_port
server_protocol: $server_protocol
binary_remote_addr: $binary_remote_addr
connection: $connection
uri: $uri
request_uri: $request_uri
scheme: $scheme
request_method: $request_method
request_length: $request_length
args: $args
arg_pid: $arg_pid
is_args: $is_args
query_string: $query_string
host: $host
http_user_agent: $http_user_agent
http_referer: $http_referer
http_via: $http_via
request_time: $request_time
https: $https
request_filename: $request_filename
document_root: $document_root
";
 }
}當我們通路 http://var.lion-test.club:8081/test?pid=121414&cid=sadasd 時,由于 Nginx 中寫了 return 方法,是以 chrome 浏覽器會預設為我們下載下傳一個檔案,下面展示的就是下載下傳的檔案内容:remote_addr: 27.16.220.84
remote_port: 56838
server_addr: 172.17.0.2
server_port: 8081
server_protocol: HTTP/1.1
binary_remote_addr: 茉
connection: 126
uri: /test/
request_uri: /test/?pid=121414&cid=sadasd
scheme: http
request_method: GET
request_length: 518
args: pid=121414&cid=sadasd
arg_pid: 121414
is_args: ?
query_string: pid=121414&cid=sadasd
host: var.lion-test.club
http_user_agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36
http_referer: 
http_via: 
request_time: 0.000
https: 
request_filename: /usr/share/nginx/html/test/
document_root: /usr/share/nginx/htmlNginx 的配置還有非常多,以上隻是羅列了一些常用的配置,在實際項目中還是要學會查閱文檔。Nginx 應用核心概念代理是在伺服器和用戶端之間假設的一層伺服器,代理将接收用戶端的請求并将它轉發給伺服器,然後将服務端的響應轉發給用戶端。不管是正向代理還是反向代理,實作的都是上面的功能。正向代理正向代理,意思是一個位于用戶端和原始伺服器(origin server)之間的伺服器,為了從原始伺服器取得内容,用戶端向代理發送一個請求并指定目标(原始伺服器),然後代理向原始伺服器轉交請求并将獲得的内容傳回給用戶端。正向代理是為我們服務的,即為用戶端服務的,用戶端可以根據正向代理通路到它本身無法通路到的伺服器資源。正向代理對我們是透明的,對服務端是非透明的,即服務端并不知道自己收到的是來自代理的通路還是來自真實用戶端的通路。反向代理反向代理*(Reverse Proxy)方式是指以代理伺服器來接受internet上的連接配接請求,然後将請求轉發給内部網絡上的伺服器,并将從伺服器上得到的結果傳回給internet上請求連接配接的用戶端,此時代理伺服器對外就表現為一個反向代理伺服器。
反向代理是為服務端服務的,反向代理可以幫助伺服器接收來自用戶端的請求,幫助伺服器做請求轉發,負載均衡等。反向代理對服務端是透明的,對我們是非透明的,即我們并不知道自己通路的是代理伺服器,而伺服器知道反向代理在為他服務。反向代理的優勢:隐藏真實伺服器;
負載均衡便于橫向擴充後端動态服務;
動靜分離,提升系統健壯性;
那麼“動靜分離”是什麼?負載均衡又是什麼?動靜分離動靜分離是指在 web 伺服器架構中,将靜态頁面與動态頁面或者靜态内容接口和動态内容接口分開不同系統通路的架構設計方法,進而提示整個服務的通路性和可維護性。
一般來說,都需要将動态資源和靜态資源分開,由于 Nginx 的高并發和靜态資源緩存等特性,經常将靜态資源部署在 Nginx 上。如果請求的是靜态資源,直接到靜态資源目錄擷取資源,如果是動态資源的請求,則利用反向代理的原理,把請求轉發給對應背景應用去處理,進而實作動靜分離。
使用前後端分離後,可以很大程度提升靜态資源的通路速度,即使動态服務不可用,靜态資源的通路也不會受到影響。負載均衡一般情況下,用戶端發送多個請求到伺服器,伺服器處理請求,其中一部分可能要操作一些資源比如資料庫、靜态資源等,伺服器處理完畢後,再将結果傳回給用戶端。這種模式對于早期的系統來說,功能要求不複雜,且并發請求相對較少的情況下還能勝任,成本也低。随着資訊數量不斷增長,通路量和資料量飛速增長,以及系統業務複雜度持續增加,這種做法已無法滿足要求,并發量特别大時,伺服器容易崩。很明顯這是由于伺服器性能的瓶頸造成的問題,除了堆機器之外,最重要的做法就是負載均衡。請求爆發式增長的情況下,單個機器性能再強勁也無法滿足要求了,這個時候叢集的概念産生了,單個伺服器解決不了的問題,可以使用多個伺服器,然後将請求分發到各個伺服器上,将負載分發到不同的伺服器,這就是負載均衡,核心是「分攤壓力」。Nginx 實作負載均衡,一般來說指的是将請求轉發給伺服器叢集。搜尋公衆号後端架構師背景回複“面試”,擷取一份驚喜禮包。舉個具體的例子,晚高峰乘坐地鐵的時候,入站口經常會有地鐵從業人員大喇叭“請走 B 口, B口人少車空....”,這個從業人員的作用就是負載均衡。

Nginx 實作負載均衡的政策:輪詢政策:預設情況下采用的政策,将所有用戶端請求輪詢配置設定給服務端。這種政策是可以正常工作的,但是如果其中某一台伺服器壓力太大,出現延遲,會影響所有配置設定在這台伺服器下的使用者。
最小連接配接數政策:将請求優先配置設定給壓力較小的伺服器,它可以平衡每個隊列的長度,并避免向壓力大的伺服器添加更多的請求。
最快響應時間政策:優先配置設定給響應時間最短的伺服器。
用戶端 ip 綁定政策:來自同一個 ip 的請求永遠隻配置設定一台伺服器,有效解決了動态網頁存在的 session 共享問題。
Nginx 實戰配置在配置反向代理和負載均衡等等功能之前,有兩個核心子產品是我們必須要掌握的,這兩個子產品應該說是 Nginx 應用配置中的核心,它們分别是:upstream 、proxy_pass 。upstream用于定義上遊伺服器(指的就是背景提供的應用伺服器)的相關資訊。
文法:upstream name {
 ...
}

上下文:http

示例:
upstream back_end_server{
  server 192.168.100.33:8081
}在 upstream 内可使用的指令:server 定義上遊伺服器位址;
zone 定義共享記憶體,用于跨 worker 子程序;
keepalive 對上遊服務啟用長連接配接;
keepalive_requests 一個長連接配接最多請求 HTTP 的個數;
keepalive_timeout 空閑情形下,一個長連接配接的逾時時長;
hash 哈希負載均衡算法;
ip_hash 依據 IP 進行哈希計算的負載均衡算法;
least_conn 最少連接配接數負載均衡算法;
least_time 最短響應時間負載均衡算法;
random 随機負載均衡算法;
server定義上遊伺服器位址。文法:server address [parameters]

上下文:upstreamparameters 可選值:weight=number 權重值,預設為1;
max_conns=number 上遊伺服器的最大并發連接配接數;
fail_timeout=time 伺服器不可用的判定時間;
max_fails=numer 伺服器不可用的檢查次數;
backup 備份伺服器,僅當其他伺服器都不可用時才會啟用;
down 标記伺服器長期不可用,離線維護;
keepalive限制每個 worker 子程序與上遊伺服器空閑長連接配接的最大數量。keepalive connections;

上下文:upstream

示例:keepalive 16;keepalive_requests單個長連接配接可以處理的最多 HTTP 請求個數。文法:keepalive_requests number;

預設值:keepalive_requests 100;

上下文:upstream
keepalive_timeout空閑長連接配接的最長保持時間。文法:keepalive_timeout time;

預設值:keepalive_timeout 60s;

上下文:upstream配置執行個體upstream back_end{
 server 127.0.0.1:8081 weight=3 max_conns=1000 fail_timeout=10s max_fails=2;
  keepalive 32;
  keepalive_requests 50;
  keepalive_timeout 30s;
}proxy_pass用于配置代理伺服器。文法:proxy_pass URL;

上下文:location、if、limit_except

示例:
proxy_pass http://127.0.0.1:8081
proxy_pass http://127.0.0.1:8081/proxyURL 參數原則1. URL 必須以 http 或 https 開頭;2. URL 中可以攜帶變量;3. URL 中是否帶 URI ,會直接影響發往上遊請求的 URL ;接下來讓我們來看看兩種常見的 URL 用法:proxy_pass http://192.168.100.33:8081
proxy_pass http://192.168.100.33:8081/
這兩種用法的差別就是帶 / 和不帶 / ,在配置代理時它們的差別可大了:不帶 / 意味着 Nginx 不會修改使用者 URL ,而是直接透傳給上遊的應用伺服器;
帶 / 意味着 Nginx 會修改使用者 URL ,修改方法是将 location 後的 URL 從使用者 URL 中删除;
不帶 / 的用法:location /bbs/{
  proxy_pass http://127.0.0.1:8080;
}分析:1. 使用者請求 URL :/bbs/abc/test.html2. 請求到達 Nginx 的 URL :/bbs/abc/test.html3 .請求到達上遊應用伺服器的 URL :/bbs/abc/test.html帶 / 的用法:location /bbs/{
  proxy_pass http://127.0.0.1:8080/;
}分析:1. 使用者請求 URL :/bbs/abc/test.html2. 請求到達 Nginx 的 URL :/bbs/abc/test.html3. 請求到達上遊應用伺服器的 URL :/abc/test.html并沒有拼接上 /bbs ,這點和 root 與 alias 之間的差別是保持一緻的。配置反向代理這裡為了示範更加接近實際,作者準備了兩台雲伺服器,它們的公網 IP 分别是:121.42.11.34與 121.5.180.193 。我們把 121.42.11.34 伺服器作為上遊伺服器,做如下配置:# /etc/nginx/conf.d/proxy.conf
server{
  listen 8080;
  server_name localhost;
  
  location /proxy/ {
    root /usr/share/nginx/html/proxy;
    index index.html;
  }
}

# /usr/share/nginx/html/proxy/index.html
<h1> 121.42.11.34 proxy html </h1>
配置完成後重新開機 Nginx 伺服器 nginx \-s reload 。
把 121.5.180.193 伺服器作為代理伺服器,做如下配置:# /etc/nginx/conf.d/proxy.conf
upstream back_end {
  server 121.42.11.34:8080 weight=2 max_conns=1000 fail_timeout=10s max_fails=3;
  keepalive 32;
  keepalive_requests 80;
  keepalive_timeout 20s;
}

server {
  listen 80;
  server_name proxy.lion.club;
  location /proxy {
   proxy_pass http://back_end/proxy;
  }
}本地機器要通路 proxy.lion.club 域名,是以需要配置本地 hosts ,通過指令:vim /etc/hosts 進入配置檔案,添加如下内容:121.5.180.193 proxy.lion.club分析:當通路 proxy.lion.club/proxy 時通過 upstream 的配置找到 121.42.11.34:8080 ;是以通路位址變為 http://121.42.11.34:8080/proxy ;連接配接到 121.42.11.34 伺服器,找到 8080 端口提供的 server ;通過 server 找到 /usr/share/nginx/html/proxy/index.html 資源,最終展示出來。配置負載均衡配置負載均衡主要是要使用 upstream 指令。我們把 121.42.11.34 伺服器作為上遊伺服器,做如下配置( /etc/nginx/conf.d/balance.conf):server{
  listen 8020;
  location / {
   return 200 'return 8020 \n';
  }
}

server{
  listen 8030;
  location / {
   return 200 'return 8030 \n';
  }
}

server{
  listen 8040;
  location / {
   return 200 'return 8040 \n';
  }
}配置完成後:1. nginx -t 檢測配置是否正确;2. nginx -s reload 重新開機 Nginx 伺服器;3. 執行 ss -nlt 指令檢視端口是否被占用,進而判斷 Nginx 服務是否正确啟動。把 121.5.180.193 伺服器作為代理伺服器,做如下配置( /etc/nginx/conf.d/balance.conf ):upstream demo_server {
  server 121.42.11.34:8020;
  server 121.42.11.34:8030;
  server 121.42.11.34:8040;
}

server {
  listen 80;
  server_name balance.lion.club;
  
  location /balance/ {
   proxy_pass http://demo_server;
  }
}配置完成後重新開機 Nginx 伺服器。并且在需要通路的用戶端配置好 ip 和域名的映射關系。# /etc/hosts

121.5.180.193 balance.lion.club在用戶端機器執行 curl http://balance.lion.club/balance/ 指令:不難看出,負載均衡的配置已經生效了,每次給我們分發的上遊伺服器都不一樣。就是通過簡單的輪詢政策進行上遊伺服器分發。

接下來,我們再來了解下 Nginx 的其它分發政策。hash 算法通過制定關鍵字作為 hash key ,基于 hash 算法映射到特定的上遊伺服器中。關鍵字可以包含有變量、字元串。upstream demo_server {
  hash $request_uri;
  server 121.42.11.34:8020;
  server 121.42.11.34:8030;
  server 121.42.11.34:8040;
}

server {
  listen 80;
  server_name balance.lion.club;
  
  location /balance/ {
   proxy_pass http://demo_server;
  }
}hash $request_uri 表示使用 request_uri 變量作為 hash 的 key 值,隻要通路的 URI 保持不變,就會一直分發給同一台伺服器。ip_hash根據用戶端的請求 ip 進行判斷,隻要 ip 位址不變就永遠配置設定到同一台主機。它可以有效解決背景伺服器 session 保持的問題。upstream demo_server {
  ip_hash;
  server 121.42.11.34:8020;
  server 121.42.11.34:8030;
  server 121.42.11.34:8040;
}

server {
  listen 80;
  server_name balance.lion.club;
  
  location /balance/ {
   proxy_pass http://demo_server;
  }
}最少連接配接數算法各個 worker 子程序通過讀取共享記憶體的資料,來擷取後端伺服器的資訊。來挑選一台目前已建立連接配接數最少的伺服器進行配置設定請求。文法:least_conn;

上下文:upstream;示例:upstream demo_server {
  zone test 10M; # zone可以設定共享記憶體空間的名字和大小
  least_conn;
  server 121.42.11.34:8020;
  server 121.42.11.34:8030;
  server 121.42.11.34:8040;
}

server {
  listen 80;
  server_name balance.lion.club;
  
  location /balance/ {
   proxy_pass http://demo_server;
  }
}最後你會發現,負載均衡的配置其實一點都不複雜。配置緩存緩存可以非常有效的提升性能,是以不論是用戶端(浏覽器),還是代理伺服器( Nginx ),乃至上遊伺服器都多少會涉及到緩存。可見緩存在每個環節都是非常重要的。下面讓我們來學習 Nginx 中如何設定緩存政策。proxy_cache存儲一些之前被通路過、而且可能将要被再次通路的資源,使使用者可以直接從代理伺服器獲得,進而減少上遊伺服器的壓力,加快整個通路速度。文法:proxy_cache zone | off ; # zone 是共享記憶體的名稱

預設值:proxy_cache off;

上下文:http、server、locationproxy_cache_path
設定緩存檔案的存放路徑。文法:proxy_cache_path path [level=levels] ...可選參數省略,下面會詳細列舉

預設值:proxy_cache_path off

上下文:http參數含義:path 緩存檔案的存放路徑;
level path 的目錄層級;
keys_zone 設定共享記憶體;
inactive 在指定時間内沒有被通路,緩存會被清理,預設10分鐘;
proxy_cache_key設定緩存檔案的 key 。文法:proxy_cache_key

預設值:proxy_cache_key $scheme$proxy_host$request_uri;

上下文:http、server、location
proxy_cache_valid配置什麼狀态碼可以被緩存,以及緩存時長。文法:proxy_cache_valid [code...] time;

上下文:http、server、location

配置示例:proxy_cache_valid 200 304 2m;; # 說明對于狀态為200和304的緩存檔案的緩存時間是2分鐘proxy_no_cache定義相應儲存到緩存的條件,如果字元串參數的至少一個值不為空且不等于“ 0”,則将不儲存該響應到緩存。文法:proxy_no_cache string;

上下文:http、server、location

示例:proxy_no_cache $http_pragma    $http_authorization;proxy_cache_bypass定義條件,在該條件下将不會從緩存中擷取響應。文法:proxy_cache_bypass string;

上下文:http、server、location

示例:proxy_cache_bypass $http_pragma    $http_authorization;upstream_cache_status 變量它存儲了緩存是否命中的資訊,會設定在響應頭資訊中,在調試中非常有用。MISS: 未命中緩存
HIT:命中緩存
EXPIRED: 緩存過期
STALE: 命中了陳舊緩存
REVALIDDATED: Nginx驗證陳舊緩存依然有效
UPDATING: 内容陳舊,但正在更新
BYPASS: X響應從原始伺服器擷取配置執行個體我們把 121.42.11.34 伺服器作為上遊伺服器,做如下配置( /etc/nginx/conf.d/cache.conf ):server {
  listen 1010;
  root /usr/share/nginx/html/1010;
  location / {
   index index.html;
  }
}

server {
  listen 1020;
  root /usr/share/nginx/html/1020;
  location / {
   index index.html;
  }
}把 121.5.180.193 伺服器作為代理伺服器,做如下配置( /etc/nginx/conf.d/cache.conf ):proxy_cache_path /etc/nginx/cache_temp levels=2:2 keys_zone=cache_zone:30m max_size=2g inactive=60m use_temp_path=off;

upstream cache_server{
  server 121.42.11.34:1010;
  server 121.42.11.34:1020;
}

server {
  listen 80;
  server_name cache.lion.club;
  location / {
    proxy_cache cache_zone; # 設定緩存記憶體,上面配置中已經定義好的
    proxy_cache_valid 200 5m; # 緩存狀态為200的請求,緩存時長為5分鐘
    proxy_cache_key $request_uri; # 緩存檔案的key為請求的URI
    add_header Nginx-Cache-Status $upstream_cache_status # 把緩存狀态設定為頭部資訊,響應給用戶端
    proxy_pass http://cache_server; # 代理轉發
  }
}緩存就是這樣配置,我們可以在 /etc/nginx/cache_temp 路徑下找到相應的緩存檔案。對于一些實時性要求非常高的頁面或資料來說,就不應該去設定緩存,下面來看看如何配置不緩存的内容。...

server {
  listen 80;
  server_name cache.lion.club;
  # URI 中字尾為 .txt 或 .text 的設定變量值為 "no cache"
  if ($request_uri ~ \.(txt|text)$) {
   set $cache_name "no cache"
  }
  
  location / {
    proxy_no_cache $cache_name; # 判斷該變量是否有值,如果有值則不進行緩存,如果沒有值則進行緩存
    proxy_cache cache_zone; # 設定緩存記憶體
    proxy_cache_valid 200 5m; # 緩存狀态為200的請求,緩存時長為5分鐘
    proxy_cache_key $request_uri; # 緩存檔案的key為請求的URI
    add_header Nginx-Cache-Status $upstream_cache_status # 把緩存狀态設定為頭部資訊,響應給用戶端
    proxy_pass http://cache_server; # 代理轉發
  }
}HTTPS在學習如何配置 HTTPS 之前,我們先來簡單回顧下 HTTPS 的工作流程是怎麼樣的?它是如何進行加密保證安全的?HTTPS 工作流程1. 用戶端(浏覽器)通路 https://www.baidu.com 百度網站;2. 百度伺服器傳回 HTTPS 使用的 CA 證書;3. 浏覽器驗證 CA 證書是否為合法證書;4. 驗證通過,證書合法,生成一串随機數并使用公鑰(證書中提供的)進行加密;5. 發送公鑰加密後的随機數給百度伺服器;6. 百度伺服器拿到密文,通過私鑰進行解密,擷取到随機數(公鑰加密,私鑰解密,反之也可以);7. 百度伺服器把要發送給浏覽器的内容,使用随機數進行加密後傳輸給浏覽器;8. 此時浏覽器可以使用随機數進行解密,擷取到伺服器的真實傳輸内容;這就是 HTTPS 的基本運作原理,使用對稱加密和非對稱機密配合使用,保證傳輸内容的安全性。關于HTTPS更多知識,可以檢視作者的另外一篇文章《學習 HTTP 協定》。配置證書下載下傳證書的壓縮檔案,裡面有個 Nginx 檔案夾,把 xxx.crt 和 xxx.key 檔案拷貝到伺服器目錄,再進行如下配置:server {
  listen 443 ssl http2 default_server; # SSL 通路端口号為 443
  server_name lion.club; # 填寫綁定證書的域名(我這裡是随便寫的)
  ssl_certificate /etc/nginx/https/lion.club_bundle.crt; # 證書位址
  ssl_certificate_key /etc/nginx/https/lion.club.key; # 私鑰位址
  ssl_session_timeout 10m;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # 支援ssl協定版本,預設為後三個,主流版本是[TLSv1.2]
 
  location / {
    root         /usr/share/nginx/html;
    index        index.html index.htm;
  }
}如此配置後就能正常通路 HTTPS 版的網站了。配置跨域 CORS先簡單回顧下跨域究竟是怎麼回事。跨域的定義同源政策限制了從同一個源加載的文檔或腳本如何與來自另一個源的資源進行互動。這是一個用于隔離潛在惡意檔案的重要安全機制。通常不允許不同源間的讀操作。同源的定義如果兩個頁面的協定,端口(如果有指定)和域名都相同,則兩個頁面具有相同的源。下面給出了與 URL http://store.company.com/dir/page.html 的源進行對比的示例:http://store.company.com/dir2/other.html 同源
https://store.company.com/secure.html 不同源,協定不同
http://store.company.com:81/dir/etc.html 不同源,端口不同
http://news.company.com/dir/other.html 不同源,主機不同不同源會有如下限制:Web 資料層面,同源政策限制了不同源的站點讀取目前站點的 Cookie 、 IndexDB 、 LocalStorage 等資料。
DOM 層面,同源政策限制了來自不同源的 JavaScript 腳本對目前 DOM 對象讀和寫的操作。
網絡層面,同源政策限制了通過 XMLHttpRequest 等方式将站點的資料發送給不同源的站點。
Nginx 解決跨域的原理例如:前端 server 的域名為:fe.server.com
後端服務的域名為:dev.server.com
現在我在 fe.server.com 對 dev.server.com 發起請求一定會出現跨域。現在我們隻需要啟動一個 Nginx 伺服器,将 server_name 設定為 fe.server.com 然後設定相應的 location 以攔截前端需要跨域的請求,最後将請求代理回 dev.server.com 。如下面的配置:server {
 listen      80;
 server_name  fe.server.com;
 location / {
  proxy_pass dev.server.com;
 }
}這樣可以完美繞過浏覽器的同源政策:fe.server.com 通路 Nginx 的 fe.server.com 屬于同源通路,而 Nginx 對服務端轉發的請求不會觸發浏覽器的同源政策。配置開啟 gzip 壓縮GZIP 是規定的三種标準 HTTP 壓縮格式之一。目前絕大多數的網站都在使用 GZIP 傳輸 HTML、CSS 、 JavaScript 等資源檔案。對于文本檔案, GZiP 的效果非常明顯,開啟後傳輸所需流量大約會降至 1/4~1/3 。并不是每個浏覽器都支援 gzip 的,如何知道用戶端是否支援 gzip 呢,請求頭中的 Accept-Encoding 來辨別對壓縮的支援。


啟用 gzip 同時需要用戶端和服務端的支援,如果用戶端支援 gzip 的解析,那麼隻要服務端能夠傳回 gzip 的檔案就可以啟用 gzip 了,我們可以通過 Nginx 的配置來讓服務端支援 gzip 。下面的 respone 中 content-encoding:gzip ,指服務端開啟了 gzip 的壓縮方式。


在 /etc/nginx/conf.d/ 檔案夾中建立配置檔案 gzip.conf :# # 預設off,是否開啟gzip
gzip on; 
# 要采用 gzip 壓縮的 MIME 檔案類型,其中 text/html 被系統強制啟用;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

# ---- 以上兩個參數開啟就可以支援Gzip壓縮了 ---- #

# 預設 off,該子產品啟用後,Nginx 首先檢查是否存在請求靜态檔案的 gz 結尾的檔案,如果有則直接傳回該 .gz 檔案内容;
gzip_static on;

# 預設 off,nginx做為反向代理時啟用,用于設定啟用或禁用從代理伺服器上收到相應内容 gzip 壓縮;
gzip_proxied any;

# 用于在響應消息頭中添加 Vary:Accept-Encoding,使代理伺服器根據請求頭中的 Accept-Encoding 識别是否啟用 gzip 壓縮;
gzip_vary on;

# gzip 壓縮比,壓縮級别是 1-9,1 壓縮級别最低,9 最高,級别越高壓縮率越大,壓縮時間越長,建議 4-6;
gzip_comp_level 6;

# 擷取多少記憶體用于緩存壓縮結果,16 8k 表示以 8k*16 為機關獲得;
gzip_buffers 16 8k;

# 允許壓縮的頁面最小位元組數,頁面位元組數從header頭中的 Content-Length 中進行擷取。預設值是 0,不管頁面多大都壓縮。建議設定成大于 1k 的位元組數,小于 1k 可能會越壓越大;
# gzip_min_length 1k;

# 預設 1.1,啟用 gzip 所需的 HTTP 最低版本;
gzip_http_version 1.1;
其實也可以通過前端建構工具例如 webpack 、rollup 等在打生産包時就做好 Gzip 壓縮,然後放到 Nginx 伺服器中,這樣可以減少伺服器的開銷,加快通路速度。
關于 Nginx 的實際應用就學習到這裡,相信通過掌握了 Nginx 核心配置以及實戰配置,之後再遇到什麼需求,我們也能輕松應對。接下來,讓我們再深入一點學習下 Nginx 的架構。Nginx 架構程序結構多程序結構 Nginx 的程序模型圖:
多程序中的 Nginx 程序架構如下圖所示,會有一個父程序( Master Process ),它會有很多子程序( Child Processes )。Master Process 用來管理子程序的,其本身并不真正處理使用者請求。
某個子程序 down 掉的話,它會向 Master 程序發送一條消息,表明自己不可用了,此時 Master 程序會去新起一個子程序。
某個配置檔案被修改了 Master 程序會去通知 work 程序擷取新的配置資訊,這也就是我們所說的熱部署。
子程序間是通過共享記憶體的方式進行通信的。
配置檔案重載原理reload 重載配置檔案的流程:1. 向 master 程序發送 HUP 信号( reload 指令);2. master 程序檢查配置文法是否正确;3. master 程序打開監聽端口;4. master 程序使用新的配置檔案啟動新的 worker 子程序;5. master 程序向老的 worker 子程序發送 QUIT 信号;6. 老的 worker 程序關閉監聽句柄,處理完目前連接配接後關閉程序;7. 整個過程 Nginx 始終處于平穩運作中,實作了平滑更新,使用者無感覺;Nginx 子產品化管理機制Nginx 的内部結構是由核心部分和一系列的功能子產品所組成。這樣劃分是為了使得每個子產品的功能相對簡單,便于開發,同時也便于對系統進行功能擴充。Nginx 的子產品是互相獨立的,低耦合高内聚。

PS:歡迎在留言區留下你的觀點,一起讨論提高。如果今天的文章讓你有新的啟發,歡迎轉發分享給更多人。


版權申明:内容來源網絡,版權歸原創者所有。除非無法确認,我們都會标明作者及出處,如有侵權煩請告知,我們會立即删除并表示歉意。謝謝!

歡迎加入後端架構師交流群,在背景回複“學習”即可。

最近面試BAT,整理一份面試資料《Java面試BAT通關手冊》,覆寫了Java核心技術、JVM、Java并發、SSM、微服務、資料庫、資料結構等等。在這裡,我為大家準備了一份2021年最新最全BAT等大廠Java面試經驗總結。
别找了,想擷取史上最簡單的Java大廠面試題學習資料
掃下方二維碼回複「面試」就好了


猜你還想看
阿裡、騰訊、百度、華為、京東最新面試題彙集
阿裡面試官的 "說一下從url輸入到傳回請求的過程" 問的難度就是不一樣!

面試官:Java 反射是什麼?我回答不上來!

Git使用的奇技淫巧,看這篇就夠了!

嘿,你在看嗎?