2W 字總結 !體系化帶你全面認識 Nginx

前言

做爲一名開發人員,你是否是常常碰到領導讓你上服務器去修改 Nginx 配置,然而你會以「我是開發,這個我不會」爲理由搪塞過去呢!今天就讓咱們一塊兒告別這種尷尬,向「真正」的程序員邁進!!!javascript

Nginx 概述

圖片

Nginx 是開源、高性能、高可靠的 Web 和反向代理服務器,並且支持熱部署,幾乎能夠作到 7 * 24 小時不間斷運行,即便運行幾個月也不須要從新啓動,還能在不間斷服務的狀況下對軟件版本進行熱更新。性能是 Nginx 最重要的考量,其佔用內存少、併發能力強、能支持高達 5w 個併發鏈接數,最重要的是, Nginx 是免費的並能夠商業化,配置使用也比較簡單。css

Nginx 特色

  • 高併發、高性能;
  • 模塊化架構使得它的擴展性很是好;
  • 異步非阻塞的事件驅動模型這點和 Node.js 類似;
  • 相對於其它服務器來講它能夠連續幾個月甚至更長而不須要重啓服務器使得它具備高可靠性;
  • 熱部署、平滑升級;
  • 徹底開源,生態繁榮;

Nginx 做用

Nginx 的最重要的幾個使用場景:html

  • 靜態資源服務,經過本地文件系統提供服務;
  • 反向代理服務,延伸出包括緩存、負載均衡等;
  • API 服務, OpenResty ;

對於前端來講 Node.js 並不陌生, Nginx 和 Node.js 的不少理念相似, HTTP 服務器、事件驅動、異步非阻塞等,且 Nginx 的大部分功能使用 Node.js 也能夠實現,但 Nginx 和 Node.js 並不衝突,都有本身擅長的領域。Nginx 擅長於底層服務器端資源的處理(靜態資源處理轉發、反向代理,負載均衡等), Node.js 更擅長上層具體業務邏輯的處理,二者能夠完美組合。前端

用一張圖表示:java

圖片

Nginx 安裝

本文演示的是 Linux centOS 7.x 的操做系統上安裝 Nginx ,至於在其它操做系統上進行安裝能夠網上自行搜索,都很是簡單的。node

使用 yum 安裝 Nginx :

yum install nginx -y

安裝完成後,經過 rpm -ql nginx 命令查看 Nginx 的安裝信息:webpack

# 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

主要關注的文件夾有兩個:nginx

  • /etc/nginx/conf.d/ 是子配置項存放處, /etc/nginx/nginx.conf 主配置文件會默認把這個文件夾中全部子配置項都引入;
  • /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  # 重啓 
Nginxnginx -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;   # 同上
    }
}
  • main 全局配置,對全局生效;
  • events 配置影響 Nginx 服務器與用戶的網絡鏈接;
  • http 配置代理,緩存,日誌定義等絕大多數功能和第三方模塊的配置;
  • server 配置虛擬主機的相關參數,一個 http 塊中能夠有多個 server 塊;
  • location 用於配置匹配的 uri ;
  • upstream 配置後端服務器具體地址,負載均衡配置不可或缺的部分;

用一張圖清晰的展現它的層級結構:web

圖片

配置文件 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_resolution

worker 子進程內部使用的計時器精度,調整時間間隔越大,系統調用越少,有利於性能提高;反之,系統調用越多,性能降低。

timer_resolution 100ms;

在 Linux 系統中,用戶須要獲取計時器時須要向操做系統內核發送請求,有請求就必然會有開銷,所以這個間隔越大開銷就越小。

daemon

指定 Nginx 的運行方式,前臺仍是後臺,前臺用於調試,後臺用於生產。

daemon off; # 默認是on,後臺運行模式

配置文件 events 段核心參數

use

Nginx 使用何種事件驅動模型。

