基於Nginx的負載均衡技術研究與實現
一、下載安裝及使用
1、版本
日期 |
版本 |
CHANGES |
NGINX |
NGINX/WINDOWS |
2018.6.27 |
MainLine(開發版) |
CHANGES |
1.15.0 |
1.15.0 |
2018.6.27 |
Stable(穩定版) |
1.14 |
1.14.0 |
1.14.0 |
2018.6.27 |
Legacy(過期版) |
1.12 |
1.12.2 |
1.12.2 |
2、下載安裝
下載地址:http://nginx.org/en/download.html
下載並解壓即可,windows和linux類似。
3、常用命令
windows中使用cd命令跳轉到nginx.exe目錄
start nginx |
啟動nginx |
tasklist /fi “imagename eq nginx.exe” |
啟動後檢視程序 |
nginx -s stop |
快速停止 |
nginx -s quit |
完整有序的停止 |
nginx -s reload |
修改配置後重新載入生效 |
nginx -s reopen |
重新開啟日誌檔案 |
nginx -t -c /path/to/nginx.conf |
測試配置檔案是否正確 |
4、已知問題
-
儘管可以開啟多個工作程序執行,但是實際上只有一個在處理請求
-
一個工作程序可以同時處理最多1024個併發連線
-
不支援UDP代理方式
注意:在windows中,不要雙擊nginx.exe來開啟,而應該使用命令,否則會導致修改配置後重啟、停止、無效,這時需手動在工作管理員中關閉所有nginx程序。
5、未來趨勢
-
作為系統服務執行
-
使用I/O完成埠作為事件模型
-
使用單程序多執行緒的模型
6、中文文件
http://tengine.taobao.org/nginx_docs/cn/docs/
二、配置
1、配置檔案
配置檔案:conf/nginx.conf
2、配置項
配置項 |
值 |
說明 |
user |
全域性生效,啟動使用者/組 |
|
work_processes |
1 |
全域性生效,啟動的工作程序數量;auto是啟動與當前CPU執行緒相同的程序數 |
pid |
logs/nginx.pid |
全域性生效,可以是絕對路徑 |
error_log |
logs/error.log |
錯誤日誌路徑 |
error_log |
logs/error.log notice |
日誌記錄級別 |
error_log |
logs/error.log info |
|
worker_rlimit_nofile |
65535 |
nginx工作程序最大開啟檔案數 |
events{} |
全域性生效,主要影響nginx伺服器與使用者的網路連線,比如是否允許同時接受多個網路連線,使用哪種事件驅動模型處理請求,每個工作程序可以同時支援的最大連線數,是否開啟對多工作程序下的網路連線進行序列化等 |
|
event.work_connections |
1024 |
設定nginx可以接受的最大併發,不能大於作業系統能開啟的最大的檔案控制代碼數 |
http{} |
Nginx伺服器配置中的重要部分,快取、代理和日誌格式定義等絕大多數功能和第三方模組都可以在這設定,http塊可以包含多個server塊,而一個server塊中又可以包含多個location塊,server塊可以配置檔案引入、MIME-Type定義、日誌自定義、是否啟用sendfile、連線超時時間和單個連結的請求上限等。 |
|
http.include |
mime.types |
副檔名與檔案型別對映表 |
http.default_type |
application/octet-stream |
預設檔案型別 |
http.log_format |
||
http.access_log |
logs/access.log main |
|
http.client_header_timeout |
4k |
用於指定來自客戶端請求頭的headerbuffer大小,對於大多數請求,1kb的緩衝區大小已經足夠,如果自定義了訊息頭部或有更大的cookie,可以增加緩衝區大小 |
http.sendfile |
on |
是否呼叫sendfile函式(零copy方式)來輸出檔案,普通應用開啟,可以大幅提升nginx的讀檔案效能,如果伺服器是下載的就需要關閉 |
http.sendtime_out |
10s |
http核心模組指令,指定了傳送給客戶端應答後的超時時間,Timeout是指沒有進入完整established狀態,只完成了兩次握手,如果超過這個時間客戶端沒有任何響應,nginx將關閉與客戶端的連線。 |
http.server.location.sendfile_max_chunk |
512k |
Nginx工作程序每次呼叫sendfile()傳輸的資料最大不能超出這個值,0表示表示無限制。 |
http.tcp_nopush |
on |
|
http.keepalive_timeout |
65 |
長連線超時時間,單位是秒 |
http.gzip |
on |
開啟或關閉gzip功能,on | off |
http.gzip_buffers |
32 4k |
第一個引數是Nginx伺服器向伺服器申請的快取空間的個數 第二個引數是每個快取空間的大小 |
http.gzip_comp_level |
4 |
壓縮級別,1-9 |
http.gzip_disable |
MSIE[1-6]\. |
使用正則表示式匹配關閉資料包的壓縮 |
http.gzip_http_version |
1.0|1.1 |
對使用http1.0和1.1的請求進行壓縮 |
http.gzip_min_length |
1024 |
最少壓縮的資料包大小 |
http.gzip_proxied |
off | any |
在Nginx 伺服器作為反向代理的時候有效,用於設定nginx伺服器是否對後端返回的結果進行gzip壓縮 off為關閉,any為壓縮所有後端伺服器返回的資料 |
http.gzip_types |
text/plain application/x-javascript text/css application/xml |
設定Nginx伺服器可以根據響應頁面的型別進行選擇性的開啟或關閉gzip功能 一般設定 |
http.gzip_vary |
on | off |
用於設定是否在使用gzip功能時傳送帶有"vary:Accept-Encoding"頭域的響應頭部,該頭域的主要功能時要告訴客戶端資料已經在伺服器進行了壓縮,預設設定為off |
http.server |
一個虛擬機器主機,可以包含自己的全域性塊,同時也可以包含多個locating模組。比如本虛擬機器監聽的埠、本虛擬機器的名稱和IP配置,多個server 可以使用一個埠,比如都使用8090埠提供web服務 |
|
http.server.listen |
server的全域性配置,配置監聽的埠 |
|
http.server.server_name |
localhost |
本server的名稱,當訪問此名稱的時候nginx會呼叫當前serevr內部的配置程序匹配 |
http.server.charset |
||
http.server.access_log |
||
http.server.location |
location其實是server的一個指令,為nginx伺服器提供比較多而且靈活的指令,都是在location中提現的,主要是基於nginx接受到的請求字串,對使用者請求的UIL進行匹配,並對特定的指令進行處理,包括地址重定向、資料快取和應答控制等功能都是在這部分實現,另外很多第三方模組的配置也是在location模組中配置 |
|
http.server.location.root |
相當於預設頁面的目錄名稱,預設是相對路徑,可以使用絕對路徑配置 |
|
http.server.location.index |
預設頁面的名稱 |
|
http.server.error_page |
錯誤頁面的檔名稱 |
3、擴充套件配置
每個配置檔案中的指令,均以“;”結尾
-
繫結Nginx工作程序到不同CPU上
預設Nginx是不進行繫結的,繫結並不能夠使當前程序獨佔一核,但可以保證該程序不會執行在其他核上,因此,繫結使程序減少在CPU間的跳轉,減少資源分配與回收,從而有效提升nginx伺服器的效能。
#確認CPU的核心數量(linux)
grep precess /proc/cpuinfo | wc -l
#4個執行緒CPU的配置
worker_processes 4;
worker_cpu_affinity 0001 0010 01001000;
#8個執行緒CPU的配置
worker_processes 8;
worker_cpu_affinity 0000000100000010 00000100 00001000 00010000 00100000 01000000 10000000;
-
配置檔案的引入
include file;#file是要匯入的檔案,支援相對路徑,一般在html目錄裡面,可以使用萬用字元*批量匯入
nginx.conf:
include/usr/local/nginx/conf.d/*.conf;
/usr/local/nginx/conf.d/abc.conf:
server {
listen 8081;
server_namewww.caini.cn;
location/ {
roothtml;
indexindex1.html index.htm;
}
error_page 500 502 503 504/50x.html;
location = /50x.html {
roothtml;
}
}
4、優化配置
-
網路連線優化
events{
accept_mutex on;#優化同一時刻只有一個請求而避免多個睡眠程序被喚醒的設定,on為防止被同時喚醒,預設為off,因此nginx剛安裝完以後要進行適當的優化。
}
-
設定是否允許同時接受多個網路連線
events {
accept_mutex on;
multi_accept on;#開啟同時接受多個新網路連線請求的功能。
}
-
隱藏版本號
server_tokensoff;#在http模組中配置,防止被黑客利用攻擊
-
選擇事件驅動模型
events {
accept_mutex on;
multi_accept on;
use epoll; #使用epoll事件驅動,因為epoll的效能相比其他事件驅動(select/poll)要好很多
}
三、原理機制
1、Web請求機制
1、多程序方式:伺服器沒接受到一個客戶端請求就有伺服器的主程序生成一個子程序響應客戶端,直到使用者關閉連線,這樣的優勢是處理速度快,子程序之間相互獨立,但是如果訪問過大會導致伺服器資源耗盡而無法提供請求。
2、多執行緒方式:與多程序方式類似,但是每收到一個客戶端請求會有服務程序派生出一個執行緒來個客戶方進行互動,一個執行緒的開銷遠遠小於一個程序,因此多執行緒方式在很大程度減輕了web伺服器對系統資源的要求,但是多執行緒也有自己的缺點,即當多個執行緒位於同一個程序內工作的時候,可以相互訪問同樣的記憶體地址空間,所以他們相互影響,一旦主程序掛掉則所有子執行緒都不能工作了,IIS伺服器使用了多執行緒的方式,需要間隔一段時間就重啟一次才能穩定。
2、同步和非同步、阻塞和非阻塞
同步:程序發出資料後,等核心返回響應以後才繼續下一個請求,即如果核心一直不返回資料,那麼程序就一直等,直到天荒地老,宕機error。
非同步:程序發出資料後,不等核心返回響應,接著處理下一個請求,Nginx是非同步的。
阻塞:IO呼叫不能立即返回結果,即一個程序發起的IO請求不能得到立即滿足時,程序就要一直等到核心響應,核心要把資料從IO裝置複製到核心空間,再返回給程序,這是阻塞。
非阻塞:IO呼叫可以立即返回結果,一個程序發起的IO程序不能立即滿足時,不在等待,而是一遍一遍的輪訓檢視IO是否完成。
同步阻塞:程式程序向核心傳送IO請求後一直等待核心響應,如果核心處理請求的IO操作不能立即返回,則程序將一直等待並不再接受新的請求,並由程序輪訓檢視IO是否完成,完成後程序將IO結果返回給Client,在IO沒有返回期間程序不能接受其他客戶的請求,而且是有程序自己去檢視IO是否完成,這種方式簡單,但是比較慢,用的比較少。
同步非阻塞:程序向核心傳送請IO求後一直等待核心響應,如果核心處理請求的IO操作不能立即返回IO結果,程序將不再等待,而且繼續處理其他請求,但是仍然需要程序隔一段時間就要檢視核心IO是否完成。
非同步阻塞:event-diver,程序向核心傳送IO呼叫後,不用等待核心響應,可以繼續接受其他請求,核心收到程序請求後進行的IO如果不能立即返回,就由核心等待結果,直到IO完成後核心再通知程序,此方式比較佔用核心,因此也很少使用。
非同步非阻塞:AIO,程序向核心傳送IO呼叫後,不用等待核心響應,可以繼續接受其他請求,核心呼叫的IO如果不能立即返回,核心會繼續處理其他事物,直到IO完成後將結果通知給核心,核心在將IO完成的結果返回給程序,期間程序可以接受新的請求,核心也可以處理新的事物,因此相互不影響,可以實現較大的同時並實現較高的IO複用,因此非同步非阻塞使用最多的一種通訊方式。
2、Nginx的事件驅動模型
select |
select庫是在linux和windows平臺都基本支援的事件驅動模型庫,並且在介面的定義也基本相同,只是部分引數的含義略有差異,最大併發限制1024,只最早期的事件驅動模型。 |
poll |
在Linux 的基本驅動模型,windows不支援此驅動模型,是select的升級版,取消了最大的併發限制,在編譯nginx的時候可以使用--with-poll_module和--without-poll_module這兩個指定是否編譯select庫。 |
epoll |
epoll是庫是Nginx伺服器支援的最高效能的事件驅動庫之一,是公認的非常優秀的事件驅動模型,它和select和poll有很大的區別,epoll是poll的升級版,但是與poll的效率有很大的區別. epoll的處理方式是建立一個待處理的事件列表,然後把這個列表發給核心,返回的時候在去輪訓檢查這個表,以判斷事件是否發生,epoll支援一個程序開啟的最大事件描述符的上限是系統可以開啟的檔案的最大數,同時epoll庫的IO效率不隨描述符數目增加而線性下降,因為它只會對核心上報的“活躍”的描述符進行操作。 |
rtsig |
不是一個常用事件驅動,最大佇列1024,不是很常用 |
kqueue |
用於支援BSD系列平臺的高效事件驅動模型,主要用在FreeBSD 4.1及以上版本、OpenBSD 2.0級以上版本,NetBSD級以上版本及Mac OS X 平臺上,該模型也是poll庫的變種,因此和epoll沒有本質上的區別,都是通過避免輪訓操作提供效率。 |
/dev/poll |
用於支援unix衍生平臺的高效事件驅動模型,主要在Solaris 平臺、HP/UX,該模型是sun公司在開發Solaris系列平臺的時候提出的用於完成事件驅動機制的方案,它使用了虛擬的/dev/poll裝置,開發人員將要見識的檔案描述符加入這個裝置,然後通過ioctl()呼叫來獲取事件通知,因此執行在以上系列平臺的時候請使用/dev/poll事件驅動機制。 |
eventpoll |
該方案也是sun公司在開發Solaris的時候提出的事件驅動庫,只是Solaris 10以上的版本,該驅動庫看防止核心崩潰等情況的發生。 |
3、Nginx程序的功能和程序間通訊
-
主程序的功能
-
讀取Nginx 配置檔案並驗證其有效性和正確性
-
建立、繫結和關閉socket連線
-
按照配置生成、管理和結束工作程序
-
接受外界指令,比如重啟、升級及退出伺服器等指令
-
不中斷服務,實現平滑升級,重啟服務並應用新的配置
-
開啟日誌檔案,獲取檔案描述符
-
不中斷服務,實現平滑升級,升級失敗進行回滾處理
-
編譯和處理perl指令碼
-
工作程序的功能
-
接受處理客戶的請求
-
將請求以此送入各個功能模組進行處理
-
IO呼叫,獲取響應資料
-
與後端伺服器通訊,接收後端伺服器的處理結果
-
快取資料,訪問快取索引,查詢和呼叫快取資料
-
傳送請求結果,響應客戶的請求
-
接收主程式指令,比如重啟、升級和退出等
-
主程序和工作程序之間的通訊
-
工作程序是有主程序生成的,主程序使用fork()函式,在Nginx伺服器啟動過程中主程序根據配置檔案決定啟動工作程序的數量,然後建立一張全域性的工作表用於存放當前未退出的所有的工作程序,主程序生成工作程序後會將新生成的工作程序加入到工作程序表中,並建立一個單向的管道並將其傳遞給工作程序,該管道與普通的管道不同,它是由主程序指向工作程序的單項通道,包含了主程序向工作程序發出的指令、工作程序ID、工作程序在工作程序表中的索引和必要的檔案描述符等資訊。
-
主程序與外界通過訊號機制進行通訊,當接收到需要處理的訊號時,它通過管道向相關的工作程序傳送正確的指令,每個工作程序都有能力捕獲管道中的可讀事件,當管道中有可讀事件的時候,工作程序就會從管道中讀取並解析指令,然後採取相應的執行動作,這樣就完成了主程序與工作程序的互動。
-
工作程序和工作程序之間的通訊
-
工作程序之間的通訊原理基本上和主程序與工作程序之間的通訊是一樣的,只要工作程序之間能夠取得彼此的資訊,建立管道即可通訊,但是由於工作程序之間是完全隔離的,因此一個程序想要直到另外一個程序的狀態資訊就只能通過主程序來設定了。
-
為了實現工作程序之間的互動,主程序在生成工作程序只之後,在工作程序表中進行遍歷,將該新程序的ID以及針對該程序建立的管道控制代碼傳遞給工作程序中的其他程序,為工作程序之間的通訊做準備,當工作程序1向工作程序2傳送指令的時候,首先在主程序給它的其他工作程序工作資訊中找到2的程序ID,然後將正確的指令寫入指向程序2的管道,工作程序2捕獲到管道中的事件後,解析指令並進行相關操作,這樣就完成了工作程序之間的通訊。
4、快取和代理
-
快取
-
memcached快取資料庫常用資料
-
xcache快取php編譯的結果,可以在多個程序間共享xcode結果
-
nginx的快取是快取opcode處理後的結果,避免客戶端請求同一個頁面而導致程式每次都處理一下,即再訪問同一個頁面,直接使用處理後的快取即可直接返回
-
代理
-
正向代理:工作在使用者前端,使用者請求的所有內容都經過代理伺服器。
-
反向代理:工作在伺服器前端,只代理請求伺服器的客戶端請求,被期代理的伺服器叫做“代理伺服器”或者“上游伺服器”。
5、負載均衡
5.1負載均衡的概念及原理
通過反向代理客戶端的請求到一個伺服器群組,通過某種演算法,將客戶端的請求按照自定義的有規律的一種排程排程給後端伺服器。
Nginx的負載均衡使用upstream定義伺服器組,後面跟著組名,組名後面是大括號包起來的是伺服器列表,每個伺服器使用server開頭,後面跟定義的伺服器名字,伺服器IP:PORT、引數
5.2負載均衡的作用
轉發功能:按照一定的演算法【權重、輪詢】,將客戶端請求轉發到不同應用伺服器上,減輕單個伺服器壓力,提高系統併發量。
故障轉移:通過心跳檢測的方式,判斷應用伺服器當前是否可以正常工作,如果伺服器宕掉,自動將請求傳送到其他應用伺服器。
恢復新增:如果檢測到發生故障的應用伺服器恢復工作,自動將其新增到處理使用者請求隊伍中。
5.3Nginx的upstream支援的排程演算法
-
輪詢(預設)
每個請求按時間順序逐一分配到不同的後端伺服器,如果後端伺服器down掉,能自動刪除。
-
權重(weight)
指定輪詢機率,weight和訪問比率成正比,用於後端伺服器效能不均的情況。
-
雜湊(ip_hash)
每個請求按ip的hash結果分配,這樣每個訪客固定訪問一個後端伺服器,可以解決session保持問題。
-
fair(第三方)
可以依據頁面大小和載入時間長短智慧地進行負載均衡,也就是根據後端伺服器的響應時間來分配請求,響應時間短的優先分配,Nginx本身是不支援fair的,如果需要使用這種演算法,必須下載Nginx的upstream_fair模組。
-
url_hash(第三方)
按照url的hash結果來分配請求,使每個url定向到同一個後端伺服器,可以進一步提高後端快取伺服器的效率,Nginx本身不支援url_hash,如果需要使用這種演算法,必須下載Nginx的hash軟體包。
-
least_conn
根據後端伺服器的連線狀況進行分配客戶請求,連線最少的伺服器將被有限分配客戶端請求。
5.4注意事項
應用系統的高可用性保證,除了提供多臺伺服器來發布相同的服務,新增負載均衡伺服器分發請求來保證各臺伺服器相對飽和的處理請求之外,負載均衡伺服器的高可用性同樣重要。
四、詳細設計與實現
1、配置Nginx的負載均衡與分發策略
具體配置說明
listen 80 |
監聽80埠 |
server_name localhost |
使用者訪問的網址為localhost |
location /jeesitepro |
配置需要負載均衡的網站,通過正則表示式匹配 當前和專案的server.xml檔案中Context的path屬性一致即可
|
proxy_pass http://tomcatserver1 |
所有請求通過反向代理伺服器,在伺服器將請求轉發給目的主機時,讀取upstream為tomcatserver1的地址中的分發策略,以此分發請求 |
upstream tomcatserver1 |
後端伺服器組,名稱為tomcatserver1 預設以輪詢排程演算法呼叫組內後端伺服器 |
ip_hash |
採用ip_hash排程演算法 |
server localhost:8081 |
一臺後端伺服器 |
server localhost:8082 |
一臺後端伺服器 |
通過上述配置,如果2個分發伺服器效能相同,那麼將通過客戶端IP地址的hash值來分配後端伺服器,實現有條件的負載均衡。
2、其他配置
server 192.168.72.49:8082 down |
表示該server暫時不參與負載 |
server 192.168.72.49:8083 weight=2 |
預設weight為1,值越大,權重越大 |
server 192.168.72.49:8084 max_fails=2 |
預設允許請求失敗的次數為1,超過最大次數時,返回proxy_next_upstream模組定義的錯誤 |
server 192.168.72.49:8085 backup |
所有非backup伺服器down或忙時,請求backup |
server 192.168.72.49:8086 fail_timeout=1s |
max_fails次失敗後,暫停的時間 |
ip_hash |
實現會話保持功能,即將某個客戶端的請求定向到組內的同一臺伺服器,保證客戶端和伺服器之間建立穩定的會話,只有伺服器處於無效狀態時,會話才會被轉發給組內其他的伺服器 |
3、實現效果
略