最近有一個項目要部署到線上服務器,花了幾天時間終於把所有的問題都完美解決了。在部署期間遇到一些與nginx相關問題及解決方法一併記錄了下來。
目錄
3.1 nginx配置後,只有一個頁面(首頁)能正常訪問,其他頁面全加載不出來
3.2 Nginx報錯"no live upstreams while connecting to upstream",錯誤碼502
3.3 用nginx進行負載均衡時,web項目的session共享問題
3.4 服務器上配置好nginx後,用兩臺電腦訪問,總是命中後臺某一個服務器
1 nginx概述
1.1 nginx簡介
Nginx是俄羅斯人Igor Sysoev編寫的輕量級Web服務器,它的發音爲 [ˈendʒɪnks] ,它不僅是一個高性能的HTTP和反向代理服務器,同時也是一個IMAP/POP3/SMTP 代理服務器。
通常是用來做代理/反向代理,負載均衡的。至於它的特點優點這裏不再贅述,我們重點看它的用法和可能遇到問題的解決方案。
1.2 nginx下載
1.2.1 windows下載
windows下載地址:http://nginx.org/en/download.html,點擊進去如下圖:
1.2.2 Linux下載
方式一
和Windows同樣的地址http://nginx.org/en/download.html,點擊進去如下圖:
方式二
從網站去去下載,http://nginx.org/download/,如下圖:
方式三
在linux環境下安裝,在下面網頁中有詳細介紹
https://jingyan.baidu.com/article/e3c78d648516243c4c85f5c2.html
1.3 啓動測試
1.3.1 windows環境
下載後,如下圖:
進入nginx-1.16.1目錄後,雙擊nginx.exe,有個窗口會一閃而過,在瀏覽器中輸入localhost,如下圖:
說明nginx正常啓動了。
1.3.2 linux環境
也很簡單,這裏不再贅述,詳情可以參照:https://jingyan.baidu.com/article/e3c78d648516243c4c85f5c2.html
啓動成功後,也會有歡迎頁面,若不成功注意防火牆對默認監聽端口80的攔截,要開放這個端口。
1.4 常用命令
nginx -s stop # 快速關閉Nginx,可能不保存相關信息,並迅速終止web服務。
nginx -s quit #平穩關閉Nginx,保存相關信息,有安排的結束web服務。
nginx -s reload #因改變了Nginx相關配置,需要重新加載配置而重載。
nginx -s reopen #重新打開日誌文件。
nginx -c filename #爲 Nginx 指定一個配置文件,來代替缺省的。
nginx -t #不運行,而僅僅測試配置文件。nginx 將檢查配置文件的語法的正確性,並嘗試打開配置文件中所引用到的文件。
nginx -v #顯示 nginx 的版本。
nginx -V #顯示 nginx 的版本,編譯器版本和配置參數。
注意運行這些命令要在nginx.exe所在的路徑下。
2 nginx配置
2.1 一個簡單例子
場景:我們現在在本地啓動了兩個web項目,訪問地址分別爲“127.0.0.8081”和“127.0.0.8081”,要實現代理/反向代理,負載均衡可以像下面這樣配置。
下面是一個默認初始的nginx.conf文件,其他都沒變,添加的是藍色框中的代碼,該文件的關鍵部分,如下圖:
注意:
兩個藍色框中都有myWebs,mywebs是後臺服務器組的名稱,這兩個地方一定要一樣。
在上面例子中,如果你的web項目登錄路徑爲:127.0.0.1:8080/webAppName 那麼nginx配置啓動後,應該訪問 localhost:80/webAppName
2.2 語句含義
#user nobody; #定義 Nginx 運行的用戶和用戶組,默認由 nobody 賬號運行, windows 下面可以註釋掉。
worker_processes 1; #nginx進程數,建議設置爲等於CPU總核心數。可以和worker_cpu_affinity配合
#全局錯誤日誌定義類型,[ debug | info | notice | warn | error | crit ]
error_log logs/error.log;
error_log logs/error.log notice;
error_log logs/error.log info;
#pid logs/nginx.pid; #進程文件,window下可以註釋掉
events {
accept_mutex on; #設置網路連接序列化,防止驚羣現象發生,默認爲on
multi_accept on; #設置一個進程是否同時接受多個網絡連接,默認爲off
#use epoll; #事件驅動模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport
worker_connections 1024; # 單個進程最大連接數(最大連接數=連接數*進程數)該值受系統進程最大打開文件數限制,需要使用命令ulimit -n 查看當前設置
}
http {
include mime.types; #文件擴展名與文件類型映射表
default_type application/octet-stream; #默認文件類型,默認爲text/plain
#定義虛擬主機日誌的格式
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指令指定nginx是否調用sendfile函數來輸出文件,對於普通應用設爲 on,如果用來進行下載等應用磁盤IO重負載應用,可設置爲off,以平衡磁盤與網絡I/O處理速度,降低系統的負載。注意:如果圖片顯示不正常把這個改成off。
sendfile on;
#autoindex on; #開啓目錄列表訪問,合適下載服務器,默認關閉。
#防止網絡阻塞
#tcp_nopush on;
#長連接超時時間,單位是秒,默認爲0
#keepalive_timeout 0;
keepalive_timeout 65;
#開啓gzip壓縮輸出
#gzip on;
#被代理的後臺服務器列表
upstream myWeb {
server 127.0.0.1:8081 weight=1;
server 127.0.0.1:9081 weight=1;
ip_hash; #ip_hash 模式,解決session不能共享問題
}
server {
listen 2041; # 監聽端口
server_name localhost; #域名可以有多個,用空格隔開
#charset koi8-r;
charset utf-8; #字符編碼設置
#access_log logs/host.access.log main; #定義本虛擬主機的訪問日誌
location / {
# root html; #一個基本路徑
# index index.html index.htm; # 在上面的基本路徑下找該文件,若是靜態文件(html)則展示;若是動態文件(jsp)在下載
proxy_pass http://myWeb; # 代理的後臺服務器列表
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr; # 獲取用戶的真實 IP 地址
#後端的Web服務器可以通過 X-Forwarded-For 獲取用戶真實IP,多個 nginx 反代的情況下,例如 CDN。參見:http://gong1208.iteye.com/blog/1559835 和 http://bbs.linuxtone.org/thread-9050-1-1.html
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 10000;
proxy_read_timeout 10000;
proxy_send_timeout 10000;
}
#設定查看Nginx狀態的地址
location /NginxStatus {
stub_status on;
access_log on;
auth_basic "NginxStatus";
auth_basic_user_file conf/htpasswd;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
2.3 重要模塊
2.3.1 負載均衡
Nginx負載均衡是通過upstream模塊來實現的,內置實現了三種負載策略,配置還是比較簡單的。官網負載均衡配置說明如下圖:
官網地址:http://nginx.org/en/docs/http/load_balancing.html
我們接下來一個個看。
2.3.1.1輪循(默認)
顧名思義,後臺服務器組的各個服務器會一個接着一個,輪流去處理請求。從整體上來看,每臺服務器處理的請求數是差不多的。
upstream 塊是配置負載均衡的,webs1是後臺服務器組名稱;
location 塊是配置代理/反向代理的(具體見下一個模塊)
2.3.1.2.最少連接
那個服務器處理的請求(被連接的)的次數最少,就那個服務器去處理當前這個請求
2.3.1.3.會話持久性
解決session共享問題。適用場景,當你的後臺服務器有多個,涉及登錄,session驗證問題。一個客戶端會持續訪問一個固定的服務器。
2.3.1.4.一些其他設置
(1) weight
默認爲1,將請求平均分配給每臺server,例如:
upstream webs1 {
server 192.168.0.101:8081 weight=2;
server 192.168.0.102:8082 weight=2;
server 192.168.0.103:8083 weight=1;
}
如果有5各請求,那麼這3臺服務器從上到下,分別處理請求個數爲2、2、1。
(2) max_fails 和 fail_timeout
max_fails默認爲1。某臺Server允許請求失敗的次數,超過最大次數後,在fail_timeout時間內,新的請求將不會分配給這臺機器。如果設置爲0,Nginx會將這臺Server置爲永久無效狀態,然後將請求發給定義了proxy_next_upstream, fastcgi_next_upstream, uwsgi_next_upstream, scgi_next_upstream, and memcached_next_upstream指令來處理這次錯誤的請求。
fail_timeout默認爲10秒。某臺Server達到max_fails次失敗請求後,在fail_timeout期間內,nginx會認爲這臺Server暫時不可用,不會將請求分配給它
max_fails和fail_timeout的使用,如下:
upstream webs1 {
server 192.168.0.101:8081 max_fails=3 fail_timeout=15;
server 192.168.0.102:8082 max_fails=3 fail_timeout=15;
server 192.168.0.103:8083 max_fails=3 fail_timeout=15;
}
即,在15秒內,如果某臺服務器連續處理請求失敗了3次,則這臺服務器判定爲宕機,請求將不會讓這臺服務器處理。
(3)backup
備份技機,其他服務器宕機後,纔會這臺備份機(服務器)。
upstream webs1 {
server 192.168.0.101:8081 max_fails=3 fail_timeout=15;
server 192.168.0.102:8082 max_fails=3 fail_timeout=15;
server 192.168.0.103:8083 backup;
}
當前兩臺服務器宕機後,請求才會發到第三臺服務器上。
(4)down
標識某臺服務器不可用,請求不會發到這臺服務器。
upstream webs1 {
server 192.168.0.101:8081 max_fails=3 fail_timeout=15;
server 192.168.0.102:8082 down;
server 192.168.0.103:8083 backup;
}
(5)max_conns
限制分配給某臺Server處理的最大連接數量,超過這個數量,將不會分配新的連接給它。默認爲0,表示不限制。注意:1.5.9之後的版本纔有這個配置。
upstream webs1 {
server 192.168.0.101:8081;
server 192.168.0.102:8082;
server 192.168.0.103:8083 max_oount=10;
}
(6)resolve
將server指令配置的域名,指定域名解析服務器。需要在http模塊下配置resolver指令,指定域名解析服務。
具體見官方文檔:http://nginx.org/en/docs/http/ngx_http_upstream_module.html#resolver
2.3.2 代理/反向代理
一般是在location塊中配置的。
2.3.1.1 默認配置
我們先來看看,默認nginx的默認配置,爲什麼啓動nginx後,在瀏覽器中輸入域名(一般是localhost),會出現nginx的歡迎頁面呢?
下面是nginx默認的初始nginx.conf文件的部分配置,其中紅框中是location塊的配置。
root html;
html是一個基本路徑(相對路徑或者絕對路徑)。
index index.html index.htm;
當在瀏覽器中訪問localhost:80或者localhost(端口默認爲80)時,是在root配置的基本路徑下找index.html 或者 index.htm文件並且響應到頁面展示,如果不能展示則去下載該文件。
我們去nginx文件下找html文件下,看能不能找到index.html或者index.htm文件,找到了,如下圖:
我們雙擊index.html,響應頁面正好就是我們在剛開始啓動nginx時,瀏覽器中訪問localhost時響應的頁面,如下圖:
2.3.1.2 與upstream配合使用
我們再次回過頭來看2.1中的那一個簡單的例子。
proxy_pass http://myWebs;
這個location塊接收(攔截)的請求(不是localhost:80請求)會去轉發給myWebs這個服務器組裏面的一臺服務器去處理。
兩個藍色框中用到的服務器組名稱一定要保持一致(比如,都是myWebs)。
2.3.1.3 其他
loction塊的配置還有很多,可以去https://segmentfault.com/a/1190000013781162 查看該文章的“location如何匹配“模塊。
3 可能遇到的問題
3.1 nginx配置後,只有一個頁面(首頁)能正常訪問,其他頁面全加載不出來
3.1.1描述
當配置完ginx啓動後,只有一個頁面可以正常訪問(一般情況下是登錄頁,只能登錄進系統),接着點擊其他頁面無反應,打開F2開發者模式,查看請求頭,請求路徑是:”
http://localhost:80/setPassword.html”,裏面的localhost是你nginx配置的域名,80端口是nginx配置的監聽端口。
3.1.2 解決
當請求到代理服務器(一般是你的後臺服務器,會有多個),不能獲取到真實的後臺服務器ip,所以就用你配置的域名去請求了。
給location 塊裏面添加下面代碼:
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr; # 獲取用戶的真實 IP 地址
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
如下圖:
3.2 Nginx報錯"no live upstreams while connecting to upstream",錯誤碼502
3.2.1 描述
前提是你的後臺服務器有兩臺(可能你的情況是多臺),nginx和web項目部署在同一臺服務器上。當你關閉和nginx部署在同一臺服務器上的web項目時(人爲造成一臺服務器故障),再次請求時發現響應頁面如下:
打開nginx的logserror.log日誌,查看報錯信息爲“no live upstreams while connecting to upstream”;
頁面上F12查看報錯“502,bad gateway!“
3.2.2 解決
當你嘗試了網上的多種解決方案無果後,試試在 nginx和web項目都部署了那臺服務器A訪問其他服務器B上的web項目,若還是訪問失敗。那麼恭喜你,問題就要解決了。
你的請求被服務器B的防火牆攔截了,要麼關掉B服務器的防火牆,要麼設置服務器B防火牆的出入站規則(開放請求所用的端口)
3.3 用nginx進行負載均衡時,web項目的session共享問題
3.3.1 描述
當你的web項目技術很簡單,登錄的session沒有存數據庫,也沒有存redis。在部署上線時,web項目有多個節點(web項目在多臺服務器上啓動了)這時用nginx做代理/反向代理,負載均衡時怎麼解決登錄一臺服務器時session共享給所以服務器呢?
最直觀的響應就是,當你配置好nginx啓動後,發出請求可能會報空指針異常。
3.3.2 解決
- 方案一,修改web項目代碼,把session入庫(reids或關係型數據庫),這樣成本大不採取;
- 方案二,註釋驗證session的攔截器,任何人不登錄都可以訪問該網站了,出於安全性的考慮,不可取;
- 方案三,負載均衡時,採用ip_hash策略,固定的客戶端訪問固定的服務端,完美解決session共享問題;
3.4 服務器上配置好nginx後,用兩臺電腦訪問,總是命中後臺某一個服務器
3.4.1 描述
當你用配置好nginx,負載均衡部分採用的ip_hash策略。用局域網內的兩臺服務器訪問服務器(服務器和你不是同一個局域網),發現這兩臺電腦發出請求命中的後臺服務器竟然是一臺(往往是upstream節點裏面配置的第一臺)。這負載均衡也沒生效啊,是什麼原因呢?
當服務器部署的網和你的客戶端訪問的網是同一個網時,一般出現上述問題。
3.4.2 解決
事實上這是正常現象,不需要解決。
因爲,在nginx使用ip_hash這種策略時,內部是使用ip的前三段去做關鍵字進行hash處理的。當你用同一局域網當的兩臺電腦(這兩臺電腦ip的前三段是一樣的)去訪問時就會始終命中後臺的某一臺服務器。
當你一臺電腦連你的局域網,一臺連手機熱點,再次訪問服務器時,就會發行請求命中到了不同的服務器上。
3.5 要對某些代理做驗證
3.5.1 描述
現在有個location節點需要做驗證,輸入賬戶密碼才能訪問,該節點如下:
根據上面配置可以看到nginx監聽端口:80,域名:localhost。訪問/NginxStatus時需要驗證,驗證文件是nginx-1.16.1/conf/htpasswd。
3.5.2 解決
現在我們在conf文件夾下新建一個htpasswd文件,不要後綴名(可以先新建文本文件,再刪掉後綴名)。文件內容如下:
可以發現用戶名是cdd,密碼是123456。配置好後,我們重啓nginx,在瀏覽器中輸入localhost:80/NginxStatus,回車,響應頁面如下要輸入賬戶和密碼。
我們用戶名輸入cdd,密碼輸入:123456,點擊登錄,響應頁面如下:
4 參考資料
nginx中文文檔:
https://www.nginx.cn/doc/index.html
nginx局域網中使用ip_hash策略,總是命中後臺某一臺服務器:
https://blog.csdn.net/sd4493091/article/details/54894479?utm_source=itdadao&utm_medium=referral
https://www.linuxidc.com/Linux/2014-02/96868.htm
linux環境下安裝nginx:https://jingyan.baidu.com/article/e3c78d648516243c4c85f5c2.html
nginx的使用及配置:https://blog.csdn.net/finnson/article/details/82461600
前端nginx使用札記:https://segmentfault.com/a/1190000013781162
nginx負載均衡配置:https://blog.csdn.net/xyang81/article/details/51702900
nginx語句含義:https://www.cnblogs.com/knowledgesea/p/5175711.html