use method; # 不推薦配置它,讓nginx本身選擇method 可選值爲:select、poll、kqueue、epoll、/dev/poll、eventport

workr_connections

worker 子進程可以處理的最大併發鏈接數。

worker_connections 1024 # 每一個子進程的最大鏈接數爲1024

accept_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 配置實例:

一、配置本地 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 解析,若是使用阿里雲上購買的域名,則須要在阿里雲上設置好域名解析。

二、配置阿里雲 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;
 }
}

三、訪問分析

當訪問 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 。

語法:rewrite 正則表達式 要替換的內容 [flag];上下文:server、location、if

示例:rewirte /images/(._.jpg)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 將這些數據以變量的形式提供給使用者。

下面列舉些項目中經常使用的變量:

remote_addr #客戶端 IP 地址
remote_port #客戶端端口
server_addr #服務端 IP 地址
server_port #服務端端口
server_protocol #服務端協議
binary_remote_addr #二進制格式的客戶端 IP 地址
connection #TCP 鏈接的序號,遞增
connection_request #TCP 鏈接當前的請求數量
uri #請求的URL,不包含參數
request_uri #請求的URL,包含參數
scheme #協議名, http 或 https
request_method #請求方法
request_length #所有請求的長度,包含請求行、請求頭、請求體
args #所有參數字符串
arg_參數名 #獲取特定參數值
is_args #URL 中是否有參數,有的話返回 ? ,不然返回空
query_string #與 args 相同
host #請求信息中的 Host ,若是請求中沒有 Host 行,則在請求頭中找,最後使用 nginx 中設置的 server_name 。
http_user_agent #用戶瀏覽器
http_referer #從哪些連接過來的請求
http_via #每通過一層代理服務器,都會添加相應的信息
http_cookie #獲取用戶 cookie
request_time #處理請求已消耗的時間
https #是否開啓了 https ,是則返回 on ,不然返回空
request_filename #磁盤文件系統待訪問文件的完整路徑
document_root #由 URI 和 root/alias 規則生成的文件夾路徑
limit_rate #返回響應時的速度上限值

實例演示 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:808... 時,因爲 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/html

Nginx 的配置還有很是多,以上只是羅列了一些經常使用的配置,在實際項目中仍是要學會查閱文檔。

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]上下文:upstream

parameters 可選值:

  • weight=number 權重值,默認爲1;
  • max_conns=number 上游服務器的最大併發鏈接數;
  • fail_timeout=time 服務器不可用的斷定時間;
  • max_fails=numer 服務器不可用的檢查次數;
  • backup 備份服務器,僅當其餘服務器都不可用時纔會啓用;
  • down 標記服務器長期不可用,離線維護;

keepalive

限制每一個 worker 子進程與上游服務器空閒長鏈接的最大數量。

keepalive connections;
上下文:upstream

