淺談Nginx是如何解決驚群效應的
什么是驚群效應?
第一次聽到的這個名詞的時候覺得很是有趣,不知道是個什么意思,總覺得又是奇怪的中文翻譯導致的。
復雜的說(來源于網(wǎng)絡)TLDR;
驚群效應(thundering herd)是指多進程(多線程)在同時阻塞等待同一個事件的時候(休眠狀態(tài)),如果等待的這個事件發(fā)生,那么他就會喚醒等待的所有進程(或者線程),但是最終卻只能有一個進程(線程)獲得這個時間的“控制權”,對該事件進行處理,而其他進程(線程)獲取“控制權”失敗,只能重新進入休眠狀態(tài),這種現(xiàn)象和性能浪費就叫做驚群效應。
簡單的講(我的大白話)
有一道雷打下來,把很多人都吵醒了,但只有其中一個人去收衣服了。也就是:有一個請求過來了,把很多進程都喚醒了,但只有其中一個能最終處理。
原因&問題
說起來其實也簡單,多數(shù)時候為了提高應用的請求處理能力,會使用多進程(多線程)去監(jiān)聽請求,當請求來時,因為都有能力處理,所以就都被喚醒了。
而問題就是,最終還是只能有一個進程能來處理。當請求多了,不停地喚醒、休眠、喚醒、休眠,做了很多的無用功,上下文切換又累,對吧。那怎么解決這個問題呢?下面就是今天要看的重點,我們看看 nginx 是如何解決這個問題的。
Nginx 架構
第一點我們需要了解 nginx 大致的架構是怎么樣的。nginx 將進程分為 master 和 worker 兩類,非常常見的一種 M-S 策略,也就是 master 負責統(tǒng)籌管理 worker,當然它也負責如:啟動、讀取配置文件,監(jiān)聽處理各種信號等工作。

