什么是反向代理
有反向代理,那也就有正向的了,正向就是:客戶端=>服務(wù)端;
反向代理指的是代理服務(wù)器接受http請(qǐng)求,然后再將請(qǐng)求轉(zhuǎn)發(fā)給其他指定服務(wù)器,即分發(fā)請(qǐng)求;如下:

網(wǎng)上說反向代理能提升網(wǎng)站性能,但其實(shí)不是的,反而可能還會(huì)降低,因?yàn)橹虚g多了一層轉(zhuǎn)發(fā);說能提升網(wǎng)站性能的前提是搭配負(fù)載均衡;多個(gè)后端服務(wù)集群統(tǒng)一由反向代理服務(wù)器進(jìn)行請(qǐng)求分發(fā),這樣就避免了單臺(tái)服務(wù)器的性能瓶頸影響整個(gè)平臺(tái)的穩(wěn)定。
配置反向代理
最簡單的配置
這也是我們經(jīng)常做的前端反向代理配置
location /api {
proxy_pass http://www.51fubei.com/;
}
完整的配置
這是完整的反向代理配置,
location /api {
add_header Cache-Control no-cache; // 設(shè)置response header
add_header Content-Encoding gzip; // 設(shè)置response header
proxy_set_header Host local.baidu.com; // HTTP header 中的 Host 含義為所請(qǐng)求的目的主機(jī)名。當(dāng) nginx 作為反向代理使用,而后端真實(shí) web 服務(wù)器設(shè)置有類似 防盜鏈功能 ,或者根據(jù) HTTP header 中的 Host 字段來進(jìn)行 路由 或 過濾 功能的話,若作為反向代理的 nginx 不重寫請(qǐng)求頭中的 Host 字段,將會(huì)導(dǎo)致請(qǐng)求失敗。
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; // HTTP header 中的 X_Forward_For 表示該條 http 請(qǐng)求是由誰發(fā)起的。如果反向代理服務(wù)器不重寫該請(qǐng)求頭的話,那么后端真實(shí) web 服務(wù)器在處理時(shí)會(huì)認(rèn)為所有的請(qǐng)求都來自反向代理服務(wù)器。如果后端 web 服務(wù)器有防攻擊策略的話,那么反向代理服務(wù)器對(duì)應(yīng)的 ip 地址就會(huì)被封掉。
proxy_set_header X-Real-IP $remote_addr; // 真是IP
proxy_pass http://www.51fubei.com/;
default_type application/octet-stream; #默認(rèn)文件類型,默認(rèn)為text/plain
#access_log off; #取消服務(wù)日志
log_format myFormat ' $remote_addr–$remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for'; #自定義格式
access_log log/access.log myFormat; #combined為日志格式的默認(rèn)值
sendfile on; #允許sendfile方式傳輸文件,默認(rèn)為off,可以在http塊,server塊,location塊。
sendfile_max_chunk 100k; #每個(gè)進(jìn)程每次調(diào)用傳輸數(shù)量不能大于設(shè)定的值,默認(rèn)為0,即不設(shè)上限。
keepalive_timeout 65; #連接超時(shí)時(shí)間,默認(rèn)為75s,可以在http,server,location塊。
proxy_connect_timeout 1; #nginx服務(wù)器與被代理的服務(wù)器建立連接的超時(shí)時(shí)間,默認(rèn)60秒
proxy_read_timeout 1; #nginx服務(wù)器想被代理服務(wù)器組發(fā)出read請(qǐng)求后,等待響應(yīng)的超時(shí)間,默認(rèn)為60秒。
proxy_send_timeout 1; #nginx服務(wù)器想被代理服務(wù)器組發(fā)出write請(qǐng)求后,等待響應(yīng)的超時(shí)間,默認(rèn)為60秒。
proxy_http_version 1.0 ; #Nginx服務(wù)器提供代理服務(wù)的http協(xié)議版本1.0,1.1,默認(rèn)設(shè)置為1.0版本。
#proxy_method get; #支持客戶端的請(qǐng)求方法。post/get;
proxy_ignore_client_abort on; #客戶端斷網(wǎng)時(shí),nginx服務(wù)器是否終端對(duì)被代理服務(wù)器的請(qǐng)求。默認(rèn)為off。
proxy_ignore_headers "Expires" "Set-Cookie"; #Nginx服務(wù)器不處理設(shè)置的http相應(yīng)投中的頭域,這里空格隔開可以設(shè)置多個(gè)。
proxy_intercept_errors on; #如果被代理服務(wù)器返回的狀態(tài)碼為400或者大于400,設(shè)置的error_page配置起作用。默認(rèn)為off。
proxy_headers_hash_max_size 1024; #存放http報(bào)文頭的哈希表容量上限,默認(rèn)為512個(gè)字符。
proxy_headers_hash_bucket_size 128; #nginx服務(wù)器申請(qǐng)存放http報(bào)文頭的哈希表容量大小。默認(rèn)為64個(gè)字符。
proxy_next_upstream timeout; #反向代理upstream中設(shè)置的服務(wù)器組,出現(xiàn)故障時(shí),被代理服務(wù)器返回的狀態(tài)值。error|timeout|invalid_header|http_500|http_502|http_503|http_504|http_404|off
#proxy_ssl_session_reuse on; 默認(rèn)為on,如果我們在錯(cuò)誤日志中發(fā)現(xiàn)“SSL3_GET_FINSHED:digest check failed”的情況時(shí),可以將該指令設(shè)置為off。
}
設(shè)置了add_header后,可以直接訪問代理服務(wù)的時(shí)候,在response頭中看到,這邊添加了一個(gè)Cache-Control no-cache,如下:

