accpet驚群和epoll驚群現象

2021-08-15 23:00:04 字數 3279 閱讀 1354

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的網路事件處理不...