文章參考:https://blog.csdn.net/physicsdandan/article/details/45667357
什么是代理?
代理在普通生活中的意義就是本來應該你做的事情,你讓別人代你做了,那么那個幫你做的人就是你的代理。和在計算機網絡中代理的概念差不多,
本來是要客戶端做的網絡訪問,現在移交給另外一台機器做,那么那個機器就被稱為代理服務器,代理服務器幫你訪問。過程如下:
正常情況:
client-(send request)->server
代理情況:
client-(send request)->client proxy(send request)->server
什么是反向代理?
反向代理在計算機網絡中是指這么一個過程,一般來說正向代理是客戶端找人來代理把自己的請求轉發給服務器,但是如果是反向代理,找代理的人不再
是客戶端,而是服務端這邊把自己接受的請求轉發給背后的其他機器。
反向代理情況:
client-(send request)->server proxy(send request)->other server
下面看一個示例:
#① part start #運行nginx進程的賬戶 user www; # worker_process 1; error_log /var/log/nginx/error.log pid /var/run/nginx.pid; events{ use epoll; worker_connections 1024; } http{ include /etc/nginx/mime.types; default_type application/octet-stream; access_log /var/log/nginx/access.log main; # sendfile on; # keepalive_timeout 65; gzip on; index index.html index.htm; include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; #② part start # 定義上游服務器列表組 upstream web1 { server 127.0.0.1:111 weight=1; server 127.0.0.1:222 weight=1; } upstream web2 { server 127.0.0.2:111 weight=1; server 127.0.0.2:222 weight=6; server 127.0.0.2:333 weight=7; } #定義一個服務器,其監聽80端口,配置的域名是www.company.com server{ listen 80; # using www domain to access the main website server_name www.company.com; access_log /var/log/nginx/www.log location / { root /home/website_root; } } #③ part start #定義第二個服務器,其同樣監聽80端口,但是匹配域名是web.company.com server{ listen 80; # using web sub domain to access server_name web.company.com; access_log /var/log/nginx/web_access.log location / { root /home/web2_root; proxy_pass http://127.0.0.1:8080/web/; proxy_read_timeout 300; proxy_connect_timeout 300; proxy_redirect off; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; } } #定義第三個服務器,其同樣監聽80端口,但是匹配域名是web1.company.com,並把請求轉發到web1上游服務 server{ listen 80; # using web1 sub domain to access server_name web1.company.com; access_log /var/log/nginx/web1_access.log location / { root /home/web1_root; proxy_pass http://web1; proxy_read_timeout 300; proxy_connect_timeout 300; proxy_redirect off; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; } } #定義第三個服務器,其同樣監聽80端口,但是匹配域名是web2.company.com,並把請求轉發到web2上游服務 server{ listen 80; # using web2 sub domain to access server_name web2.company.com; access_log /var/log/nginx/web2_access.log location / { root /home/web2_root; proxy_pass http://web2; proxy_read_timeout 300; proxy_connect_timeout 300; proxy_redirect off; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; } } }
這個示例都做了什么?
1.第一部分,定義了 nginx 通用規則
2.第二部分,開始定義上游服務器組
3.第三部分,開始定義 server,並指定如何使用第二部分定義的 upstream
總體來說上面的示例提供了四個服務,www、web、web1、web2 4個網站,這個例子很適合一台機器,但是又想避免訪問 url 中帶有端口號,統一使用
域名方式訪問。4個網站都監聽 80 端口,但是分配不同的二級域名即可。這就需要 nginx 反向代理,具體如何實現,我們重新舉一個例子,如下所示:
(1) 只有一台服務器,一個 IP,一個域名 www.xsgzs.com
(2) 這台服務器上有多個應用運行在不同端口,如:
127.0.0.1:4000 運行着一個 博客應用
127.0.0.1:3009 運行着一個博客后台管理系統
我們不期望在訪問的 url 中攜帶有端口號,統一使用域名方式訪問,可以為運行在不同端口號的應用分配二級域名,同時把二級域名都解析到 80 端口,
但是轉發到不同的端口去,希望訪問 www.blog.xsgzs.com 能訪問到 127.0.0.1:4000 ,訪問 www.admin.xsgzs.com 能訪問到 127.0.0.1:3009
具體步驟:
(1) 在 nginx.conf 文件新增 upstream server(上游服務器)
upstream blog.xsgzs { server 127.0.0.1:4000 } upstream admin.xsgzs { server 127.0.0.1:3009 }
(2) 在配置文件中添加 server,都監聽 80 端口
server { listen 80; server_name www.blog.xsgzs.com; location / { proxy_pass http://blog.xsgzs; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } server { listen 80; server_name www.admin.xsgzs.com; location / { proxy_pass http://admin.xsgzs; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }
為什么需要反向代理?
作為服務端代理,自然是一台機器處理不過來了,需要轉發、分散請求給其他服務器做。下面列出一些適用場景:
1.負載均衡:
上面的例子1中 web1 和 web2 上游服務器組都使用了負載均衡,把請求轉發向一組服務器。具體轉發給哪台服務器,nginx 提供了多種負載均衡策略,上面使用的是加權方式
2.一個域名,多個網站。 如上面的例2
3.反向代理另一個作用就是隱藏后面的真實服務,以此達到一定的安全性
仔細講解各個模塊
nginx 配置文件主要分為六個區域
(1) main 全局設置 (2) events (nginx 工作模式) (3) http (http設置) (4) server (主機設置) (5) location (URL匹配) (6) upstream (負載均衡服務器設置)
main 模塊(全局設置)
下面是一個 main 區域,它是一個全局設置
user nobody nobody; worker_processes 2; error_log /usr/local/var/log/nginx/error.log notice; worker_rlimit_nofile 1024;
user 用來設置運行 nginx 服務器的用戶或用戶組,語法格式:
user user [group]
user , 指定可以運行 nginx 服務器的用戶
group,可選項,指定可以運行 nginx 服務器的用戶組
注:只有被指定的用戶或用戶組才有權限啟動 nginx 進程,如果是其他用戶 (test_user) 嘗試啟動 nginx 進程,將會報錯
nginx: [emerg] getpwnam("test_user") failed (2:No such file or directory) in /Nginx/conf/nginx.conf:2
從上面的報錯信息中可以知道,nginx 無法運行的原因是查找 test_user 失敗,引起錯誤的原因在 nginx.conf 文件第二行即
配置運行 nginx 服務器的用戶或用戶組
如果希望所有的用戶或用戶組都有權限啟動 nginx 進程,有兩種方式:一是將此行指令注釋掉、而是將用戶或用戶組設置
為 nobody,這也是 user 指令的默認值
worker_processes 用來指定 nginx 要開啟的子進程數目
worker prcocess 是 nginx 服務器實現並發處理的關鍵所在,從理論上來說,worker process 的值越大,可以支持的並發處理量越大,但實際上它還要受到來自軟件本身、
操作系統本身資源和能力、硬件設備(如:CPU 和 磁盤驅動器)等制約,其語法格式:
worker_processes number | auto
number,來指定 nginx 要開啟的子進程數目
auto,nginx 自動檢測
在默認配置文件中,number = 1,啟動 nginx 服務器之后,使用以下命令可以看到此時的 nginx 除了主進程 master process 之外還生成了一個 worker process,在這里我將
number 指定為 4 ,除了主進程 master process 之外還生成了 4 個 worker process
在這里還有一點需要注意的地方:
worker_processes 指的是操作系統啟動多少個工作進程運行 nginx,注意這里說的是工作進程(worker process)。在 nginx 運行的時候,會啟動兩種進程,一種進程是 master pro
cess(主進程),一種是 worker process(工作進程)。主進程負責監控端口,協調工作進程的工作狀態,分配工作任務,工作進程負責進行任務處理,一般這個參數要和操作系統 CPU 內
核數成倍數。
error_log 關於錯誤日志的配置可以參考這一篇文章:https://www.cnblogs.com/leeyongbard/p/10880356.html
worker_rlimit_nofile 用來設定一個 nginx worker process (工作進程),可打開最大文件數
events 模塊
events 模塊用來指定 nginx 的工作模式以及每一個 worker process 同時開啟的最大連接數,如下:
events { use epoll; #Linux平台 worker_connections 1024; }
use 用來指定 nginx 的工作模式,nginx 支持的工作模式有:select、poll、Kqueue、epoll、rtsig 和 /dev/poll,select 和 poll 是標准的工作模式,Kqueue 和 epoll 是
高效的工作模式,不同的是 epoll 是用在 linux 平台,而 Kqueue 是用在 BSD 系統,而 mac 基於 BSD ,所以 mac 上的 nginx 工作模式是 Kqueue ,epoll 是 Linux 上nginx
工作模式的首選
worker_connections 用來設置允許每一個 worker process 同時開啟的最大連接數,即接收前端的最大請求數。最大客戶端連接數由 worker_processes 和 worker_conn
ectios決定,即 max_clients = worker_processes * worker_connections ,在作為反向代理時,max_clients = worker_processes * worker_connections/4。注意,一個進程建
立一個連接后,進程將打開一個文件副本。所以,worker_connections 的 number 值還受到操作系統設定的,進程最大可打開文件數
其語法格式:
worker_connections number
設置 nginx 進程最大可打開文件數(不能超過系統級別設定的進程可打開最大文件數)
1.更改系統級別 "進程可打開最大文件數"
首先需要要有 root 權限,修改 /etc/security/limits.conf
在主配置文件中添加下面兩句
* soft nofile 327680 * hard nofile 327680
soft 表示應用軟件級別限制的最大可打開文件數,hard 表示操作系統級別限制的最大可打開文件數,"*" 表示對所有用戶都生效
保存配置不會立即生效,需要通過 ulimit 命令 或 重啟系統
ulimit -n 327680
執行命令后,通過 ulimit -a 查看修改是否生效
core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 63704 max locked memory (kbytes, -l) 64 max memory size (kbytes, -m) unlimited open files (-n) 327680 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 10240 cpu time (seconds, -t) unlimited max user processes (-u) 63704 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited
注意,open files 這一項變化了表示修改生效
2. 修改 nginx 軟件級別的 "進程最大可打開文件數"
第一步只是修改了操作系統級別的 "進程最大可打開文件數",作為 nginx 來說,我們還需要對這個軟件進行修改,打開 nginx.conf 主配置文件,修改 worker_rlimit_nofile 屬性
修改完成之后,需要重啟 nginx 配置才能生效
3.驗證 nginx 的 "進程最大可打開文件數" 是否生效
在 Linux 中,所有的進程都會有一個臨時的核心配置文件描述,存放位置:/pro/進程號/limit
我們可以看到,nginx worker process 的進程號分別是:4872、4873、4874、4875,我們選擇其中一個查看其核心配置信息:
可以看到 Max open files 分別是65535,更改配置信息后,重啟 nginx,如上所示方式查看是否生效
http 模塊
http 模塊可以說是最核心的模塊了,它主要負責 HTTP 服務器相關屬性的配置,它里面的 server、upstream 至關重要,下面看一個簡單的 http 模塊配置
http{ include mime.types; default_type application/octet-stream; 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 /usr/local/var/log/nginx/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 10; #gzip on; upstream myproject { ..... } server { .... } }
說一下每個配置項的具體含義
include:nginx 服務器作為 web 服務器,必須能夠識別前端請求過來的資源類型,include mime.types 用來設置 nginx 所能識別的文件類型,mime.types 在
nginx 主配置文件同級目錄下
default_type:設置默認的類型為二進制流,也就是當請求的資源類型在 mime.types 里面未定義時默認使用該類型
access_log、log_format 可以參考這篇文章:https://www.cnblogs.com/leeyongbard/p/10880356.html
sendfile 用於開啟高效的文件傳輸模式。將 tcp_nopush、tcp_nodelay 設置為 on 用於防止網絡阻塞
keepalive_timeout:用於設置與用戶建立連接之后,nginx 服務器可以保持這些連接一段時間
server 模塊
server 模塊是 http 模塊的子模塊,主要用於定義一個虛擬主機,下面先看一個簡單的 server 是如何做的?
server { listen 8080; server_name localhost 192.168.12.10 www.yangyi.com; # 全局定義,如果都是這一個目錄,這樣定義最簡單。 root /Users/yangyi/www; index index.php index.html index.htm; charset utf-8; access_log usr/local/var/log/host.access.log main; error_log usr/local/var/log/host.error.log error; .... }
server,標志定義虛擬主機開始
listen,指定虛擬主機的服務端口
server_name,用來指定 IP 地址或 域名,多個域名之間用空格分開
root,配置請求的根目錄
web 服務器在接收到網絡請求后,需要在服務端指定的根目錄中尋找請求的資源。在 nginx 服務器中 root 指令就是設置這個根目錄的,其語法為:
root path
path 為 nginx 服務器接收到請求后查找資源的根目錄。root 指令可以在 http,server,location 塊中都可以配置,多數情況下 root 指令是配置在 location
塊中,看一個簡單的示例
location /data/ { root /locationtest1; }
當 location 塊接收到 /data/index.html 的請求時,將會在 /locationtest1/data/ 目錄下尋找 index.html 響應請求
index,用於設定只輸入域名時訪問的默認首頁地址,有個先后順序:index.php、index.html、index.htm 如果沒有開啟目錄瀏覽權限,又找不到這些默認首頁,則會報 403
charset,設置網頁的默認編碼格式
access_log,error_log 這里不再說
location 模塊
location 模塊也是一個非常重要且常用的模塊,根據字面意思就可以知道主要用於定位,定位 URL,解析 URL,它提供了非常強大的正則匹配功能,也支持條件判斷匹配
在 nginx 官方文檔中定義的 location 語法為:
location [ = | ~ | ~* | ^~] uri { ................ ................ }
其中,uri 是待匹配的請求字符串,可以是不含正則表達式的字符串,如,/myserver.php,也可以是包含正則表達式的字符串,如,.php$(表示以 .php 結尾)
不包含正則表達式的 uri -> 標准 uri
包含正則表達式的 uri -> 正則 uri
方括號里面的部分是可選項,在介紹四種標識之前先了解下如果不添加此選項時,nginx 服務器是如何在 server 塊中搜索並使用 location 塊和 uri 實現和請求字符串匹配的
在不添加此選項時,nginx 服務器會在 server 塊的多個 location 塊中搜索是否有和標准 uri 匹配的請求字符串,如果有多個可以匹配,就記錄匹配度最高的一個。然后再用
location 塊中的正則 uri 和請求字符串匹配,當正則 uri 匹配成功之后,結束搜索,使用此 location 塊處理請求。如果正則 uri 匹配失敗,就是用上面匹配度最高的 location
塊處理此請求。
四種標識(=、~、~*、^~)
1. =,用於標准 uri 前,要求請求字符串和 uri 嚴格匹配。如果匹配成功,就停止向下繼續搜索並立即使用該 location 塊處理請求 2,~,用於表示 uri 包含正則表達式,並區分大小寫 3,~*,用於表示 uri 包含正則表達式,並且不區分大小寫 4,^~,用於標准 uri 前,要求 nginx 服務器找到和請求字符串匹配度最高的標准 uri 后,立即使用該 location 快處理請求,不再使用 location 塊的正則 uri 和請求字符串做匹配
注意:
我們知道瀏覽器傳送 uri 時,會對一部分 uri 進行編碼,比如,空格會被編碼成 "%20",問號會被編碼成 '%3f"等,"^"有一個特點,它會對 uri 中的這些符號做編碼處理,如,如果 location 塊接收到的 uri 是 /html/%20/data,則當 nginx 服務器搜索到配置為 /html//data 的 location 塊時就可以匹配成功
upstream 模塊
upstream 模塊負責負載均衡,目前 nginx 的負載均衡支持 4 種方式:
1,輪詢(默認)
每個請求按照時間順序逐一分配到不同后端服務器,如果后端服務器 down 掉,則自動剔除,使用戶訪問不受影響
2,weight(指定輪詢權重)
weight 的值越大分配到的訪問概率越高,主要用於后端每台服務器性能不均衡的情況下,或僅僅在主從情況下設置不同的權值,達到有效合理的利用主機資源。
upstream bakend { server 192.168.0.14 weight=10; server 192.168.0.15 weight=10; }
3,ip_hash
每個請求按照訪問 ip 的哈希結果分配,使來自同一個 ip 的訪客固定訪問一台后端服務器
upstream bakend { ip_hash; server 192.168.0.14:88; server 192.168.0.15:80; }
4,fair
比 weight、ip_hash 更加智能的負載均衡算法,fair 可以根據頁面大小和加載時間長短智能地進行負載均衡,也就是根據后端服務器的響應時間來分配請求,響應時間
的優先分配。nginx 本身並不支持 fair,如果要使用這種調度算法,則需要安裝 upstream_fair 模塊。
upstream backend { server server1; server server2; fair; }
4,url_hash
按照訪問 url 的哈希結果分配,使每一個 url 定向到后端某一台服務器,可以進一步提高后端緩存服務器的效率,不過 nginx 本身是不支持這種調度算法的,需要安裝
nginx 的 hash 軟件包
例:在upstream中加入hash語句,server語句中不能寫入weight等其他的參數,hash_method是使用的hash算法 upstream backend { server squid1:3128; server squid2:3128; hash $request_uri; hash_method crc32; }
在 nginx 的 upstream 模塊,可以設置每台后端服務器在負載均衡中的調度狀態,常用的狀態:
1,down,表示當前機器暫時不參與負載均衡 2,backup,預留的備份機器。當其他所有的非 backup 機器出現故障或忙的時候,才會請求 backup 機器,因為此台機器的訪問壓力最小 3,max_fails,允許請求的失敗次數,默認為 1,當超過最大次數時,返回 proxy_next_upstream 模塊定義的錯誤 4,fail_timeout,請求失敗超時時間,在經歷了 max_fails 次失敗后,暫停服務的時間。max_fails 和 fail_timeout 可以一起使用
下面看一個簡單的 upstream 模塊配置:
1,在 http 節點下添加 upstream 節點
upstream linuxidc { server 10.0.6.108:7080; server 10.0.0.85:8980; }
2,將 server 節點下的 location 節點中的 proxy_pass 配置為:http:// + upstream名稱
location / { root hml; index index.html index.htm; proxy_pass http://linuxidc; }
現在負載均衡初步完成了,upstream 按照輪詢(默認)方式進行負載均衡。