Nginx 反向代理 + 緩存 + 靜態資源服務器 + 負載均衡

前言:

nginx經常掛在嘴邊的就是反向代理,不過他還可以幹很多事,我所瞭解的只是反向代理、靜態文件緩存、靜態資源服務器,對於負載均衡只是略有涉及。


Nginx (“engine x”) 是一個高性能的 HTTP 和 反向代理 服務器 ,也是一個 IMAP/POP3/SMTP 代理 服務器 。 Nginx 是由 Igor Sysoev 為俄羅斯訪問量第二的 Rambler.ru 站點開發的,第一個公開版本0.1.0發佈於2004年10月4日。其將源代碼以類BSD許可證的形式發佈,因它的穩定性、豐富的功能集、示例配置文件和低系統資源的消耗而聞名

引用一下菜鳥教程的簡介:Nginx功能豐富,可作為HTTP服務器,也可作為反向代理服務器,郵件服務器。支持FastCGI、SSL、Virtual Host、URL Rewrite、Gzip等功能。並且支持很多第三方的模塊擴展。Nginx的穩定性、功能集、示例配置文件和低系統資源的消耗讓他後來居上,在全球活躍的網站中有12.18%的使用比率,大約為2220萬個網站。

特點 (1):代理服務器,快速高效反向代理,提升網站性能。 (2):負載均衡器,內部支持Rails和PHP,也可支持HTTP代理服務器,對外進行服務。同時支持簡單容錯和利用算法進行負載均衡。 (3):性能方面,Nginx專門為性能設計,實現注重效率。採用Poll模型,可以支持更多的併發連接,並在大併發時佔用很低內存。 (4):穩定性方面,採用分階段資源分配技術,使CPU資源佔用率低。 (5):高可用性方面,支持熱備,啟動迅速。


Nginx 反向代理 + 緩存 + 靜態資源服務器 + 負載均衡

文尾:有免費nginx視頻教程推薦資料

nginx安裝

mac 下安裝

<code>brew install nginx
/<code>

安裝目錄為 /usr/local/Cellar/nginx/1.17.2/ 配置文件目錄為 /usr/local/etc/nginx/nginx.conf服務器默認路徑 /usr/local/var/www

常用命令

mac 下的啟動命令

  • 啟動 nginx
  • 快速停止關閉 nignx -s stop
  • 優雅的關閉 nginx -s quit
  • 承載配置文件 nginx -s reload
  • 查看nginx進程 ps -ef | grep nginx
  • 查看配置文件是否正確 nginx -t
  • 優雅的殺死nginx進程 kill -quit 進程號
  • 快速的殺死nginx進程 kill -term 進程號

nginx配置

nginx 文件的默認配置文件位置 /usr/local/etc/nginx/nginx.conf

打開 /usr/local/etc/nginx/ 目錄可以看到,裡面有很多的配置文件,其中有一個nginx.conf 和 nginx.conf.default兩個配置文件,剛開始安裝的時候,兩個文件的內容是一樣的,所以我們可以肆意的修改nginx.conf搞崩的話就直接把nginx.conf.default中的內容複製過來就行了又是一個新的nginx。

配置文件架構

<code>// nginx全局塊
...

// events塊
events {
...
}

// http 塊
http {
// http全局塊
...

// server塊
server {
...
}

// http全局塊
...
}

/<code>

配置文件加註釋說明

<code># 配置nginx的用戶組 默認為nobody
#user nobody;

# 配置nginx的主線程數量 nginx是一個主線程下面多個子線程
worker_processes 1;


# 配置nginx的錯誤日誌 格式為 log路徑 log級別
# error_log 的日誌級別為: debug info notice warn error crit alert emerg 緊急由低到高
# error_log的默認日誌級別為error,那麼就只有緊急程度大於等於error的才會記錄在日誌
# error_log 的作用域為 main http mail stream server location

#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;

# 指定nginx進程運行文件存放地址
#pid logs/nginx.pid;


events {
# poll是多路複用IO中的一種方式,但是僅用於linux2.6以上內核,可以大大提高nginx的性能
# use poll

# 設置網絡的連接序列化 防止驚群現象發生 默認為 on
# accept_mutex on;

# 設置一個進程是否同時接受多個網絡連接 默認為 off
# multi_accept off

# 最大連接數 默認為 512
worker_connections 1024;
}


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 logs/access.log main;

# sendfile 指定使用 sendfile 系統調用來傳輸文件。優點在於在兩個文件描述符之間傳遞數據(完全在內核中操作),從而避免了數據在內核緩衝區和用戶緩衝區之間的拷貝,效率高,稱之為零拷貝,這個東西有點講究,自行百度
# sendfile 作用域 location server http
sendfile on;

#tcp_nopush on;

