原文地址:Nginx concepts I wish I knew years ago
原文作者:Aemie Jariwala(已授權)
譯者 & 校正:HelloGitHub-小魚乾 & 滷蛋
Nginx 是一個採用主從架構的 Web 伺服器,可用於反向代理、負載均衡器、郵件代理和 HTTP 快取。
Emmm,上面的 Nginx 介紹看過去有些複雜而且充滿了不明覺厲的術語。Relax,在這篇文章裡,我(原作者)會先帶你理解 Nginx 的架構和專有術語,最後實踐一把安裝和配置 Nginx。
簡單來說,你只要記住一點:Nginx 是個神奇的 Web 伺服器。(注:神奇之處下文會娓娓道來)
那什麼是 Web 伺服器呢?簡而言之,Web 伺服器就是一箇中間人。舉個例子,你要訪問 hellogithub.com
(注:原文例子為 dev.to),在位址列輸入 https://hellogithub.com
時,你的瀏覽器會找到 https://hellogithub.com
的網路伺服器地址並將它指向後端伺服器,後端伺服器再返回響應給客戶端。
代理 vs 反向代理
Nginx 的基本特性是代理,所以你一定要明白什麼是代理和反向代理。
代理
看個小例子,現在我們有 N 個客戶端(N >= 1),一箇中間 Web 伺服器(在本例中,我們稱之為代理)和一個伺服器。這個例子主要的場景是,伺服器不知道哪個客戶端在請求(響應)。是不是有點難以理解?下面讓我用示意圖講解下:
如圖,client1 和 client2 通過代理伺服器向伺服器傳送請求 request1 和 request2,此時後端伺服器不知道 request1 是由 client1 傳送的還是 client2 傳送的,但會執行(響應)操作。
反向代理
簡單來說,反向代理與代理的功能相反。現在我們有一個客戶端、一箇中間 Web 伺服器和 N 個後端伺服器(N >= 1),同樣的來看下示意圖:
如圖,客戶端將通過 Web 伺服器傳送請求。而 Web 伺服器會通過一個演算法,當中最有意思的演算法是輪詢,直接將請求指向許多後端伺服器中的一個,並通過 Web 伺服器將響應返回給客戶端。因此,在上面的例子中,客戶端其實並不知道在與哪個後端伺服器進行互動。
負載均衡
又是枯燥的一個名詞:負載均衡,不過它很好理解,因為負載均衡本身就是反向代理的一個例項。
來看看負載均衡和反向代理的本質區別。在負載均衡中,你必須有 2 個或者更多的後端伺服器,但在反向代理中,多臺伺服器不是必需的,甚至一臺後端伺服器也能運作。我們再深入點,如果我們有很多來自客戶端的請求,負載均衡器會檢查每個後端伺服器的狀態,均勻地分配請求,更快地向客戶端傳送響應。
有狀態 vs 無狀態應用
Okay,在我們開始實踐 Nginx 之前,先搞清所有的基本知識!
有狀態應用
有狀態應用存了一個額外變數,只用來儲存伺服器中單個例項使用所需的資訊。
如圖所示,一個後端伺服器 server1 儲存了一些資訊,伺服器 server2 並不儲存此資訊,因此,客戶端 (上圖 Bob) 的互動可能會也可能不會得到想要的結果,因為它可能會與 server1 或 server2 互動。在本例中,server1 允許 Bob 檢視資料檔案,但 server2 不允許。因此,雖然有狀態應用避免對資料庫的多次 API 呼叫,並且(響應)速度更快,但它可能會在不同的伺服器上導致這個(無法得到想要結果)問題。
無狀態應用
無狀態應用有更多的資料庫 API 呼叫,但當客戶端與不同後端伺服器的互動時,無狀態應用卻存在更少的問題。
沒明白?簡單來說,如果我通過 Web 伺服器從客戶端向後端伺服器 server1 傳送請求,它將向客戶端返回一個令牌,用於任何進一步的訪問請求。客戶端可以使用令牌並向 Web 伺服器傳送請求。此 Web 伺服器將請求連同令牌一起傳送到任意後端伺服器,而每個後端伺服器都能提供相同的所需結果。
Nginx 是什麼?
Nginx 是網路伺服器,到目前為止,我的整個部落格一直在用這個網路伺服器。老實說,Nginx 這就像個中間人。
這個圖不難理解,它是目前為止所有概念的一個組合。在這裡,我們有 3 個後端伺服器執行在 3001、3002 和 3003 埠,這些後端伺服器都能訪問同一個執行在 5432 埠的資料庫。
當一個客戶端向 https://localhost
(預設埠 443)發起一個 GET /employees
請求時,Nginx 將基於演算法向任意後端伺服器傳送請求,從資料庫獲取資料並將 JSON 資料返回 Nginx Web 伺服器再傳送給客戶端。
如果我們使用一個諸如輪詢這樣的演算法,它讓 client2 向 https://localhost
傳送一個請求,然後 Nginx 伺服器會先將請求傳到 3000 埠並將響應返回給客戶端。對另一個請求,Nginx 會把請求傳給 3002 埠,以此類推。
知識儲備完成!到這裡,你對 Nginx 是什麼以及 Nginx 所涉及的術語有了一個清晰的理解。是時候,瞭解安裝和配置技術了。
開始安裝 Nginx
時機到了,如果你瞭解了上面的概念,可以動手開始 Nginx 實踐了。
嗯,Nginx 的安裝過程對任何系統來說都很簡單。我是一個 Mac OSX 使用者,所以例子的命令是基於 macOS 的, Ubuntu、Windows 和其他 Linux 發行版操作和例子類似。
$ brew install Nginx
只要執行上面這步,你的系統就有 Nginx 了!是不是很神奇!
執行 Nginx 如此簡單 ?
要檢查 Nginx 是否執行也很簡單。
$ nginx
# OR
$ sudo nginx
執行上面指令,再開啟瀏覽器並輸入 http://localhost:8080/
回車檢視下,你會看到以下畫面!
Nginx 基本配置 & 示例
下面,我們通過實操來感受下 Nginx 的魔力。
首先,在本地建立如下的目錄結構:
.
├── nginx-demo
│ ├── content
│ │ ├── first.txt
│ │ ├── index.html
│ │ └── index.md
│ └── main
│ └── index.html
└── temp-nginx
└── outsider
└── index.html
當然,.html 和 .md 檔案中要包含基本資訊。
我們想要得到什麼呢?
這裡,我們有兩個單獨的資料夾 nginx-demo
和 temp-nginx
,每個資料夾都包含靜態 HTML 檔案。我們將著力在一個公共埠上執行這兩個資料夾,並設定我們想要的規則。
回到之前說的,如果要修改 Nginx 預設配置,得修改 usr/local/etc/nginx
目錄下的 nginx.conf
檔案。我的系統中有 vim,所以在這裡用 vim 來更改 Nginx 配置,你可以用自己的編輯器來修改配置。
$ cd /usr/local/etc/nginx
$ vim nginx.conf
上面的命令會開啟一個 Nginx 預設配置檔案,我真的不想直接使用預設配置。因此,我通常的做法是複製這個配置檔案,然後對主檔案進行更改。這裡也不例外。
$ cp nginx.conf copy-nginx.conf
$ rm nginx.conf && vim nginx.conf
上面命令將開啟一個空檔案,我們將為它新增配置。
-
新增配置的基本設定。一定要新增
events {}
,因為在 Nginx 架構中,它通常用來表示 worker 的數量。在這裡我們用http
告訴 Nginx 我們將在 OSI 模型 的第 7 層作業。這裡,我們告訴 Nginx 監聽 5000 埠,並指向 main 資料夾中的靜態檔案。
http { server { listen 5000; root /path/to/nginx-demo/main/; } } events {}
-
接下來我們將為
/content
和/outsider
URL 新增其他的規則,其中 outsider 將指向第一步中提到的根目錄之外的目錄。這裡的
location /content
表示無論我在葉(leaf)目錄中定義了什麼根(root),content 子 URL 都會被新增到定義的根 URL 的末尾。因此,當我指定 root 為root /path/to/nginx-demo/
時,這僅僅意味著我告訴 Nginx 在http://localhost:5000/path/to/nginx-demo/content/
資料夾中顯示靜態檔案的內容。http { server { listen 5000; root /path/to/nginx-demo/main/; location /content { root /path/to/nginx-demo/; } location /outsider { root /path/temp-nginx/; } } } events {}
酷斃了!現在 Nginx 不僅能定義 URL 根路徑,還可以設定規則,這樣我們就能阻止客戶端訪問某個檔案了。
-
接下來,我們在主伺服器上編寫一個規則來防止任意 .md 檔案被訪問。我們可以在 Nginx 中使用正規表示式,因此我們將這樣定義規則:
location ~ .md { return 403; }
-
最後,讓我們學習下
proxy_pass
命令來結束這個章節。我們已經瞭解了什麼是代理和反向代理,在這裡我們從定義另一個執行在 8888 埠上的後端伺服器開始。現在,我們在 5000 和 8888 埠上執行了 2 個後端伺服器。我們要做的是,當客戶端通過 Nginx 訪問 8888 埠時,將這個請求傳到 5000 埠,並將響應返回給客戶端!
server { listen 8888; location / { proxy_pass http://localhost:5000/; } location /new { proxy_pass http://localhost:5000/outsider/; } }
看下,這是所有的配置資訊 ?
http {
server {
listen 5000;
root /path/to/nginx-demo/main/;
location /content {
root /path/to/nginx-demo/;
}
location /outsider {
root /path/temp-nginx/;
}
location ~ .md {
return 403;
}
}
server {
listen 8888;
location / {
proxy_pass http://localhost:5000/;
}
location /new {
proxy_pass http://localhost:5000/outsider/;
}
}
}
events {}
使用 sudo nginx
來執行此配置。
其他 Nginx 命令
-
首次啟動 Nginx Web 伺服器。
$ nginx #OR $ sudo nginx
-
重新載入正在執行的 Nginx Web 伺服器。
$ nginx -s reload #OR $ sudo nginx -s reload
-
停止正在執行中的 Nginx Web 伺服器。
$ nginx -s stop #OR $ sudo nginx -s stop
-
檢視系統上執行的 Nginx 程式。
$ ps -ef | grep Nginx
第 4 條命令很重要,如果前 3 條命令產生了一些問題,通常你可以用第 4 條命令找到所有正在執行的 Nginx 程式並殺死程式,然後重新啟動它們。
要殺死一個程式,你需要 PID,再用以下命令殺死它:
$ kill -9 <PID>
#OR
$ sudo kill -9 <PID>
結束本文之前,宣告下,文中我用了些來自 Google 的圖片和 Hussein Nasser 釋出在油管的視訊教程。
下面盡情享受 Coding、探索 Nginx 的魔力吧!?
最後,歡迎優秀的你加入 HelloGitHub 的「譯文亦舞」系列,讓你的才華舞動起來!把優秀的文章分享給更多的人。要求:
- 平時瀏覽 GitHub、開源、程式設計、程式設計師等英文資訊和文章
- 想把自己閱讀到優秀的英文文章分享給更多的人
- 翻譯準確但不是直翻或機翻
- 保證每月至少翻譯或校正 1 篇高質量文章
- 瞭解 Markdown 和排版規則
- 聯絡微信:xueweihan (備註:翻譯)