但是,第一個要注意的問題就出現(xiàn)了,master 的工作有且只有這些,對于請求來說它是不管的,就如同圖中所示,請求是直接被 worker 處理的。如此一來,請求應該被哪個 worker 處理呢?worker 內(nèi)部又是如何處理請求的呢?
nginx 使用 epoll
接下來我們就要知道 nginx 是如何使用 epoll 來處理請求的。下面可能會涉及到一些源碼的內(nèi)容,但不用擔心,你不需要全部理解,只需要知道它們的作用就可以了。順便我會簡單描述一下我是如何去找到這些源碼的位置的。
master 的工作
其實 master 并不是毫無作為,至少端口是它來占的。
ngx_open_listening_sockets(ngx_cycle_t *cycle)
{
.....
for (i = 0; i < cycle->listening.nelts; i++) {
.....
if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) {
if (listen(s, ls[i].backlog) == -1) {
}
那么,根據(jù)我們 nginx.conf 的配置文件,看需要監(jiān)聽哪個端口,于是就去 bind 的了,這里沒問題。
【發(fā)現(xiàn)源碼】這里我是直接在代碼里面搜 bind 方法去找的,因為我知道,不管你怎么樣,你總是要綁定端口的
然后是創(chuàng)建 worker 的,雖不起眼,但很關鍵。
ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
char *name, ngx_int_t respawn)
{
....
pid = fork();
【發(fā)現(xiàn)源碼】這里我直接搜 fork,整個項目里面需要 fork 的情況只有兩個地方,很快就找到了 worker
由于是 fork 創(chuàng)建的,也就是復制了一份 task_struct 結構。所以 master 的幾乎全部它都有。
worker 的工作
nginx 有一個分模塊的思想,它將不同功能分成了不同的模塊,而 epoll 自然就是在 ngx_epoll_module.c 中了
ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
{
ngx_epoll_conf_t *epcf;
epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_module);
if (ep == -1) {
ep = epoll_create(cycle->connection_n / 2);
其他不重要,就連 epoll_ctl 和 epoll_wait 也不重要了,這里你需要知道的就是,從調(diào)用鏈路來看,是 worker 創(chuàng)建的 epoll 對象,也就是每個 worker 都有自己的 epoll 對象,而監(jiān)聽的sokcet 是一樣的!
【發(fā)現(xiàn)源碼】這里更加直接,搜索 epoll_create 肯定就能找到
問題的關鍵
此時問題的關鍵基本就能了解了,每個 worker 都有處理能力,請求來了此時應該喚醒誰呢?講道理那不是所有 epoll 都會有事件,所有 worker 都 accept 請求?顯然這樣是不行的。那么 nginx 是如何解決的呢?
如何解決
解決方式一共有三種,下面我們一個個來看:
accept_mutex(應用層的解決方案)EPOLLEXCLUSIVE(內(nèi)核層的解決方案)SO_REUSEPORT(內(nèi)核層的解決方案)
accept_mutex
看到 mutex 可能你就知道了,鎖嘛!這也是對于高并發(fā)處理的 ”基操“ 遇事不決加鎖,沒錯,加鎖肯定能解決問題。
具體代碼就不展示了,其中細節(jié)很多,但本質(zhì)很容易理解,就是當請求來了,誰拿到了這個鎖,誰就去處理。沒拿到的就不管了。鎖的問題很直接,除了慢沒啥不好的,但至少很公平。
EPOLLEXCLUSIVE
EPOLLEXCLUSIVE 是 2016 年 4.5+ 內(nèi)核新添加的一個 epoll 的標識。它降低了多個進程/線程通過 epoll_ctl 添加共享 fd 引發(fā)的驚群概率,使得一個事件發(fā)生時,只喚醒一個正在 epoll_wait 阻塞等待喚醒的進程(而不是全部喚醒)。
關鍵是:每次內(nèi)核只喚醒一個睡眠的進程處理資源
但,這個方案不是完美的解決了,它僅是降低了概率哦。為什么這樣說呢?相比于原來全部喚醒,那肯定是好了不少,降低了沖突。但由于本質(zhì)來說 socket 是共享的,當前進程處理完成的時間不確定,在后面被喚醒的進程可能會發(fā)現(xiàn)當前的 socket 已經(jīng)被之前喚醒的進程處理掉了。
SO_REUSEPORT
nginx 在 1.9.1 版本加入了這個功能
https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/
其本質(zhì)是利用了 Linux 的 reuseport 的特性,使用 reuseport 內(nèi)核允許多個進程 listening socket 到同一個端口上,而從內(nèi)核層面做了負載均衡,每次喚醒其中一個進程。
反應到 nginx 上就是,每個 worker 進程都創(chuàng)建獨立的 listening socket,監(jiān)聽相同的端口,accept 時只有一個進程會獲得連接。效果就和下圖所示一樣。

而使用方式則是:
http {
server {
listen 80 reuseport;
server_name localhost;
# ...
}
}
從官方的測試情況來看確實是厲害

當然,正所謂:完事無絕對,技術無銀彈。這個方案的問題在于內(nèi)核是不知道你忙還是不忙的。只會無腦的丟給你。與之前的搶鎖對比,搶鎖的進程一定是不忙的,現(xiàn)在手上的工作都已經(jīng)忙不過來了,沒機會去搶鎖了;而這個方案可能導致,如果當前進程忙不過來了,還是會只要根據(jù) reuseport 的負載規(guī)則輪到你了就會發(fā)送給你,所以會導致有的請求被前面慢的請求卡住了。
總結
本文,從了解什么 ”驚群效應“ 到 nginx 架構和 epoll 處理的原理,最終分析三種不同的處理 “驚群效應” 的方案。分析到這里,我想你應該明白其實 nginx 這個多隊列服務模型是所存在的一些問題,只不過絕大多數(shù)場景已經(jīng)完完全全夠用了。
到此這篇關于淺談Nginx是如何解決驚群效應的的文章就介紹到這了,更多相關Nginx 驚群效應內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Nginx?Proxy?Manager配置Web?WAF應用防火墻
Nginx?Proxy?Manager是一款功能強大的開源軟件,配置Web應用防火墻,可以防止常見的web攻擊,本文就來介紹一下Nginx?Proxy?Manager配置Web?WAF應用防火墻,感興趣的可以了解一下2025-02-02
Nginx的偽靜態(tài)配置中使用rewrite來實現(xiàn)自動補全的實例
這篇文章主要介紹了Nginx的偽靜態(tài)配置中使用rewrite來實現(xiàn)自動補全的實例,文中對rewrite的相關參數(shù)和正則表達使用也做了介紹,需要的朋友可以參考下2015-12-12
Nexus使用nginx代理實現(xiàn)支持HTTPS協(xié)議
這篇文章主要介紹了Nexus使用nginx代理實現(xiàn)支持HTTPS協(xié)議,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-05-05