設(shè)置了proxy_set_header后,在服務(wù)端請(qǐng)求中可以看到代理請(qǐng)求的header內(nèi)容,這邊自己起了一個(gè)node服務(wù),然后把request的內(nèi)容打印輸出了,這邊配置了Host、X-Forwarded-For、X-Real-IP,最終服務(wù)端接收到的header頭信息如下:
負(fù)載均衡
什么是負(fù)載均衡?其實(shí)比較容易理解,可以理解成餐廳門口有一個(gè)接待員,然后來1位顧客A,接待員就把顧客A分配給了服務(wù)員A,再來一位顧客B,接待員就分配給服務(wù)員B;如果一下來來了10位,則招待員就分別分配給服務(wù)員A、B、C、D、E,平均每個(gè)服務(wù)員接待兩個(gè),平均大家的工作量,而不會(huì)一個(gè)很忙,一個(gè)很閑;如果有一個(gè)服務(wù)員上廁所,那原本她的那個(gè)顧客會(huì)轉(zhuǎn)給其他幾個(gè)服務(wù)員接待;
專業(yè)的表述是:按照一定算法【權(quán)重、輪訓(xùn) 】,將客戶端請(qǐng)求轉(zhuǎn)發(fā)到不同應(yīng)用服務(wù)器上,減輕單個(gè)服務(wù)器壓力,提高系統(tǒng)并發(fā)量;并且能移除故障,通過心跳檢測方式,判斷應(yīng)用服務(wù)器是否正常工作,如果某一臺(tái)服務(wù)器宕機(jī)了,則會(huì)自動(dòng)將請(qǐng)求發(fā)送到其他應(yīng)用服務(wù)器去;如果檢測到服務(wù)器恢復(fù)了,則再添加到集群中來處理請(qǐng)求;如下圖所示:

熱備
如果主要服務(wù)器掛了,則會(huì)被備份服務(wù)器
upstream nodeserver {
server 127.0.0.1:8001;
server 127.0.0.1:8002 backup; #如果127.0.0.1:8001掛了,則會(huì)走127.0.0.1:8002
}
server {
listen 8080;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
}
location /api {
add_header Cache-Control no-cache;
proxy_pass http://nodeserver/;
proxy_set_header Host local.baidu.com;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 30s;
}
}
輪訓(xùn)算法
輪訓(xùn)算法每一臺(tái)服務(wù)器的權(quán)重都是1,表示平均分配,所有請(qǐng)求按照順序分配,如上圖就是輪訓(xùn)平均分配請(qǐng)求;
upstream nodeserver {
server 127.0.0.1:8001;
server 127.0.0.1:8002;
}
image.png
加權(quán)輪訓(xùn)算法
這邊可以設(shè)置權(quán)重大小,比如服務(wù)器A性能好一些,權(quán)重給3;服務(wù)器B性能差一些,權(quán)重給2;服務(wù)器C配置最差,權(quán)重給1;這個(gè)時(shí)候分配請(qǐng)求的量就會(huì)按照權(quán)重來按比例分配,50%的請(qǐng)求給到了A;33%的請(qǐng)求給到了B;17%的請(qǐng)求給到了C; 如下圖:

這邊以兩臺(tái)服務(wù)器來做測試,8002的權(quán)重是2;8001的權(quán)重是1,結(jié)果如下:
upstream nodeserver {
server 127.0.0.1:8001 weight=1;
server 127.0.0.1:8002 weight=2;
}
ip_hash
每個(gè)請(qǐng)求按訪問ip的hash結(jié)果分配,這樣每個(gè)訪客固定訪問一個(gè)應(yīng)用服務(wù)器,可以解決session共享的問題。

這邊以兩臺(tái)服務(wù)器來做測試,結(jié)果如下:
upstream nodeserver {
server 127.0.0.1:8001;
server 127.0.0.1:8002;
ip_hash;
}
最終請(qǐng)求只走到了8001這臺(tái)服務(wù)器,因?yàn)槲艺?qǐng)求ip沒有變;
當(dāng)我8001端口服務(wù)器掛了之后,請(qǐng)求就會(huì)被分配到8002端口服務(wù)器;
其他配置
upstream nodeserver {
server 127.0.0.1:8001 down; #表示當(dāng)前的server暫時(shí)不參與負(fù)載
server 127.0.0.1:8002 Weight=3; #默認(rèn)是1,表示平均分配;weight越大,負(fù)載的權(quán)重就越大
server 127.0.0.1:8003 max_fails=1 fail_timeout=10s; #允許請(qǐng)求失敗的次數(shù);默認(rèn)是1,當(dāng)超過最大次數(shù)時(shí),返回proxy_next_upstream模塊定義的錯(cuò)誤,判斷該節(jié)點(diǎn)不可用,判斷不可用后10秒內(nèi)請(qǐng)求不會(huì) 轉(zhuǎn)發(fā)到此節(jié)點(diǎn),直到10秒后重新檢測節(jié)點(diǎn)健康情況;
server 127.0.0.1:8003 backup; #其他服務(wù)器掛了之后,再請(qǐng)求backup服務(wù)器,所以這臺(tái)服務(wù)器是兜底的,壓力也是最輕的;
}