epoll的驚群現象解決。想一想nginx解決的應該時epoll的驚群問題具體**網上有就不貼出。得到鎖的可以將accpet放進自己的epoll中然後。沒有得到的移出去;
在思考這個問題之前,我們應該以前對前面所講幾點有所了解,即先弄清楚問題的背景,並能自己復現出來,而不僅僅只是看書或部落格,然後再來看看 nginx 的解決之道。這個順序不應該顛倒。
首先,我們先大概梳理一下 nginx 的網路架構,幾個關鍵步驟為:
nginx 主程序解析配置檔案,根據 listen 指令,將監聽套接字初始化到全域性變數 ngx_cycle 的 listening 陣列之中。此時,監聽套接字的建立、繫結工作早已完成。
nginx 主程序 fork 出多個子程序。
每個子程序在 ngx_worker_process_init 方法裡依次呼叫各個 nginx 模組的 init_process 鉤子,其中當然也包括 ngx_event_module 型別的 ngx_event_core_module 模組,其 init_process 鉤子為 ngx_event_process_init。
ngx_event_process_init 函式會初始化 nginx 內部的連線池,並把 ngx_cycle 裡的監聽套接字陣列通過連線池來獲得相應的表示連線的 ngx_connection_t 資料結構,這裡關於 nginx 的連線池先略過。我們主要看 ngx_event_process_init 函式所做的另乙個工作:如果在配置檔案裡沒有開啟accept_mutex鎖,就通過 ngx_add_event 將所有的監聽套接字新增到 epoll 中。
每乙個 nginx 子程序在執行完 ngx_worker_process_init 後,會在乙個死迴圈中執行 ngx_process_events_and_timers,這就進入到事件處理的核心邏輯了。
在 ngx_process_events_and_timers 中,如果在配置檔案裡開啟了 accept_mutext 鎖,子程序就會去獲取 accet_mutext 鎖。如果獲取成功,則通過 ngx_enable_accept_events 將監聽套接字新增到 epoll 中,否則,不會將監聽套接字新增到 epoll 中,甚至有可能會呼叫 ngx_disable_accept_events 將監聽套接字從 epoll 中刪除(如果在之前的連線中,本worker子程序已經獲得過accept_mutex鎖)。
ngx_process_events_and_timers 繼續呼叫 ngx_process_events,在這個函式裡面阻塞呼叫 epoll_wait。
至此,關於 nginx 如何處理 fork 後的監聽套接字,我們已經差不多理清楚了,當然還有一些細節略過了,比如在每個 nginx 在獲取 accept_mutex 鎖前,還會根據當前負載來判斷是否參與 accept_mutex 鎖的爭奪。
把這個過程理清了之後,nginx 解決驚群問題的方法也就出來了,就是利用 accept_mutex 這把鎖。
如果配置檔案中沒有開啟 accept_mutex,則所有的監聽套接字不管三七二十一,都加入到每子個程序的 epoll中,這樣當乙個新的連線來到時,所有的 worker 子程序都會驚醒。
如果配置檔案中開啟了 accept_mutex,則只有乙個子程序會將監聽套接字新增到 epoll 中,這樣當乙個新的連線來到時,當然就只有乙個 worker 子程序會被喚醒了。
accept 不會有驚群,epoll_wait 才會。
nginx 的 accept_mutex,並不是解決 accept 驚群問題,而是解決 epoll_wait 驚群問題。
說nginx 解決了 epoll_wait 驚群問題,也是不對的,它只是控制是否將監聽套接字加入到epoll 中。監聽套接字只在乙個子程序的 epoll 中,當新的連線來到時,其他子程序當然不會驚醒了。具體epoll驚群現象的解決參考上面的。是在linux後面的版本上進行的解決。具體檢視上面的博文鏈結。
新增到共享喚醒源的epoll_create [1]())始終是以非排他性方式新增。這意味著當我們有多個時
epfds附加到乙個共享的fd源,他們都被喚醒了。這建立
雷鳴般的群體行為。
引入乙個新的'epollexclusive'標誌,可以作為其中的一部分傳遞'epoll_ctl()epoll_ctl_add操作期間的'event'引數。這個新的
當連線多個epfds時,標誌允許獨家喚醒到乙個共享的fd事件源。
這個實現遍歷獨佔服務員的列表,並排隊等候事件傳送給每個epfd,直到找到有執行緒的第乙個伺服器通過epoll_wait()阻止它。這個想法是搜尋哪些執行緒
空閒並準備好處理喚醒事件。因此,我們排隊乙個事件
到至少1個epfd,但仍可能將事件排隊到所有epfds附加到共享fd原始檔。
效能測試由madars vitolins使用修改後的版本完成enduro / x。使用'epollexclusive'標誌減少了長度
這個特殊的工作量從860秒降低到24秒。
示例epoll_clt文字:
epollexclusive
為epfd檔案描述符設定獨佔喚醒模式被附加到目標檔案描述符fd。因此,當乙個事件
發生並且多個epfd檔案描述符被附加到相同使用epollexclusive的目標檔案,乙個或多個epfds將收到乙個帶有epoll_wait(2)的事件。在這種情況下的預設值(何時
epollexclusive未設定)適用於所有epfds接收事件。epollexclusive只能用epoll_ctl_add指定。
epoll 群驚現象
遇到問題 手頭原來有乙個單程序的linux epoll伺服器程式,近來希望將它改寫成多程序版本,主要原因有 在服務高峰期間 併發的 網路請求非常海量,目前的單程序版本的程式有點吃不消 單程序時只有乙個迴圈先後處理epoll wait 到的事件,使得某些不幸排隊靠後的socket fd的事件處理不及時...
epoll驚群測試
3.1.1 核心版本3.10測試結果 兩個程序均被喚醒 3.1.2 核心版本4.18測試結果 僅有乙個程序被喚醒。如果在epoll wait之後sleep一秒,結果如下 兩個程序均被喚醒,總共收到乙個包。小結 較新版本的核心做了一些優化,不一定會喚醒所有的程序。核心版本為3.10和4.18結果一致,...
關於 多程序epoll 與 「驚群」問題
遇到問題 手頭原來有乙個單程序的linux epoll伺服器程式,近來希望將它改寫成多程序版本,主要原因有 在服務高峰期間 併發的 網路請求非常海量,目前的單程序版本的程式有點吃不消 單程序時只有乙個迴圈先後處理epoll wait 到的事件,使得某些不幸排隊靠後的socket fd的網路事件處理不...