示例:[keepalive](http://mp.weixin.qq.com/s?__b...
485067&idx=1&sn=d5585b021802dfa47fb9cd8e01ddfb1d&chksm=e91b639
7de6cea81179917290cde1ff505291cee65f08d78f6a48fee90425db7e19b025fa683&scene=21#wechat_redirect) 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/proxy

URL 參數原則

  • URL 必須以 httphttps 開頭;
  • URL 中能夠攜帶變量;
  • URL 中是否帶 URI ,會直接影響發往上游請求的 URL ;

接下來讓咱們來看看兩種常見的 URL 用法:

這兩種用法的區別就是帶 / 和不帶 / ,在配置代理時它們的區別可大了:

  • 不帶 / 意味着 Nginx 不會修改用戶 URL ,而是直接透傳給上游的應用服務器;
  • 帶 / 意味着 Nginx 會修改用戶 URL ,修改方法是將 location 後的 URL 從用戶 URL 中刪除;

不帶 / 的用法:

location /bbs/{  proxy_pass http://127.0.0.1:8080;}

分析:

  • 用戶請求 URL :/bbs/abc/test.html
  • 請求到達 Nginx 的 URL :/bbs/abc/test.html
  • 請求到達上游應用服務器的 URL :/bbs/abc/test.html

帶 / 的用法:

location /bbs/{  proxy_pass http://127.0.0.1:8080/;}

分析:

  • 用戶請求 URL :/bbs/abc/test.html
  • 請求到達 Nginx 的 URL :/bbs/abc/test.html
  • 請求到達上游應用服務器的 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 \nserver{
  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';
  }
}

配置完成後:

  • nginx -t 檢測配置是否正確;
  • nginx -s reload 重啓 Nginx 服務器;
  • 執行 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/hosts121.5.180.193 balance.lion.club

在客戶端機器執行 curl http://balance.lion.club/bala... 命令:

圖片

不難看出,負載均衡的配置已經生效了,每次給咱們分發的上游服務器都不同。就是經過簡單的輪詢策略進行上游服務器分發。

接下來,咱們再來了解下 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_nme balance.lion.club;
  
  location /balance/ {
   proxy_pass http://demo_server;
  }
}

最後你會發現,負載均衡的配置其實一點都不復雜。

配置緩

緩存能夠很是有效的提高性能,所以不管是客戶端(瀏覽器),仍是代理服務器( Nginx ),乃至上游服務器都多少會涉及到緩存。可見緩存在每一個環節都是很是重要的。下面讓咱們來學習 Nginx 中如何設置緩存策略。

proxy_cache

存儲一些以前被訪問過、並且可能將要被再次訪問的資源,使用戶能夠直接從代理服務器得到,從而減小上游服務器的壓力,加快整個訪問速度。

語法:proxy_cache zone | off ; # zone 是共享內存的名稱默認值:proxy_cache off;上下文:http、server、location

proxy_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 工做流程

  • 客戶端(瀏覽器)訪問 https://www.baidu.com 百度網站;
  • 百度服務器返回 HTTPS 使用的 CA 證書
  • 瀏覽器驗證 CA 證書是否爲合法證書;
  • 驗證經過,證書合法,生成一串隨機數並使用公鑰(證書中提供的)進行加密;
  • 發送公鑰加密後的隨機數給百度服務器;
  • 百度服務器拿到密文,經過私鑰進行解密,獲取到隨機數(公鑰加密,私鑰解密,反之也能夠);
  • 百度服務器把要發送給瀏覽器的內容,使用隨機數進行加密後傳輸給瀏覽器;
  • 此時瀏覽器可使用隨機數進行解密,獲取到服務器的真實傳輸內容;
  • 這就是 HTTPS 的基本運做原理,使用對稱加密和非對稱機密配合使用,保證傳輸內容的安全性。

配置證書

下載證書的壓縮文件,裏面有個 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/... 的源進行對比的示例:

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 重載配置文件的流程:

  • 向 master 進程發送 HUP 信號( reload 命令);
  • master 進程檢查配置語法是否正確;
  • master 進程打開監聽端口;
  • master 進程使用新的配置文件啓動新的 worker 子進程;
  • master 進程向老的 worker 子進程發送 QUIT 信號;
  • 老的 worker 進程關閉監聽句柄,處理完當前鏈接後關閉進程;
  • 整個過程 Nginx 始終處於平穩運行中,實現了平滑升級,用戶無感知;

Nginx 模塊化管理機制

Nginx 的內部結構是由核心部分和一系列的功能模塊所組成。這樣劃分是爲了使得每一個模塊的功能相對簡單,便於開發,同時也便於對系統進行功能擴展。Nginx 的模塊是互相獨立的,低耦合高內聚。

圖片

總結

相信經過本文的學習,你應該會對 Nginx 有一個更加全面的認識。

都看到這裏了,點在看、留言、轉發朋友圈走一波吧!!

來源: https://juejin.cn/post/694260...

相關文章
相關標籤/搜索