走進nginx事件驅動模型

最近在看阿里陶輝前輩寫的”深入理解nginx”中的nginx的事件模塊。之所以想看這塊內容,是因爲nginx可以處理龐大的併發連接,想看看支持其背後的事件驅動是如何構建的

這篇博文我也不想貼代碼什麼的整一堆東西來講述nginx事件驅動,一來我未必理解的那麼透徹,而來這樣反而更不易閱讀者快速的掌握知識,所以我會簡單的將幾個我認爲可能會對我之後的服務器程序開發中有所幫助的幾個知識點

簡單論述nginx的epoll模型

本文只以epoll爲例

nginx以epoll爲事件驅動的基礎,epoll共檢測4類事件,分別如下

.處理新連接事件
.處理定時事件
.處理普通讀寫事件
.處理從磁盤讀事件

(1)首先來談第一個處理新連接事件,我們在平時的服務器設計時,由於連接事件比較敏感(對快速響應要求比較高),所以我會單開一個線程(進程)來專門處理連接,獲取連接後然後在分發給各個I/O複用線程,然而nginx的處理連接事件和處理其他事件都是在同一個I/O複用下,那麼它是如何保證連接事件對響應的要求的呢?niginx是通過將獲取的事件先不調用其回調,而是把他們先放入倆個post隊列,這倆個隊列分別爲

.ngx_posted_accept_events
.ngx_posted_events

第一個隊列用來保存連接事件,而第二個隊列用來保存普通讀寫事件,之後在執行時我們可以先保證ngx_posted_accept_events中的事件先處理,就可以保證連接對響應速度的敏感性
(2)如何防止串話
串話問題可以說是服務器程序中都需要處理的一個問題。串話問題是指剛剛關閉了一個套接字,又來了一個新連接,而新連接剛好系統給分配的就是剛關閉的那個套接字,那麼如果方纔哪個套接字還有事件未處理完成,接下來它給對應的套接字發送數據很有可能就會發到新建立的用戶那。那麼nginx如何來解決這個問題呢?很簡單,nginx在每次獲得新連接後都會將連接中的一個標誌爲置反,這樣本個連接和上個連接的instance就會不同,而每個事件都包含了連接,所以每次處理事件時只需要比較事件中的instance是否相同就OK了
(3)如何處理”驚羣問題”
所謂驚羣問題就是說多個進程在同時監聽同一個端口,當有連接到來時,系統會把多個進程都喚醒,但是當然任然只有一個進程能處理到新連接,所以本來其他進程是不需要被喚醒的,但是被喚醒了,這就是註明的驚羣問題。nginx解決它的方法也很簡單,只需要保證同一時間點只有一個進程在監聽端口就可避免驚羣問題了。但是問題的關鍵是如何能保證同一時間點只有一個進程來監聽端口。nginx採用了嘗試加鎖,根據加鎖的返回值確定本進程是否要接下來處理新連接事件,從而解決了”驚羣問題”
(4)如何解決負載均衡
在我之前寫的一個小網絡庫中,我所採用的負載均衡很簡單,就是主線程用來接受新連接,然後輪流把新連接分發給各個子線程,而nginx解決個進程間的負載均衡問題並沒有均衡分配,而是當每個進程處理的額連接數超過了規定其處理的最大連接數的7/8時,就會本次不處理連接,而是將其處理的連接數-1,這樣相當於就把機會讓給了其他線程,從而實現了負載均衡了

總結

關於nginx驅動模塊就先寫這麼點吧,隨後在看的時候在不上,寫本片博客只是用來督促自己學習的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章