nginx經(jīng)常掛在嘴邊的就是反向代理,不過他還可以干很多事贱鼻,我所了解的只是反向代理症昏、靜態(tài)文件緩存肝谭、靜態(tài)資源服務(wù)器攘烛,對(duì)于負(fù)載均衡只是略有涉及。
Nginx (“engine x”) 是一個(gè)高性能的 HTTP 和 反向代理 服務(wù)器 靖秩,也是一個(gè) IMAP/POP3/SMTP 代理 服務(wù)器 沟突。 Nginx 是由 Igor Sysoev 為俄羅斯訪問量第二的 Rambler.ru 站點(diǎn)開發(fā)的扩劝,第一個(gè)公開版本0.1.0發(fā)布于2004年10月4日棒呛。其將源代碼以類BSD許可證的形式發(fā)布簇秒,因它的穩(wěn)定性、豐富的功能集皱坛、示例配置文件和低系統(tǒng)資源的消耗而聞名
引用一下菜鳥教程的簡(jiǎn)介:Nginx功能豐富剩辟,可作為HTTP服務(wù)器抹沪,也可作為反向代理服務(wù)器卦羡,郵件服務(wù)器绿饵。支持FastCGI拟赊、SSL瑟慈、Virtual Host葛碧、URL Rewrite、Gzip等功能乳绕。并且支持很多第三方的模塊擴(kuò)展。Nginx的穩(wěn)定性呻纹、功能集专缠、示例配置文件和低系統(tǒng)資源的消耗讓他后來居上雷酪,在全球活躍的網(wǎng)站中有12.18%的使用比率,大約為2220萬個(gè)網(wǎng)站涝婉。
特點(diǎn)
(1):代理服務(wù)器哥力,快速高效反向代理,提升網(wǎng)站性能墩弯。
(2):負(fù)載均衡器吩跋,內(nèi)部支持Rails和PHP,也可支持HTTP代理服務(wù)器,對(duì)外進(jìn)行服務(wù)渔工。同時(shí)支持簡(jiǎn)單容錯(cuò)和利用算法進(jìn)行負(fù)載均衡。
(3):性能方面氛谜,Nginx專門為性能設(shè)計(jì)杨何,實(shí)現(xiàn)注重效率迁沫。采用Poll模型挺智,可以支持更多的并發(fā)連接,并在大并發(fā)時(shí)占用很低內(nèi)存寄纵。
(4):穩(wěn)定性方面崖媚,采用分階段資源分配技術(shù),使CPU資源占用率低。
(5):高可用性方面,支持熱備,啟動(dòng)迅速。
nginx安裝
mac 下安裝
brew install nginx
安裝目錄為 /usr/local/Cellar/nginx/1.17.2/
配置文件目錄為 /usr/local/etc/nginx/nginx.conf
服務(wù)器默認(rèn)路徑 /usr/local/var/www
常用命令
mac 下的啟動(dòng)命令
啟動(dòng)
nginx
快速停止關(guān)閉
nignx -s stop
優(yōu)雅的關(guān)閉
nginx -s quit
承載配置文件
nginx -s reload
查看nginx進(jìn)程
ps -ef | grep nginx
查看配置文件是否正確
nginx -t
優(yōu)雅的殺死nginx進(jìn)程
kill -quit 進(jìn)程號(hào)
快速的殺死nginx進(jìn)程
kill -term 進(jìn)程號(hào)
nginx配置
nginx 文件的默認(rèn)配置文件位置 /usr/local/etc/nginx/nginx.conf
打開 /usr/local/etc/nginx/
目錄可以看到,里面有很多的配置文件畜隶,啟動(dòng)有一個(gè)nginx.conf
和 nginx.conf.default
兩個(gè)配置文件,剛開始安裝的時(shí)候,兩個(gè)文件的內(nèi)容是一樣的菠赚,所以我們可以肆意的修改nginx.conf
搞崩的話就直接把nginx.conf.default
中的內(nèi)容復(fù)制過來就行了又是一個(gè)新的nginx歌粥。
配置文件架構(gòu)
// nginx全局塊
...
// events塊
events {
...
}
// http 塊
http {
// http全局塊
...
// server塊
server {
...
}
// http全局塊
...
}
配置文件加注釋說明
# 配置nginx的用戶組 默認(rèn)為nobody
#user nobody;
# 配置nginx的主線程數(shù)量 nginx是一個(gè)主線程下面多個(gè)子線程
worker_processes 1;
# 配置nginx的錯(cuò)誤日志 格式為 log路徑 log級(jí)別
# error_log 的日志級(jí)別為: debug info notice warn error crit alert emerg 緊急由低到高
# error_log的默認(rèn)日志級(jí)別為error,那么就只有緊急程度大于等于error的才會(huì)記錄在日志
# error_log 的作用域?yàn)?main http mail stream server location
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
# 指定nginx進(jìn)程運(yùn)行文件存放地址
#pid logs/nginx.pid;
events {
# poll是多路復(fù)用IO中的一種方式,但是僅用于linux2.6以上內(nèi)核,可以大大提高nginx的性能
# use poll
# 設(shè)置網(wǎng)絡(luò)的連接序列化 防止驚群現(xiàn)象發(fā)生 默認(rèn)為 on
# accept_mutex on;
# 設(shè)置一個(gè)進(jìn)程是否同時(shí)接受多個(gè)網(wǎng)絡(luò)連接 默認(rèn)為 off
# multi_accept off
# 最大連接數(shù) 默認(rèn)為 512
worker_connections 1024;
}
http {
# 文件擴(kuò)展名和文件類型映射表
include mime.types;
# 默認(rèn)文件類型
default_type application/octet-stream;
# 日志格式 文章后面會(huì)介紹
#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 系統(tǒng)調(diào)用來傳輸文件氏捞。優(yōu)點(diǎn)在于在兩個(gè)文件描述符之間傳遞數(shù)據(jù)(完全在內(nèi)核中操作),從而避免了數(shù)據(jù)在內(nèi)核緩沖區(qū)和用戶緩沖區(qū)之間的拷貝买窟,效率高,稱之為零拷貝锄贷,這個(gè)東西有點(diǎn)講究,自行百度
# sendfile 作用域 location server http
sendfile on;
#tcp_nopush on;
# 鏈接超時(shí)時(shí)間 默認(rèn) 75s 作用域 http server location
#keepalive_timeout 0;
keepalive_timeout 65;
# 開始gzip壓縮
#gzip on;
server {
# 端口號(hào)
listen 8080;
# 域名或ip
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
# 對(duì)請(qǐng)求的路由進(jìn)行過濾 正則匹配
location / {
root html;
index index.html index.htm;
}
...
}
include servers/*;
}
nginx 日志
nginx的日志大致分為 access_log
和 error_log
几莽。error_log 記錄的是nginx的錯(cuò)誤日志。(以下對(duì)日志的理解不是很全面庆尘,還只是基礎(chǔ)的)
error_log
- 記錄nginx錯(cuò)誤日志
- 作用域?yàn)?
main http mail stream server location
- 日志級(jí)別
debug info notice warn error crit alert emerg
- 日志級(jí)別默認(rèn)為 error 當(dāng)級(jí)別高于或等于指定級(jí)別時(shí)才會(huì)記錄
access_log
- 記錄請(qǐng)求通過的日志
- 作用域?yàn)?
http server location limit_except
- 日志格式默認(rèn)為
combined
- 日志格式是可以自定義的
# 定義一個(gè)為 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;
上方的 log_format
后面類似 $remote_addr
是nginx的內(nèi)置變量惠勒,取值如下
$remote_addr, $http_x_forwarded_for(反向) 記錄客戶端IP地址
$remote_user 記錄客戶端用戶名稱
$request 記錄請(qǐng)求的URL和HTTP協(xié)議
$status 記錄請(qǐng)求狀態(tài)
$body_bytes_sent 發(fā)送給客戶端的字節(jié)數(shù),不包括響應(yīng)頭的大卸芗啤逝淹; 該變量與Apache模塊mod_log_config里的“%B”參數(shù)兼容栅葡。
$bytes_sent 發(fā)送給客戶端的總字節(jié)數(shù)。
$connection 連接的序列號(hào)。
$connection_requests 當(dāng)前通過一個(gè)連接獲得的請(qǐng)求數(shù)量黔龟。
$msec 日志寫入時(shí)間。單位為秒纹蝴,精度是毫秒。
$pipe 如果請(qǐng)求是通過HTTP流水線(pipelined)發(fā)送集漾,pipe值為“p”切黔,否則為“.”。
$http_referer 記錄從哪個(gè)頁(yè)面鏈接訪問過來的
$http_user_agent 記錄客戶端瀏覽器相關(guān)信息
$request_length 請(qǐng)求的長(zhǎng)度(包括請(qǐng)求行具篇,請(qǐng)求頭和請(qǐng)求正文)绕娘。
$request_time 請(qǐng)求處理時(shí)間,單位為秒栽连,精度毫秒险领; 從讀入客戶端的第一個(gè)字節(jié)開始侨舆,直到把最后一個(gè)字符發(fā)送給客戶端后進(jìn)行日志寫入為止。
$time_iso8601 ISO8601標(biāo)準(zhǔn)格式下的本地時(shí)間绢陌。
$time_local 通用日志格式下的本地時(shí)間挨下。
反向代理
正向代理 反向代理
- 正向代理大概的意思就是,客戶端發(fā)送一個(gè)請(qǐng)求脐湾,這個(gè)請(qǐng)求包含服務(wù)器地址臭笆,那么代理服務(wù)器收到了請(qǐng)求后會(huì)將請(qǐng)求發(fā)送到客戶端指定的服務(wù)器,并將響應(yīng)內(nèi)容傳遞給客戶端秤掌,在這個(gè)過程中愁铺,客戶端是知道請(qǐng)求的服務(wù)器地址的,但是服務(wù)器是不知道哪個(gè)客戶端請(qǐng)求的闻鉴。VPN做的就是這個(gè)事茵乱。
- 反向代理大概的意思就是,客戶端發(fā)送一個(gè)請(qǐng)求給代理服務(wù)器孟岛,由代理服務(wù)器來決定這個(gè)請(qǐng)求該交給哪個(gè)服務(wù)器瓶竭,這就是實(shí)現(xiàn)了服務(wù)器負(fù)載均衡,可以將請(qǐng)求轉(zhuǎn)發(fā)到比較空閑的服務(wù)器來響應(yīng)渠羞,這個(gè)時(shí)候斤贰,代理服務(wù)器就是相對(duì)于客戶端的服務(wù)器,因?yàn)榇藭r(shí)客戶端也不知道請(qǐng)求交給了哪個(gè)服務(wù)器次询。
我所理解的正向代理和反向代理就是這個(gè)意思荧恍,如有錯(cuò)誤歡迎下方評(píng)論。
proxy_pass
那么nginx使用的就是proxy_pass
屬性來進(jìn)行反向代理的處理屯吊,使用也是很簡(jiǎn)單块饺。下面以nodejs開啟一個(gè)建立在 localhost:4000 的服務(wù)
const http = require('http');
http.createServer(function(req, res){
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('server 4000');
}).listen(4000);
請(qǐng)求 localhost:4000
可以打開我們的頁(yè)面
那么我們需要做的是將 localhost:5000
的所有請(qǐng)求都代理到4000這個(gè)server里,這樣就會(huì)出現(xiàn)我們?cè)L問5000和訪問4000一樣的效果雌芽。具體配置如下
server {
# 監(jiān)聽 localhost:5000
listen 5000;
server_name localhost;
# / 表示匹配所有的請(qǐng)求授艰,所有的請(qǐng)求都會(huì)經(jīng)過這個(gè)過濾器
location / {
# 設(shè)定請(qǐng)求轉(zhuǎn)發(fā)的地址
proxy_pass http://localhost:4000;
}
}
這邊需要注意的是 proxy_pass
的寫法,必須是http://
或者https://
開頭的世落,http頭是不能省的淮腾。
請(qǐng)求5000端口效果如下:
本地代理至百度
上方的例子過于簡(jiǎn)單,那么這一個(gè)和上面的有點(diǎn)類似屉佳,這次是將4000的端口號(hào)代理到www.baidu.com
谷朝。修改一下proxy_pass
server {
# 監(jiān)聽 localhost:5000
listen 5000;
server_name localhost;
# / 表示匹配所有的請(qǐng)求,所有的請(qǐng)求都會(huì)經(jīng)過這個(gè)過濾器
location / {
# 設(shè)定請(qǐng)求轉(zhuǎn)發(fā)的地址
proxy_pass https://www.baidu.com;
}
}
這樣就可以了武花,至于這邊寫的是http
還是 https
圆凰,這個(gè)倒是不影響,因?yàn)榘俣葍?nèi)部會(huì)自動(dòng)將http
轉(zhuǎn)成https
畢竟安全嘛体箕。
百度代理至本地
那么按照剛剛的思路就是監(jiān)聽 www.baidu.com
然后設(shè)置一下 proxy_pass
為 localhost:4000
配置如下
server {
listen 80;
server_name www.baidu.com;
location / {
proxy_pass http://localhost:4000;
}
}
試一下专钉,是不是沒有用挑童,沒有用就對(duì)了。要是這么輕松的搞定nginx
還玩?zhèn)€蛋跃须。那么這個(gè)里面又有點(diǎn)操作了站叼,先看正確的配置,修改本地的hosts文件菇民,mac下的文件位置為 /etc/hosts
但是需要 sudo 來進(jìn)行修改尽楔,畢竟這個(gè)文件比較重要嘛
sudo vim /etc/hosts
添加一句
server {
listen 80;
server_name baidu.com;
location / {
proxy_pass http://127.0.0.1:4000;
}
}
一般在本地開發(fā)的時(shí)候我們都會(huì)修改本地的hosts
文件,但是會(huì)遇到一個(gè)問題就是有的時(shí)候是有用的有的時(shí)候又沒用了第练,我這邊的解決辦法是阔馋,每次修改完hosts
文件就清楚瀏覽器的瀏覽數(shù)據(jù),尤其是緩存這一塊的東西娇掏。
如果遇到nginx配置完全正確hosts
文件也配置了呕寝,但是還是沒有用,不妨清一下緩存驹碍,至少在我這是每次都是清完緩存才有用的。
nginx跨域
跨域的解決辦法就是在header
里面加上允許跨域的源等信息
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;
}
}
但是在實(shí)際項(xiàng)目里凡恍。origin
還是不要設(shè)置為*
比較好志秃,因?yàn)榍岸耸褂胊xios的話在獲取session這一塊會(huì)出現(xiàn)問題。
nginx緩存
這邊有一個(gè)需要注意的地方阴孟,nginx作為靜態(tài)資源服務(wù)器的時(shí)候是不做緩存的荸百,只有當(dāng)nginx進(jìn)行反向代理的時(shí)候才具備緩存這個(gè)功能倒堕。我一開始寫了半天發(fā)現(xiàn)鳥用都沒有,最后才發(fā)現(xiàn)只有做代理的時(shí)候才具備緩存钧舌。
各大瀏覽器本身已經(jīng)具有緩存了,比如說谷歌涎跨,我們可以寫一個(gè)html洼冻,然后在html引入一張圖片,我們可以看看瀏覽器是怎么對(duì)圖片這些靜態(tài)資源進(jìn)行緩存的隅很。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<img src="./static/test.jpg" alt="">
</body>
</html>
這個(gè)html代碼我使用http-server
部署在了http-server -a 127.0.0.1 -p 4000
可以看出是在127.0.0.1 4000
端口撞牢。
這是首次加載的時(shí)候的狀況
刷新一下
那么區(qū)別還是很大的
-
html
文件的狀態(tài)碼從200到304,304狀態(tài)碼表明該文件是從緩存中讀取 -
jpg
文件可以發(fā)現(xiàn)在size
這一列叔营,多了一個(gè)memory cache
屋彪,這表明這個(gè)圖片是從瀏覽器緩存中讀取的 - 各個(gè)文件的加載事件明顯減少,尤其是圖片
可能有的人會(huì)發(fā)現(xiàn)第一次加載的時(shí)候绒尊,顯示的是from desk cache
畜挥,那么chrome瀏覽器的緩存分為兩種,一種是磁盤緩存一種是內(nèi)存緩存婴谱,
官方文檔:
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點(diǎn)開圖片可以發(fā)現(xiàn)
在cache-control
后面有一個(gè)max-age
矮湘,那么具體的有關(guān)緩存的技術(shù)這邊就不說了我回頭整理一下
那么針對(duì)不同類型的文件進(jìn)行緩存還是很簡(jiǎn)單的斟冕,需要注意的在于location
的正則匹配
那么第一種最簡(jiǎn)單的緩存,就是直接設(shè)置expires 緩存時(shí)間
設(shè)置expires
location ~ .*\.(jpg|png)$ {
proxy_pass http://127.0.0.1:4000;
expires 3m;
}
expires
是以秒為單位的缅阳,那么我們?cè)O(shè)置為3m
也就是180秒磕蛇,發(fā)現(xiàn)確實(shí)是可以的。
proxy_cache_path 的使用
那么我們也可以指定我們的nginx緩存目錄十办,通過proxy_cache_path 屬性
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)$ {
proxy_pass http://127.0.0.1:4000;
proxy_cache my_cache;
proxy_cache_valid 200 304 1y;
proxy_cache_valid any 1m;
expires 1y;
}
- proxy_cache_path 執(zhí)行緩存文件的目錄秀撇,如果沒有的話需要提前創(chuàng)建,不然nginx會(huì)報(bào)錯(cuò)
- levels 采用2級(jí)目錄來存儲(chǔ)
- key_zone 在共享內(nèi)存中設(shè)置一塊存儲(chǔ)區(qū)域來存放緩存的key和metadata(類似使用次數(shù))向族,這樣nginx可以快速判斷一個(gè)request是否命中或者未命中緩存呵燕,1m可以存儲(chǔ)8000個(gè)key,10m可以存儲(chǔ)80000個(gè)key
- max_size 最大cache空間件相,如果不指定再扭,會(huì)使用掉所有disk space,當(dāng)達(dá)到配額后夜矗,會(huì)刪除最少使用的cache文件
- inactive 未被訪問文件在緩存中保留時(shí)間泛范,在指定時(shí)間內(nèi)未被訪問的文件會(huì)被刪除
- use_temp_path 如果為off,則nginx會(huì)將緩存文件直接寫入指定的cache文件中紊撕,而不是使用temp_path存儲(chǔ)罢荡,official建議為off,避免文件在不同文件系統(tǒng)中不必要的拷貝对扶;
- proxy_cache 啟用proxy cache区赵,對(duì)應(yīng)著配置的key_zone;
- proxy_cache_valid 根據(jù)不同的狀態(tài)碼設(shè)置不同的緩存時(shí)間
可以查看一下nginx
進(jìn)程,會(huì)發(fā)現(xiàn)這個(gè)時(shí)候是有緩存的進(jìn)程在開著的浪南。
這邊可以看到笼才,我們的圖片的緩存時(shí)間已經(jīng)被設(shè)置為1年
location匹配優(yōu)先級(jí)
在緩存中需要注意的一點(diǎn)就是location的匹配規(guī)則和優(yōu)先級(jí)
- = 開頭表示精確匹配
- ^~ 開頭表示uri以某個(gè)常規(guī)字符串開頭,不是正則匹配;
- ~ 開頭表示區(qū)分大小寫的正則匹配;
- ~* 開頭表示不區(qū)分大小寫的正則匹配;
- / 通用匹配, 如果沒有其它匹配,任何請(qǐng)求都會(huì)匹配到;
upstream負(fù)載均衡
負(fù)載均衡是nginx的另一大特點(diǎn)络凿,可以配置多個(gè)服務(wù)器患整,將請(qǐng)求分發(fā)到最合適的那臺(tái)服務(wù)器,避免某一臺(tái)服務(wù)器請(qǐng)求太多而崩潰喷众。使用upstream
屬性來配置
upstream favtomcat {
server 192.168.1.100:4000;
server 192.168.1.111:5000;
}
location / {
root html;
index index.html index.htm;
# 對(duì)應(yīng)上方的 favtomcat
proxy_pass http://favtomcat;
}
這是最基礎(chǔ)的負(fù)載均衡配置各谚,采用的是輪詢
的策略進(jìn)行負(fù)載,每個(gè)請(qǐng)求按時(shí)間順序逐一分配到不同的后端服務(wù)器到千,適用于圖片服務(wù)器集群和純靜態(tài)頁(yè)面服務(wù)器集群昌渤。
優(yōu)點(diǎn): 方式簡(jiǎn)便、成本低廉
缺點(diǎn): 可靠性低和負(fù)載分配不均衡
那么upstream
還有其他的負(fù)載策略
weight權(quán)重
可以給每一臺(tái)服務(wù)器設(shè)置一個(gè)權(quán)重憔四,這樣權(quán)重高的干的活也就會(huì)多一點(diǎn)
upstream favtomcat {
server 192.168.1.100:4000 weight=5;
server 192.168.1.111:5000 weight=10;
}
ip_hash
這種方式是基于客戶端的ip地址膀息,采用hash算法計(jì)算下一個(gè)請(qǐng)求要選擇哪一個(gè)服務(wù)器般眉,這樣固定的ip會(huì)訪問同一個(gè)服務(wù)器,可以解決session問題
upstream favtomcat {
ip_hash;
server 192.168.1.100:4000;
server 192.168.1.111:5000;
}
least_conn最少鏈接
會(huì)將下一個(gè)請(qǐng)求分發(fā)到當(dāng)前鏈接數(shù)最少的一臺(tái)服務(wù)器
upstream favtomcat {
least_conn;
server 192.168.1.100:4000;
server 192.168.1.111:5000;
}
fair
按后端服務(wù)器的響應(yīng)時(shí)間來分配請(qǐng)求潜支,響應(yīng)時(shí)間短的優(yōu)先分配甸赃。
upstream favtomcat {
fair;
server 192.168.1.100:4000;
server 192.168.1.111:5000;
}
url_hash
按訪問url的hash結(jié)果來分配請(qǐng)求,使每個(gè)url定向到同一個(gè)后端服務(wù)器
upstream backserver {
server squid1:3128;
server squid2:3128;
hash $request_uri;
hash_method crc32;
}
參考
https://juejin.im/post/59f94f626fb9a045023af34c冗酿;
Nginx Proxy Cache原理和最佳實(shí)踐