nginx是什么?
nginx是一個強大的web服務器軟件,用於處理高並發的http請求和作為反向代理服務器做負載均衡。具有高性能、輕量級、內存消耗少,強大的負載均衡能力等優勢。
nginx架構?
如上官方示意圖所示,nginx啟動以后,會在系統中以daemon的方式在后台運行,其中包括一個master進程,n(n>=1)個worker進程。
其中,master進程用於接收來自外界的信號,並給worker進程發送信號,同時監控worker進程的工作狀態。
worker進程則是外部請求真正的處理者,每個worker請求相互獨立且平等的競爭來自客戶端的請求。請求只能在一個worker進程中被處理,且一個worker進程只有一個主線程,所以同時只能處理一個請求。那么問題來了,一個worker進程只有一個主線程,只能同時處理一個請求,nginx對高並發請求強大的處理能力是如何保證的呢?答案是nginx采用異步非阻塞的方式來處理請求,即單線程、非阻塞、異步IO的工作模型。對比apache的異步非阻塞版本的工作模式,apache會為每一個請求新建一個線程去處理請求,線程進行上下文切換,會造成內存和CPU的浪費。反看nginx的異步非阻塞io模式,實用操作系統提供的io多路復用技術(epoll),在一個線程中處理所有請求,當一個io操作開始的時候,nginx不會等待其完成就回去處理下一個請求,等到io操作完成后,nginx再回來處理這一次請求io操作的后續工作。相比apache,nginx省去了線程上下文切換帶來的資源開銷。
那么nginx如何確定哪個worker來處理請求呢?首先,每個worker進程都是從master進程fork過來,在master進程里面,先建立好需要listen的socket(listenfd)之后,然后再fork出多個worker進程。所有worker進程的listenfd會在新連接到來時變得可讀,為保證只有一個進程處理該連接,所有worker進程在注冊listenfd讀事件前搶accept_mutex,搶到互斥鎖的那個進程注冊listenfd讀事件,在讀事件里調用accept接受該連接。當一個worker進程在accept這個連接之后,就開始讀取請求,解析請求,處理請求,產生數據后,再返回給客戶端,最后才斷開連接,這樣一個完整的請求就是這樣的了。這樣,一個請求,完全由worker進程來處理,而且只在一個worker進程中處理。
nginx性能?
這里援引網上搜索到的nginx的測試數據:10000個非活躍的HTTP keep-alive 連接僅占用約2.5MB內存。三萬並發連接下,10個Nginx進程,消耗內存150M。淘寶tengine團隊說測試結果是“24G內存機器上,處理並發請求可達200萬”。
nginx負載均衡?
通信協議支持:nginx負載均衡主要是對七層網絡通信模型中的第七層應用層上的http、https進行支持。同時nginx更新版本也在逐步對Websocket、SPDY等協議作出支持。
nginx是以反向代理的方式進行負載均衡的。反向代理(Reverse Proxy)方式是指以代理服務器來接受Internet上的連接請求,然后將請求轉發給內部網絡上的服務器,並將從服務器上得到的結果返回給Internet上請求連接的客戶端,此時代理服務器對外就表現為一個服務器。(為了理解反向代理,這里插播一條什么是正向代理:正向代理指的是,一個位於客戶端和原始服務器之間的服務器,為了從原始服務器取得內容,客戶端向代理發送一個請求並指定目標(原始服務器),然后代理向原始服務器轉交請求並將獲得的內容返回給客戶端。)
這里再插播一條實現負載均衡的技術的方式有哪些:硬件層面有F5負載均衡器,網絡層層面有LVS(Linux Virtual Server),應用層層面就是nginx、Haproxy等。
nginx實現負載均衡的分配策略有很多,被編進nginx內核的策略有輪詢和ip_hash,第三方的有fair、url_hash等。這里主要對內核策略進行介紹。
1.輪詢
a)none(默認輪詢):upstream按照輪詢(默認)方式進行負載,每個請求按時間順序逐一分配到不同的后端服務器,如果后端服務器down掉,能自動剔除。雖然這種方式簡便、成本低廉。但缺點是:可靠性低和負載分配不均衡。
b)weight(按權重輪詢):指定輪詢幾率,weight和訪問比率成正比,用於后端服務器性能不均的情況。
server 192.168.61.22 weight = 6; # 60% 請求 server 192.168.61.23 weight = 4; # 40% 請求
2.ip_hash
每個請求按訪問ip的hash結果分配,這樣每個訪客固定訪問一個后端服務器,可以解決session的問題。配置只需要在upstream中加入"ip_hash;"即可。
upstream tomcats { ip_hash; server 127.0.0.1:9001; server 127.0.0.1:9002; }
3.fair(第三方)
按后端服務器的響應時間來分配請求,響應時間短的優先分配。與weight分配策略類似。
upstream tomcats { server 127.0.0.1:9001; server 127.0.0.1:9002; fair; }
4.url_hash(第三方)
和IP哈希類似,只不過針對請求的url進行hash(基於緩存的server,頁面靜態化)。