最近在看阿里陶輝前輩寫的”深入理解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驅動模組就先寫這麼點吧,隨後在看的時候在不上,寫本片部落格只是用來督促自己學習的
').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('
').text(i)); }; $numbering.fadeIn(1700); }); });
以上就介紹了走進nginx事件驅動模型,包括了方面的內容,希望對PHP教程有興趣的朋友有所協助。