# 鏈接超時時間 默認 75s 作用域 http server location
#keepalive_timeout 0;
keepalive_timeout 65;

# 開始gzip壓縮
#gzip on;

server {
# 端口號
listen 8080;
# 域名或ip
server_name localhost;

#charset koi8-r;

#access_log logs/host.access.log main;

# 對請求的路由進行過濾 正則匹配
location / {
root html;

index index.html index.htm;
}

...
}
include servers/*;
}

/<code>

nginx 日誌

nginx的日誌大致分為 access_log 和 error_log。error_log 記錄的是nginx的錯誤日誌。(以下對日誌的理解不是很全面,還只是基礎的)

error_log

  • 記錄nginx錯誤日誌
  • 作用域為 main http mail stream server location
  • 日誌級別 debug info notice warn error crit alert emerg
  • 日誌級別默認為 error 當級別高於或等於指定級別時才會記錄

access_log

  • 記錄請求通過的日誌
  • 作用域為 http server location limit_except
  • 日誌格式默認為 combined
  • 日誌格式是可以自定義的
<code># 定義一個為 main 的日誌格式 

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 logs/access.log main;
/<code>

上方的 log_format 後面類似 $remote_addr 是nginx的內置變量,取值如下

<code>$remote_addr, $http_x_forwarded_for(反向) 記錄客戶端IP地址
$remote_user 記錄客戶端用戶名稱
$request 記錄請求的URL和HTTP協議
$status 記錄請求狀態
$body_bytes_sent 發送給客戶端的字節數,不包括響應頭的大小; 該變量與Apache模塊mod_log_config裡的“%B”參數兼容。
$bytes_sent 發送給客戶端的總字節數。
$connection 連接的序列號。
$connection_requests 當前通過一個連接獲得的請求數量。
$msec 日誌寫入時間。單位為秒,精度是毫秒。
$pipe 如果請求是通過HTTP流水線(pipelined)發送,pipe值為“p”,否則為“.”。
$http_referer 記錄從哪個頁面鏈接訪問過來的
$http_user_agent 記錄客戶端瀏覽器相關信息
$request_length 請求的長度(包括請求行,請求頭和請求正文)。
$request_time 請求處理時間,單位為秒,精度毫秒; 從讀入客戶端的第一個字節開始,直到把最後一個字符發送給客戶端後進行日誌寫入為止。

$time_iso8601 ISO8601標準格式下的本地時間。
$time_local 通用日誌格式下的本地時間。

/<code>

反向代理

正向代理 反向代理

  • 正向代理大概的意思就是,客戶端發送一個請求,這個請求包含服務器地址,那麼代理服務器收到了請求後會將請求發送到客戶端指定的服務器,並將響應內容傳遞給客戶端,在這個過程中,客戶端是知道請求的服務器地址的,但是服務器是不知道哪個客戶端請求的。VPN做的就是這個事。
  • 反向代理大概的意思就是,客戶端發送一個請求給代理服務器,由代理服務器來決定這個請求該交給哪個服務器,這就是實現了服務器負載均衡,可以將請求轉發到比較空閒的服務器來響應,這個時候,代理服務器就是相對於客戶端的服務器,因為此時客戶端也不知道請求交給了哪個服務器。

我所理解的正向代理和反向代理就是這個意思,如有錯誤歡迎下方評論。

proxy_pass

那麼nginx使用的就是proxy_pass屬性來進行反向代理的處理,使用也是很簡單。下面以nodejs開啟一個建立在 localhost:4000 的服務

<code>const http = require('http');

http.createServer(function(req, res){
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('server 4000');
}).listen(4000);
/<code>

請求 localhost:4000 可以打開我們的頁面

Nginx 反向代理 + 緩存 + 靜態資源服務器 + 負載均衡


那麼我們需要做的是將 localhost:5000的所有請求都代理到4000這個server裡,這樣就會出現我們訪問5000和訪問4000一樣的效果。具體配置如下

<code>server {
# 監聽 localhost:5000
listen 5000;
server_name localhost;
# / 表示匹配所有的請求,所有的請求都會經過這個過濾器
location / {
# 設定請求轉發的地址
\t proxy_pass http://localhost:4000;
}
}
/<code>

這邊需要注意的是 proxy_pass 的寫法,必須是http://或者https://開頭的,http頭是不能省的。

請求5000端口效果如下:

Nginx 反向代理 + 緩存 + 靜態資源服務器 + 負載均衡


上方的例子過於簡單,那麼這一個和上面的有點類似,這次是將4000的端口號代理到www.baidu.com。修改一下proxy_pass

<code>server {
# 監聽 localhost:5000
listen 5000;
server_name localhost;
# / 表示匹配所有的請求,所有的請求都會經過這個過濾器
location / {
# 設定請求轉發的地址
\t proxy_pass https://www.baidu.com;
}
}
/<code>

這樣就可以了,至於這邊寫的是http 還是 https,這個倒是不影響,因為百度內部會自動將http轉成https畢竟安全嘛。

那麼按照剛剛的思路就是監聽 www.baidu.com 然後設置一下 proxy_pass 為 localhost:4000

配置如下

<code>server {
listen 80;
server_name www.baidu.com;

location / {
\t proxy_pass http://localhost:4000;
}
}
/<code>

試一下,是不是沒有用,沒有用就對了。要是這麼輕鬆的搞定nginx還玩個蛋。那麼這個裡面又有點操作了,先看正確的配置,修改本地的hosts文件,mac下的文件位置為 /etc/hosts但是需要 sudo 來進行修改,畢竟這個文件比較重要嘛

<code>sudo vim /etc/hosts
/<code>

添加一句

Nginx 反向代理 + 緩存 + 靜態資源服務器 + 負載均衡


<code>server {
listen 80;
server_name baidu.com;

location / {
\t proxy_pass http://127.0.0.1:4000;
}
}
/<code>

一般在本地開發的時候我們都會修改本地的hosts文件,但是會遇到一個問題就是有的時候是有用的有的時候又沒用了,我這邊的解決辦法是,每次修改完hosts文件就清楚瀏覽器的瀏覽數據,尤其是緩存這一塊的東西。

Nginx 反向代理 + 緩存 + 靜態資源服務器 + 負載均衡

如果遇到nginx配置完全正確hosts文件也配置了,但是還是沒有用,不妨清一下緩存,至少在我這是每次都是清完緩存才有用的。

nginx跨域

跨域的解決辦法就是在header裡面加上允許跨域的源等信息

<code>location / {  
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';

if ($request_method = 'OPTIONS') {
return 204;
}
}
/<code>

但是在實際項目裡。origin還是不要設置為*比較好,因為前端使用axios的話在獲取session這一塊會出現問題。

nginx緩存

這邊有一個需要注意的地方,nginx作為靜態資源服務器的時候是不做緩存的,只有當nginx進行反向代理的時候才具備緩存這個功能。我一開始寫了半天發現鳥用都沒有,最後才發現只有做代理的時候才具備緩存。

各大瀏覽器本身已經具有緩存了,比如說谷歌,我們可以寫一個html,然後在html引入一張圖片,我們可以看看瀏覽器是怎麼對圖片這些靜態資源進行緩存的。

<code>





<title>Document/<title>





/<code>

這個html代碼我使用http-server部署在了http-server -a 127.0.0.1 -p 4000可以看出是在127.0.0.1 4000端口。

這是首次加載的時候的狀況

Nginx 反向代理 + 緩存 + 靜態資源服務器 + 負載均衡

刷新一下

Nginx 反向代理 + 緩存 + 靜態資源服務器 + 負載均衡

那麼區別還是很大的

  • html文件的狀態碼從200到304,304狀態碼錶明該文件是從緩存中讀取
  • jpg文件可以發現在size這一列,多了一個memory cache,這表明這個圖片是從瀏覽器緩存中讀取的
  • 各個文件的加載事件明顯減少,尤其是圖片

可能有的人會發現第一次加載的時候,顯示的是from desk cache,那麼chrome瀏覽器的緩存分為兩種,一種是磁盤緩存一種是內存緩存,

官方文檔:

Chrome employs two caches — an on-disk cache and a very fast in-memory cache. The lifetime of an in-memory cache is attached to the lifetime of a render process, which roughly corresponds to a tab. Requests that are answered from the in-memory cache are invisible to the web request API. If a request handler changes its behavior (for example, the behavior according to which requests are blocked), a simple page refresh might not respect this changed behavior. To make sure the behavior change goes through, call handlerBehaviorChanged() to flush the in-memory cache. But don't do it often; flushing the cache is a very expensive operation. You don't need to call handlerBehaviorChanged() after registering or unregistering an event listener.

大概意思就是:chrome有兩種緩存,一種是desk cache一種是memory cache,然後memory cache的效率高於前者。

那麼打開chrome devtools點開圖片可以發現

Nginx 反向代理 + 緩存 + 靜態資源服務器 + 負載均衡


在cache-control後面有一個max-age,那麼具體的有關緩存的技術這邊就不說了我回頭整理一下

那麼針對不同類型的文件進行緩存還是很簡單的,需要注意的在於location的正則匹配

那麼第一種最簡單的緩存,就是直接設置expires 緩存時間

設置expires

<code>location ~ .*\\.(jpg|png)$ {
\tproxy_pass http://127.0.0.1:4000;
expires 3m;
}
/<code>
Nginx 反向代理 + 緩存 + 靜態資源服務器 + 負載均衡


expires是以秒為單位的,那麼我們設置為3m 也就是180秒,發現確實是可以的。

proxy_cache_path 的使用

那麼我們也可以指定我們的nginx緩存目錄,通過proxy_cache_path 屬性

<code>proxy_cache_path /tmp/cache/test levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;
location ~ .*\\.(jpg|png)$ {
\t proxy_pass http://127.0.0.1:4000;
\t proxy_cache my_cache;
\t proxy_cache_valid 200 304 1y;
\t proxy_cache_valid any 1m;
\t expires 1y;
}
/<code>
  • proxy_cache_path 執行緩存文件的目錄,如果沒有的話需要提前創建,不然nginx會報錯
  • levels 採用2級目錄來存儲
  • key_zone 在共享內存中設置一塊存儲區域來存放緩存的key和metadata(類似使用次數),這樣nginx可以快速判斷一個request是否命中或者未命中緩存,1m可以存儲8000個key,10m可以存儲80000個key
  • max_size 最大cache空間,如果不指定,會使用掉所有disk space,當達到配額後,會刪除最少使用的cache文件
  • inactive 未被訪問文件在緩存中保留時間,在指定時間內未被訪問的文件會被刪除
  • use_temp_path 如果為off,則nginx會將緩存文件直接寫入指定的cache文件中,而不是使用temp_path存儲,official建議為off,避免文件在不同文件系統中不必要的拷貝;
  • proxy_cache 啟用proxy cache,對應著配置的key_zone;
  • proxy_cache_valid 根據不同的狀態碼設置不同的緩存時間

可以查看一下nginx進程,會發現這個時候是有緩存的進程在開著的。

Nginx 反向代理 + 緩存 + 靜態資源服務器 + 負載均衡


這邊可以看到,我們的圖片的緩存時間已經被設置為1年

Nginx 反向代理 + 緩存 + 靜態資源服務器 + 負載均衡


location匹配優先級

在緩存中需要注意的一點就是location的匹配規則和優先級

  • = 開頭表示精確匹配
  • ^~ 開頭表示uri以某個常規字符串開頭,不是正則匹配;
  • ~ 開頭表示區分大小寫的正則匹配;
  • ~* 開頭表示不區分大小寫的正則匹配;
  • / 通用匹配, 如果沒有其它匹配,任何請求都會匹配到;

upstream負載均衡

負載均衡是nginx的另一大特點,可以配置多個服務器,將請求分發到最合適的那臺服務器,避免某一臺服務器請求太多而崩潰。使用upstream屬性來配置

<code>upstream favtomcat {
server 192.168.1.100:4000;
server 192.168.1.111:5000;
}
location / {
root html;
index index.html index.htm;
# 對應上方的 favtomcat
proxy_pass http://favtomcat;
}
/<code>

這是最基礎的負載均衡配置,採用的是輪詢的策略進行負載,每個請求按時間順序逐一分配到不同的後端服務器,適用於圖片服務器集群和純靜態頁面服務器集群。 優點: 方式簡便、成本低廉 缺點: 可靠性低和負載分配不均衡

那麼upstream還有其他的負載策略

weight權重

可以給每一臺服務器設置一個權重,這樣權重高的乾的活也就會多一點

<code>upstream favtomcat {
server 192.168.1.100:4000 weight=5;
server 192.168.1.111:5000 weight=10;
}
/<code>

ip_hash

這種方式是基於客戶端的ip地址,採用hash算法計算下一個請求要選擇哪一個服務器,這樣固定的ip會訪問同一個服務器,可以解決session問題

<code>upstream favtomcat {
ip_hash;
server 192.168.1.100:4000;
server 192.168.1.111:5000;
}
/<code>

least_conn最少鏈接

會將下一個請求分發到當前鏈接數最少的一臺服務器

<code>upstream favtomcat {
least_conn;
server 192.168.1.100:4000;
server 192.168.1.111:5000;
}
/<code>

fair

按後端服務器的響應時間來分配請求,響應時間短的優先分配。

<code>upstream favtomcat {
fair;
server 192.168.1.100:4000;
server 192.168.1.111:5000;
}
/<code>

url_hash

按訪問url的hash結果來分配請求,使每個url定向到同一個後端服務器

<code>upstream backserver { 
server squid1:3128;
server squid2:3128;
hash $request_uri;
hash_method crc32;
} /<code>

推薦資料:

  • NGINX模塊開發
Nginx 反向代理 + 緩存 + 靜態資源服務器 + 負載均衡

  • 服務端網絡處理,Redis到Memcached,再到Nginx
Nginx 反向代理 + 緩存 + 靜態資源服務器 + 負載均衡

  • NGINX源碼解讀
Nginx 反向代理 + 緩存 + 靜態資源服務器 + 負載均衡

關注後臺回覆:1,領取視頻教程學習,希望對你有幫助


分享到:


相關文章: