Nginx同Apache一樣都是一種WEB服務(wù)器?;赗EST架構(gòu)風(fēng)格,以統(tǒng)一資源描述符(Uniform Resources Identifier)URI或者統(tǒng)一資源定位符(Uniform Resources Locator)URL作為溝通依據(jù),通過HTTP協(xié)議提供各種網(wǎng)絡(luò)服務(wù)。Apache的發(fā)展時期很長,而且是毫無爭議的世界第一大服務(wù)器。它有著很多優(yōu)點:穩(wěn)定、開源、跨平臺等等。它出現(xiàn)的時間太長了,它興起的年代,互聯(lián)網(wǎng)產(chǎn)業(yè)遠遠比不上現(xiàn)在,所以它被設(shè)計為一個重量級的服務(wù)器。它不支持高并發(fā),在Apache上運行數(shù)以萬計的并發(fā)訪問,會導(dǎo)致服務(wù)器消耗大量內(nèi)存(新起線程會分配內(nèi)存)。操作系統(tǒng)對其進行進程或線程間的切換也消耗了大量的CPU資源,導(dǎo)致HTTP請求的平均響應(yīng)速度降低。Nginx是輕量級高并發(fā)服務(wù)器,開源、跨平臺且使用基于事件驅(qū)動架構(gòu),這些優(yōu)秀的設(shè)計帶來的極大的穩(wěn)定性。nginx的模塊根據(jù)其功能基本上可以分為以下幾種類型:
event module: 搭建了獨立于操作系統(tǒng)的事件處理機制的框架,及提供了各具體事件的處理。包括ngx_events_module, ngx_event_core_module和ngx_epoll_module等。nginx具體使用何種事件處理模塊,這依賴于具體的操作系統(tǒng)和編譯選項。
phase handler: 此類型的模塊也被直接稱為handler模塊。主要負責(zé)處理客戶端請求并產(chǎn)生待響應(yīng)內(nèi)容,比如ngx_http_static_module模塊,負責(zé)客戶端的靜態(tài)頁面請求處理并將對應(yīng)的磁盤文件準(zhǔn)備為響應(yīng)內(nèi)容輸出。
output filter: 也稱為filter模塊,主要是負責(zé)對輸出的內(nèi)容進行處理,可以對輸出進行修改。例如,可以實現(xiàn)對輸出的所有html頁面增加預(yù)定義的footbar一類的工作,或者對輸出的圖片的URL進行替換之類的工作。
upstream: upstream模塊實現(xiàn)反向代理的功能,將真正的請求轉(zhuǎn)發(fā)到后端服務(wù)器上,并從后端服務(wù)器上讀取響應(yīng),發(fā)回客戶端。upstream模塊是一種特殊的handler,只不過響應(yīng)內(nèi)容不是真正由自己產(chǎn)生的,而是從后端服務(wù)器上讀取的。
load-balancer: 負載均衡模塊,實現(xiàn)特定的算法,在眾多的后端服務(wù)器中,選擇一個服務(wù)器出來作為某個請求的轉(zhuǎn)發(fā)服務(wù)器。
一.正向代理及反向代理
在如今的網(wǎng)絡(luò)環(huán)境下,我們?nèi)绻捎诩夹g(shù)需要要去訪問國外的某些網(wǎng)站,此時你會發(fā)現(xiàn)位于國外的某網(wǎng)站我們通過瀏覽器是沒有辦法訪問的,此時大家可能都會用一個操作FQ進行訪問,F(xiàn)Q的方式主要是找到一個可以訪問國外網(wǎng)站的代理服務(wù)器,我們將請求發(fā)送給代理服務(wù)器,代理服務(wù)器去訪問國外的網(wǎng)站,然后將訪問到的數(shù)據(jù)傳遞給我們!上述這樣的代理模式稱為正向代理,正向代理最大的特點是客戶端非常明確要訪問的服務(wù)器地址;服務(wù)器只清楚請求來自哪個代理服務(wù)器,而不清楚來自哪個具體的客戶端;正向代理模式屏蔽或者隱藏了真實客戶端信息。客戶端必須設(shè)置正向代理服務(wù)器,當(dāng)然前提是要知道正向代理服務(wù)器的IP地址,還有代理程序的端口。正向代理,"它代理的是客戶端",是一個位于客戶端和原始服務(wù)器(origin server)之間的服務(wù)器。正向代理的用途:訪問原來無法訪問的資源,如Google;可以做緩存,加速訪問資源;對客戶端訪問授權(quán),上網(wǎng)進行認證;代理可以記錄用戶訪問記錄(上網(wǎng)行為管理),對外隱藏用戶信息。
多個客戶端給服務(wù)器發(fā)送的請求,Nginx服務(wù)器接收到之后,按照一定的規(guī)則分發(fā)給了后端的業(yè)務(wù)處理服務(wù)器進行處理了。此時請求的來源也就是客戶端是明確的,但是請求具體由哪臺服務(wù)器處理的并不明確了,Nginx扮演的就是一個反向代理角色。客戶端是無感知代理的存在的,反向代理對外都是透明的,訪問者并不知道自己訪問的是一個代理。因為客戶端不需要任何配置就可以訪問。反向代理,"它代理的是服務(wù)端",主要用于服務(wù)器集群分布式部署的情況下,反向代理隱藏了服務(wù)器的信息。反向代理的作用:保證內(nèi)網(wǎng)的安全,通常將反向代理作為公網(wǎng)訪問地址,Web服務(wù)器是內(nèi)網(wǎng);負載均衡,通過反向代理服務(wù)器來優(yōu)化網(wǎng)站的負載。
二.nginx負載均衡原理
當(dāng)前大多數(shù)的互聯(lián)網(wǎng)系統(tǒng)都使用了服務(wù)器集群技術(shù),集群是將相同服務(wù)部署在多臺服務(wù)器上構(gòu)成一個集群整體對外提供服務(wù),這些集群可以是 Web 應(yīng)用服務(wù)器集群,也可以是數(shù)據(jù)庫服務(wù)器集群,還可以是分布式緩存服務(wù)器集群等等。客戶端發(fā)送的、Nginx反向代理服務(wù)器接收到的請求數(shù)量,就是我們說的負載量。請求數(shù)量按照一定的規(guī)則進行分發(fā)到不同的服務(wù)器處理的規(guī)則,就是一種均衡規(guī)則。所以將服務(wù)器接收到的請求按照規(guī)則分發(fā)的過程,稱為負載均衡。
負載均衡在實際項目操作過程中,有硬件負載均衡和軟件負載均衡兩種,硬件負載均衡也稱為硬負載,如F5負載均衡,相對造價昂貴成本較高,但是數(shù)據(jù)的穩(wěn)定性安全性等等有非常好的保障,如中國移動中國聯(lián)通這樣的公司才會選擇硬負載進行操作;更多的公司考慮到成本原因,會選擇使用軟件負載均衡,軟件負載均衡是利用現(xiàn)有的技術(shù)結(jié)合主機硬件實現(xiàn)的一種消息隊列分發(fā)機制。
LVS、Nginx、HAProxy 是目前使用最廣泛的三種軟件負載均衡軟件。目前關(guān)于網(wǎng)站架構(gòu)一般比較合理流行的架構(gòu)方案:Web 前端采用 Nginx/HAProxy+Keepalived 作負載均衡器;后端采用 MySQ L數(shù)據(jù)庫一主多從和讀寫分離,采用 LVS+Keepalived 的架構(gòu)。
1.LVS
LVS 是 Linux Virtual Server 的簡稱,也就是 Linux 虛擬服務(wù)器?,F(xiàn)在 LVS 已經(jīng)是 Linux 標(biāo)準(zhǔn)內(nèi)核的一部分。LVS 的服務(wù)器集群由三部分組成:最前端的負載均衡層,中間的服務(wù)器集群層,最底端的數(shù)據(jù)共享存儲層。LVS 是四層負載均衡,也就是說建立在 OSI 模型的第四層——傳輸層之上,傳輸層上有我們熟悉的 TCP/UDP,LVS 支持 TCP/UDP 的負載均衡,它的效率是非常高的。LVS 的轉(zhuǎn)發(fā)主要通過修改 IP 地址(NAT 模式,分為源地址修改 SNAT 和目標(biāo)地址修改 DNAT)、修改目標(biāo) MAC(DR 模式)來實現(xiàn)。
NAT(Network Address Translation)是一種外網(wǎng)和內(nèi)網(wǎng)地址映射的技術(shù)。當(dāng)包到達 LVS 時,LVS 做目標(biāo)地址轉(zhuǎn)換(DNAT),將目標(biāo) IP 改為 RS(RealServer) 的 IP。RS 接收到包以后,仿佛是客戶端直接發(fā)給它的一樣。RS 處理完,返回響應(yīng)時,源 IP 是 RS IP,目標(biāo) IP 是客戶端的 IP。這時 RS 的包通過網(wǎng)關(guān)(LVS)中轉(zhuǎn),LVS 會做源地址轉(zhuǎn)換(SNAT),將包的源地址改為 VIP,這樣,這個包對客戶端看起來就仿佛是 LVS 直接返回給它的。
DR 模式下需要 LVS 和 RS 集群綁定同一個 VIP(RS 通過將 VIP 綁定在 loopback 實現(xiàn)),一個請求過來時,LVS 只需要將網(wǎng)絡(luò)幀的 MAC 地址修改為某一臺 RS 的 MAC,該包就會被轉(zhuǎn)發(fā)到相應(yīng)的 RS 處理,注意此時的源 IP 和目標(biāo) IP 都沒變,LVS 只是做了一下移花接木。RS 收到 LVS 轉(zhuǎn)發(fā)來的包時,鏈路層發(fā)現(xiàn) MAC 是自己的,到上面的網(wǎng)絡(luò)層,發(fā)現(xiàn) IP 也是自己的,于是這個包被合法地接受,RS 感知不到前面有 LVS 的存在。而當(dāng) RS 返回響應(yīng)時,只要直接向源 IP(即用戶的 IP)返回即可,不再經(jīng)過 LVS。DR 模式具有較好的性能,也是目前大型網(wǎng)站使用最廣泛的一種負載均衡手段。

LVS?抗負載能力強、是工作在傳輸層上僅作分發(fā)之用,沒有流量的產(chǎn)生,這個特點也決定了它在負載均衡軟件里的性能最強的,對內(nèi)存和 cpu 資源消耗比較低;配置性比較低,這是一個缺點也是一個優(yōu)點,因為沒有可太多配置的東西,所以并不需要太多接觸,大大減少了人為出錯的幾率;工作穩(wěn)定,因為其本身抗負載能力很強,自身有完整的雙機熱備方案,如 LVS + Keepalived;因為 LVS 工作在傳輸層,所以它幾乎可以對所有應(yīng)用做負載均衡,包括 http、數(shù)據(jù)庫、在線聊天室等等。
2.nginx
Nginx 負載均衡主要是對七層網(wǎng)絡(luò)通信模型中的第七層應(yīng)用層上的 http、https 進行支持。Nginx 是以反向代理的方式進行負載均衡的。Nginx 實現(xiàn)負載均衡的分配策略有很多,Nginx 的 upstream 目前支持以下幾種方式:
輪詢(默認):每個請求按時間順序逐一分配到不同的后端服務(wù)器,如果后端服務(wù)器 down 掉,能自動剔除。
weight:指定輪詢幾率,weight 和訪問比率成正比,用于后端服務(wù)器性能不均的情況。
ip_hash:每個請求按訪問 ip 的 hash 結(jié)果分配,這樣每個訪客固定訪問一個后端服務(wù)器,可以解決 session 的問題。
fair(第三方):按后端服務(wù)器的響應(yīng)時間來分配請求,響應(yīng)時間短的優(yōu)先分配。
url_hash(第三方):按訪問 url 的 hash 結(jié)果來分配請求,使每個 url 定向到同一個后端服務(wù)器,后端服務(wù)器為緩存時比較有效。
Nginx 負載均衡主要優(yōu)點有:跨平臺、配置異常簡單、事件驅(qū)動、非阻塞、高并發(fā)連接、Master/Worker 結(jié)構(gòu)、內(nèi)存消耗小、內(nèi)置的健康檢查功能(如果 Nginx 代理的后端的某臺 Web 服務(wù)器宕機了,不會影響前端訪問)、節(jié)省帶寬(支持 GZIP 壓縮,可以添加瀏覽器本地緩存的 Header 頭)、穩(wěn)定性高。
Nginx 負載均衡主要缺點有:Nginx 僅能支 持http、https 、tcp、 Email等協(xié)議,這樣就在適用范圍上面小些;對后端服務(wù)器的健康檢查,只支持通過端口來檢測,不支持通過 ur l來檢測;不支持 Session 的直接保持,但能通過 ip_hash 來解決。
3.HAProxy
HAProxy 支持兩種代理模式 TCP(四層)和HTTP(七層),也是支持虛擬主機的。HAProxy 的優(yōu)點能夠補充 Nginx 的一些缺點,比如支持 Session 的保持,Cookie 的引導(dǎo);同時支持通過獲取指定的 url 來檢測后端服務(wù)器的狀態(tài)。單純從效率上來講 HAProxy 會比 Nginx 有更出色的負載均衡速度,在并發(fā)處理上也是優(yōu)于 Nginx 的。HAProxy 負載均衡策略非常多:Round-robin(輪循)、Weight-round-robin(帶權(quán)輪循)、source(原地址保持)、RI(請求URL)、rdp-cookie(根據(jù)cookie)。
三.nginx支持高并發(fā)原理
同步異步、阻塞非阻塞:
同步與異步,重點在于消息通知的方式;阻塞與非阻塞,重點在于等消息時候的行為。同步阻塞:小明在柜臺干等著拿奶茶;同步非阻塞:小明在柜臺邊刷微博邊等著拿奶茶;異步阻塞:小明拿著小票啥都不干,一直等著店員通知他拿奶茶;異步非阻塞:小明拿著小票,刷著微博,等著店員通知他拿奶茶。
select、poll、epoll:
當(dāng)連接有I/O流事件產(chǎn)生的時候,就會去喚醒進程去處理。select與poll原理是一樣的,只不過select只能觀察1024個連接,poll可以觀察無限個連接,進程并不知道是哪個連接產(chǎn)生的I/O流事件,于是進程就挨個去問:“請問是你有事要處理嗎?”......問了99999遍,哦,原來是第100000個進程有事要處理。那么,前面這99999次就白問了,白白浪費寶貴的CPU時間片了。epoll當(dāng)連接有I/O流事件產(chǎn)生的時候,epoll就會去告訴進程哪個連接有I/O流事件產(chǎn)生,然后進程就去處理這個連接的IO事件。Nginx是基于epoll的,異步非阻塞的服務(wù)器程序。Apache處理一個請求是同步阻塞的模式,每到達一個請求,Apache都會去fork一個子進程去處理這個請求,直到這個請求處理完畢。
nginx進程模型:

多進程:一個 Master 進程、多個 Worker 進程
Master 進程:管理 Worker 進程,加載配置文件,初始化監(jiān)聽的 socket,fork 出多個 Worker 進程
對外接口:接收外部的操作(信號)
對內(nèi)轉(zhuǎn)發(fā):根據(jù)外部的操作的不同,通過信號管理 Worker
監(jiān)控:監(jiān)控 worker 進程的運行狀態(tài),worker 進程異常終止后,自動重啟 worker 進程
Worker 進程:所有 Worker 進程都是平等的,在 nginx.conf 中配置,一般設(shè)置為核心數(shù),充分利用 CPU 資源,同時,避免進程數(shù)量過多,避免進程競爭 CPU 資源,增加上下文切換的損耗;網(wǎng)絡(luò)請求,由 Worker 進程處理,競爭新的連接,獲勝方通過三次握手,建立 Socket 連接,并處理請求。
四.nginx配置
nginx.conf的內(nèi)容通常是這樣的:
...
...? ? ? ? ? ? #核心摸塊
events {? ? ? ? #事件模塊
? ...
}
http {? ? # http 模塊
? ? server {? ? ? # server塊
? ? ? ? location [PATTERN] {? # location塊
? ? ? ? ? ? ...
? ? ? ? }
? ? ? ? location [PATTERN] {
? ? ? ? ? ? ...
? ? ? ? }
? ? }
? ? server {
? ? ? ...
? ? }
}
mail {? ? # mail 模塊
? ? server {? ? # server塊
? ? ? ? ? ...
? ? }
}
核心模塊
user admin; #配置用戶或者組
worker_processes 4; #允許生成的進程數(shù),默認為1
pid /nginx/pid/nginx.pid; #指定 nginx 進程運行文件存放地址
error_log log/error.log debug; #錯誤日志路徑,級別
事件模塊
events {
? ? accept_mutex on; #設(shè)置網(wǎng)路連接序列化,防止驚群現(xiàn)象發(fā)生,默認為on
? ? multi_accept on; #設(shè)置一個進程是否同時接受多個網(wǎng)絡(luò)連接,默認為off
? ? use epoll; #事件驅(qū)動模型select|poll|kqueue|epoll|resig
? ? worker_connections 1024; #最大連接數(shù),默認為512
}
http 模塊
http {
? ? include? ? ? mime.types;? #文件擴展名與文件類型映射表
? ? default_type? application/octet-stream; #默認文件類型,默認為text/plain
? ? access_log off; #取消服務(wù)日志
? ? sendfile on;? #允許 sendfile 方式傳輸文件,默認為off,可以在http塊,server塊,location塊
? ? sendfile_max_chunk 100k;? #每個進程每次調(diào)用傳輸數(shù)量不能大于設(shè)定的值,默認為0,即不設(shè)上限
? ? keepalive_timeout 65;? #連接超時時間,默認為75s,可以在http,server,location塊
? ? server
? ? {
? ? ? ? ? ? keepalive_requests 120; #單連接請求上限次數(shù)
? ? ? ? ? ? listen 80; #監(jiān)聽端口
? ? ? ? ? ? server_name? 127.0.0.1;? #監(jiān)聽地址
? ? ? ? ? ? index index.html index.htm index.php;
? ? ? ? ? ? root your_path;? #根目錄
? ? ? ? ? ? location ~ .php$
? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
? ? ? ? ? ? ? ? ? #fastcgi_pass 127.0.0.1:9000;
? ? ? ? ? ? ? ? ? fastcgi_index index.php;
? ? ? ? ? ? ? ? ? include fastcgi_params;
? ? ? ? ? ? }
? ? }
}
location 查找規(guī)則
location = / {
? # 精確匹配 / ,主機名后面不能帶任何字符串
? [ config A ]
}
location? / {
? # 因為所有的地址都以 / 開頭,所以這條規(guī)則將匹配到所有請求
? # 但是正則和最長字符串會優(yōu)先匹配
? [ config B ]
}
location /documents/ {
? # 匹配任何以 /documents/ 開頭的地址,匹配符合以后,還要繼續(xù)往下搜索
? # 只有后面的正則表達式?jīng)]有匹配到時,這一條才會采用這一條
? [ config C ]
}
location ~ /documents/Abc {
? # 匹配任何以 /documents/Abc 開頭的地址,匹配符合以后,還要繼續(xù)往下搜索
? # 只有后面的正則表達式?jīng)]有匹配到時,這一條才會采用這一條
? [ config CC ]
}
location ^~ /images/ {
? # 匹配任何以 /images/ 開頭的地址,匹配符合以后,停止往下搜索正則,采用這一條
? [ config D ]
}
location ~* .(gif|jpg|jpeg)$ {
? # 匹配所有以 gif,jpg或jpeg 結(jié)尾的請求
? # 然而,所有請求 /images/ 下的圖片會被 config D 處理,因為 ^~ 到達不了這一條正則
? [ config E ]
}
location /images/ {
? # 字符匹配到 /images/,繼續(xù)往下,會發(fā)現(xiàn) ^~ 存在
? [ config F ]
}
location /images/abc {
? # 最長字符匹配到 /images/abc,繼續(xù)往下,會發(fā)現(xiàn) ^~ 存在
? # F與G的放置順序是沒有關(guān)系的
? [ config G ]
}
location ~ /images/abc/ {
? # 只有去掉 config D 才有效:先最長匹配 config G 開頭的地址,繼續(xù)往下搜索,匹配到這一條正則,采用
? ? [ config H ]
}
正則查找優(yōu)先級從高到低依次如下:
“ = ” 開頭表示精確匹配,如 A 中只匹配根目錄結(jié)尾的請求,后面不能帶任何字符串。
“ ^~ ” 開頭表示uri以某個常規(guī)字符串開頭,不是正則匹配。
“ ~ ” 開頭表示區(qū)分大小寫的正則匹配。
“ ~* ”開頭表示不區(qū)分大小寫的正則匹配。
“ / ” 通用匹配, 如果沒有其它匹配,任何請求都會匹配到。
負載均衡配置
Nginx 的負載均衡需要用到 upstream模塊,可通過以下配置來實現(xiàn):
upstream test-upstream {
? ? ip_hash; # 使用 ip_hash 算法分配
? ? server 192.168.1.1; # 要分配的 ip
? ? server 192.168.1.2;
}
server {
? ? location / {
? ? ? ? proxy_pass http://test-upstream;
? ? }
}
上面的例子定義了一個 test-upstream的負載均衡配置,通過 proxy_pass反向代理指令將請求轉(zhuǎn)發(fā)給該模塊進行分配處理。
參考文章: