一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Nginx深入詳解之多進(jìn)程網(wǎng)絡(luò)模型,用共享鎖解決驚群?jiǎn)栴}

 印度阿三17 2019-01-25

遇到問(wèn)題】

? ? 手頭原來(lái)有一個(gè)單進(jìn)程的linux epoll服務(wù)器程序,近來(lái)希望將它改寫(xiě)成多進(jìn)程版本,主要原因有:

  1. 在服務(wù)高峰期間 并發(fā)的 網(wǎng)絡(luò)請(qǐng)求非常海量,目前的單進(jìn)程版本的程序有點(diǎn)吃不消:?jiǎn)芜M(jìn)程時(shí)只有一個(gè)循環(huán)先后處理epoll_wait()到的事件,使得某些不幸排隊(duì)靠后的socket fd的網(wǎng)絡(luò)事件處理不及時(shí)(擔(dān)心有些socket客戶端等不耐煩而超時(shí)斷開(kāi));
  2. 希望充分利用到服務(wù)器的多顆CPU;

?

? ? 但隨著改寫(xiě)工作的深入,便第一次碰到了“驚群”問(wèn)題,一開(kāi)始我的程序設(shè)想如下:

  1. 主進(jìn)程先監(jiān)聽(tīng)端口, listen_fd = socket(...);
  2. 創(chuàng)建epoll,epoll_fd =?epoll_create(...);
  3. 然后開(kāi)始fork(),每個(gè)子進(jìn)程進(jìn)入大循環(huán),去等待new??accept,epoll_wait(...),處理事件等。

?

? ? 接著就遇到了“驚群”現(xiàn)象:當(dāng)listen_fd有新的accept()請(qǐng)求過(guò)來(lái),操作系統(tǒng)會(huì)喚醒所有子進(jìn)程(因?yàn)檫@些進(jìn)程都epoll_wait()同一個(gè)listen_fd,操作系統(tǒng)又無(wú)從判斷由誰(shuí)來(lái)負(fù)責(zé)accept,索性干脆全部叫醒……),但最終只會(huì)有一個(gè)進(jìn)程成功accept,其他進(jìn)程accept失敗。外國(guó)IT友人認(rèn)為所有子進(jìn)程都是被“嚇醒”的,所以稱之為Thundering Herd(驚群)。

? ??打個(gè)比方,街邊有一家麥當(dāng)勞餐廳,里面有4個(gè)服務(wù)小窗口,每個(gè)窗口各有一名服務(wù)員。當(dāng)大門(mén)口進(jìn)來(lái)一位新客人,“歡迎光臨!”餐廳大門(mén)的感應(yīng)式門(mén)鈴自動(dòng)響了(相當(dāng)于操作系統(tǒng)底層捕抓到了一個(gè)網(wǎng)絡(luò)事件),于是4個(gè)服務(wù)員都抬起頭(相當(dāng)于操作系統(tǒng)喚醒了所有服務(wù)進(jìn)程)希望將客人招呼過(guò)去自己所在的服務(wù)窗口。但結(jié)果可想而知,客人最終只會(huì)走向其中某一個(gè)窗口,而其他3個(gè)窗口的服務(wù)員只能“失望嘆息”(這一聲無(wú)奈的嘆息就相當(dāng)于accept()返回EAGAIN錯(cuò)誤),然后埋頭繼續(xù)忙自己的事去。

? ? 這樣子“驚群”現(xiàn)象必然造成資源浪費(fèi),那有木有好的解決辦法呢?

?

?

【尋找辦法】

? ? 看了網(wǎng)上N多帖子和網(wǎng)頁(yè),閱讀多款優(yōu)秀開(kāi)源程序的源代碼,再結(jié)合自己的實(shí)驗(yàn)測(cè)試,總結(jié)如下:

  1. ?實(shí)際情況中,在發(fā)生驚群時(shí),并非全部子進(jìn)程都會(huì)被喚醒,而是一部分子進(jìn)程被喚醒。但被喚醒的進(jìn)程仍然只有1個(gè)成功accept,其他皆失敗。
  2. 所有基于linux epoll機(jī)制的服務(wù)器程序在多進(jìn)程時(shí)都受驚群?jiǎn)栴}的困擾,包括 lighttpd 和 nginx 等程序,各家程序的處理辦法也不一樣。
  3. lighttpd的解決思路:無(wú)視驚群。采用Watcher/Workers模式,具體措施有優(yōu)化fork()與epoll_create()的位置(讓每個(gè)子進(jìn)程自己去epoll_create()和epoll_wait()),捕獲accept()拋出來(lái)的錯(cuò)誤并忽視等。這樣子一來(lái),當(dāng)有新accept時(shí)仍將有多個(gè)lighttpd子進(jìn)程被喚醒。
  4. nginx的解決思路:避免驚群。具體措施有使用全局互斥鎖,每個(gè)子進(jìn)程在epoll_wait()之前先去申請(qǐng)鎖,申請(qǐng)到則繼續(xù)處理,獲取不到則等待,并設(shè)置了一個(gè)負(fù)載均衡的算法(當(dāng)某一個(gè)子進(jìn)程的任務(wù)量達(dá)到總設(shè)置量的7/8時(shí),則不會(huì)再嘗試去申請(qǐng)鎖)來(lái)均衡各個(gè)進(jìn)程的任務(wù)量。
  5. 一款國(guó)內(nèi)的優(yōu)秀商業(yè)MTA服務(wù)器程序(不便透露名稱):采用Leader/Followers線程模式,各個(gè)線程地位平等,輪流做Leader來(lái)響應(yīng)請(qǐng)求。
  6. 對(duì)比lighttpd和nginx兩套方案,前者實(shí)現(xiàn)方便,邏輯簡(jiǎn)單,但那部分無(wú)謂的進(jìn)程喚醒帶來(lái)的資源浪費(fèi)的代價(jià)如何仍待商榷(有網(wǎng)友測(cè)試認(rèn)為這部分開(kāi)銷(xiāo)不大 http://www./topic/382107)。后者邏輯較復(fù)雜,引入互斥鎖和負(fù)載均衡算分也帶來(lái)了更多的程序開(kāi)銷(xiāo)。所以這兩款程序在解決問(wèn)題的同時(shí),都有其他一部分計(jì)算開(kāi)銷(xiāo),只是哪一個(gè)開(kāi)銷(xiāo)更大,未有數(shù)據(jù)對(duì)比。
  7. 坊間也流傳Linux 2.6.x之后的內(nèi)核,就已經(jīng)解決了accept的驚群?jiǎn)栴},論文地址?http://static./event/usenix2000/freenix/full_papers/molloy/molloy.pdf?。
  8. 但其實(shí)不然,這篇論文里提到的改進(jìn)并未能徹底解決實(shí)際生產(chǎn)環(huán)境中的驚群?jiǎn)栴},因?yàn)榇蠖鄶?shù)多進(jìn)程服務(wù)器程序都是在fork()之后,再對(duì)epoll_wait(listen_fd,...)的事件,這樣子當(dāng)listen_fd有新的accept請(qǐng)求時(shí),進(jìn)程們還是會(huì)被喚醒。論文的改進(jìn)主要是在內(nèi)核級(jí)別讓accept()成為原子操作,避免被多個(gè)進(jìn)程都調(diào)用了。

?

【采用方案】

? ? 多方考量,最后選擇參考lighttpd的Watcher/Workers模型,實(shí)現(xiàn)了我需要的那款多進(jìn)程epoll程序,核心流程如下:

  1. 主進(jìn)程先監(jiān)聽(tīng)端口, listen_fd = socket(...); ,setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR,...),setnonblocking(listen_fd),listen(listen_fd,...)。
  2. 開(kāi)始fork(),到達(dá)子進(jìn)程數(shù)上限(建議根據(jù)服務(wù)器實(shí)際的CPU核數(shù)來(lái)配置)后,主進(jìn)程變成一個(gè)Watcher,只做子進(jìn)程維護(hù)和信號(hào)處理等全局性工作。
  3. 每一個(gè)子進(jìn)程(Worker)中,都創(chuàng)建屬于自己的epoll,epoll_fd =?epoll_create(...);,接著將listen_fd加入epoll_fd中,然后進(jìn)入大循環(huán),epoll_wait()等待并處理事件。千萬(wàn)注意,epoll_create()這一步一定要在fork()之后。
  4. 大膽設(shè)想(未實(shí)現(xiàn)):每個(gè)Worker進(jìn)程采用多線程方式來(lái)提高大循環(huán)的socket fd處理速度,必要時(shí)考慮加入互斥鎖來(lái)做同步,但也擔(dān)心這樣子得不償失(進(jìn)程 線程頻繁切換帶來(lái)的額外操作系統(tǒng)開(kāi)銷(xiāo)),這一步尚未實(shí)現(xiàn)和測(cè)試,但看到nginx源碼中貌似有此邏輯。

【小結(jié)】

? ? 縱觀現(xiàn)如今的Linux服務(wù)器程序開(kāi)發(fā)(無(wú)論是游戲服務(wù)器/WebServer服務(wù)器/balabala各類(lèi)應(yīng)用服務(wù)器),epoll可謂大行其道,當(dāng)紅炸子雞一枚。它也確實(shí)是一個(gè)好東西,單進(jìn)程時(shí)的事件處理能力就已經(jīng)大大強(qiáng)于poll/select,難怪Nginx/Lighttpd等生力軍程序都那么喜歡它。

? ? 但畢竟只有一個(gè)進(jìn)程的話,晾著服務(wù)器的多個(gè)CPU實(shí)在是罪過(guò),為追求更高的機(jī)器利用率更短的請(qǐng)求響應(yīng)處理時(shí)間,還是折騰著搞出了多進(jìn)程epoll。

來(lái)源:http://www./content-3-104601.html

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多

    欧美国产在线观看精品| 99精品国产自在现线观看| 精品香蕉一区二区在线| 欧美日韩国内一区二区| 国产一级特黄在线观看| 国产精品一区二区香蕉视频| 中国美女草逼一级黄片视频| 日本一本在线免费福利| 亚洲一区二区三区福利视频| 免费在线观看激情小视频| 国产福利一区二区三区四区| 国产精品九九九一区二区| 国产亚洲欧美日韩精品一区| 99热九九热这里只有精品| 老鸭窝精彩从这里蔓延| 91在线国内在线中文字幕| 福利视频一区二区三区| 亚洲一级在线免费观看| 好吊视频有精品永久免费| 在线视频三区日本精品| 欧美日韩最近中国黄片| 欧美成人免费视频午夜色| 日韩黄色一级片免费收看| 九九热最新视频免费观看| 中文字幕精品少妇人妻| 欧美不卡高清一区二区三区| 一区二区三区免费公开| 国产乱人伦精品一区二区三区四区| 大香伊蕉欧美一区二区三区| 日本午夜福利视频免费观看| 欧美日韩免费观看视频| 91久久国产福利自产拍| 免费啪视频免费欧美亚洲| 中文字幕亚洲在线一区| 欧美视频在线观看一区| 欧美性高清一区二区三区视频| 国产麻豆精品福利在线| 国产精品一区二区香蕉视频| 女厕偷窥一区二区三区在线| 国产精品亚洲二区三区| 中文字幕av诱惑一区二区|