nginx是什麼? nginx是一個強大的web伺服器軟體,用於處理高併發的http請求和作為反向代理伺服器做負載均衡。具有高性能、輕量級、記憶體消耗少,強大的負載均衡能力等優勢。 nginx架構? 如上官方示意圖所示,nginx啟動以後,會在系統中以daemon的方式在後臺運行,其中包括一個mast ...
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,頁面靜態化)。