nginx 多進程 + io多路復用 實現高并發

一、nginx 高并發原理

簡單介紹:nginx 采用的是多進程(單線程) + io多路復用(epoll)模型 實現高并發

二、nginx 多進程

  • 啟動nginx
    o_4071177893-5bc03aa71d0f3_articlex.png
解析初始化配置文件后會 創建(fork)一個master進程 之后 這個進程會退出 
master 進程會 變為孤兒進程 由init進程托管。(可以通過python 或php 啟動后創建子進程,然后殺死父進程得見子進程會由init進程托管)
如下圖可以看到nginx master 進程由init(ppid 為1 )進程管理。

o_1559542370(1).png

  • master進程和worker進程
    o_20170303170640322.png
1、master 
首先nginx 創建一個master 進程,通過socket() 創建一個sock文件描述符用來監聽(sockfd)
綁定端口(bind) 開啟監聽(listen)。
nginx 一般監聽80(http) 或 443 (https)端口
(fork 多個子進程后,master 會監聽worker進程,和等待信號)2、worker
然后 創建(fork)多個 worker子進程(復制master 進程的數據),
此時所有的worker進程 繼承了sockfd(socket文件描述符),
當有連接進來之后 worker進程就可以accpet()創建已連接描述符,
然后通過已連接描述符與客戶端通訊
  • 驚群現象
由于worker進程 繼承了master進程的sockfd,當連接進來是,所有的子進程都將收到通知并“爭著”與
它建立連接,這就叫驚群現象。大量的進程被激活又掛起,最后只有一個進程accpet() 到這個連接,這會消耗系統資源
(等待通知,進程被內核全部喚醒,只有一個進程accept成功,其他進程又休眠。這種浪費現象叫驚群)
  • nginx 對驚群現象的處理
原因:多個進程監聽同一個端口引發的。
解決:如果可以同一時刻只能有一個進程監聽端口,這樣就不會發生“驚群”了,此時新連接事件只能喚醒正在監聽的唯一進程。如何保持一個時刻只能有一個worker進程監聽端口呢?nginx設置了一個accept_mutex鎖,在使用accept_mutex鎖是,只有進程成功調用了ngx_trylock_accept_mutex方法獲取鎖后才可以監聽端口(linux 內核2.6 之后 不會出現驚群現象,只會有一個進程被喚醒)
  • 代碼簡單理解
    o_1559551783(1).png

三、worker進程

  • worker進程做了什么事
從上圖中,我們可以看到worker進程做了
1、accept() 與客戶端建立連接
2、recv()接收客戶端發過來的數據
3、send() 向客戶端發送數據
4、close() 關閉客戶端連接
  • 如果不使用io多路復用 會是什么樣的
首先 等待客戶端有連接進來
accpet()  與客戶端建立連接后
recv()  一直等待客戶的發送過來數據(此時處于io阻塞狀態)如果此時又有客戶端過來建立連接,那么只能等待,需要一直等待close() 之后才可以建立連接也就是說這個worker進程會因為recv() 而處于阻塞狀態,而不能處理與其他客戶端建立連接,
這段時間不能做任何事,這是對性能了浪費。(進程 和線程的切換也是需要消耗 時間的。)
  • 能不能利用io堵塞的時間 accept,recv
nginx 采用了io多路復用技術實現了 

四、io多路復用

  • 什么是io復用
IO復用解決的就是并發行的問題,比如多個用戶并發訪問一個WEB網站,對于服務端后臺而言就會產生多個請求,處理多個請求對于中間件就會產生多個IO流對于系統的讀寫。那么對于IO流請求操作系統內核有并行處理和串行處理的概念,串行處理的方式是一個個處理,前面的發生阻塞,就沒辦法完成后面的請求。這個時候我們必須考慮并行的方式完成整個IO流的請求來實現最大的并發和吞吐,這時候就是用到IO復用技術。IO復用就是讓一個Socket來作為復用完成整個IO流的請求。
當然實現整個IO流的請求多線程的方式就是其中一種。
(一個socket作為復用來完成整個io流的請求連接建立(accept),而處理請求(recv,send,close)則采用多線程)
  • io復用之多線程處理
# -*- coding:utf-8 -*-
import socket
from threading import Threaddef comm(conn):data = conn.recv(1024)conn.send(data)conn.close()obj = socket.socket(socket.AF_INET,socket.SOCK_STREAM)   # sockfd (socket 文件描述符,這個描述符是用來監聽的--監聽socket)
obj.bind(('127.0.0.1',8082))                             # 綁定地址
obj.listen(5)                                            # 開啟監聽while True:conn,addr  = obj.accept()             // 每建立一個 連接 就交由線程處理t = Thread(target=comm,args=(conn,))  // 創建線程對象t.start()                             // 啟動// 這樣就可以處理多個io請求,不會因為一個沒處理完而導致的堵塞
  • io 多路復用
多個描述符(監聽描述符,已連接描述符) 的io 操作都能在一個線程內并發交替順序完成,這就叫io多路復用,
這里的復用指的是復用同一個線程
  • io 多路復用的三種機制 select poll epoll
    • select
        #include <sys/select.h>int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);//參數nfds是需要監聽的最大的文件描述符值+1//rdset,wrset,exset分別對應需要檢測的可讀文件描述符的集合,//可寫文件描述符的集合集異常文件描述符的集合//參數timoout為結構timeval,用來設置select()的等待時間
        1、用戶將自己所關心的文件描述符添加進描述符集中,并且明確關心的是讀,寫,還是異常事件2、select 通過輪詢的方式不斷掃碼所有被關心的文件描述符,具體時間由參數timeout決定的3、執行成功則返回文件描述符已改變的個數4、具體哪一個或哪幾個文件描述符就緒,則需要文件描述符集傳出,它既是輸入型參數,又是輸出型參數5、fd_set 是用位圖存儲文件描述符的,因為文件描述符是唯一且遞增的整數
        特點:1、可關心的文件描述符數量是有上限的,取決于fd_set(文件描述符集)的大小2、每次的調用select 前,都要把文件描述符重新添加進fd_set(文件描述符集)中,因為fd_set也是輸出型參數在函數返回后,fd_set中只有就緒的文件描述符3、通常我們要關心的文件描述符不止一個,所有首先用數組保存文件描述符,每次調用select前再通過遍歷數逐個添加進去
    
        缺點:1、每次調用select都需要手動設置fd_Set2、每次調用select 需要遍歷fd_set 集合,而且要將fd_set 集合從用戶態拷貝到內核態,如何fd很多時,開銷會很大3、select 支持的文件描述符數量太少 32- 1024 64 -2048
    • poll
        #include <sys/poll.h>int poll(struct pollfd *fds, nfds_t nfds, int timeout);// 第一個參數是指向一個結構數組的第一個元素的指針// 第二個參數是要監聽的文件描述符的個數// 第三個參數意義與select相同        //pollfd結構struct pollfd{int fd; short events;  short revents;};//events 是我們要關心的事件,revents是調用后操作系統設置的參數,//也就是表明該文件描述符是否就緒
        首先創建一個pollfd結構體變量數組fd_list,然后將我們然后將我們關心的fd(文件描述符)放置在數組中的結構變量中,并添加我們所關系的事件,調用poll函數,函數返回后我們再通過遍歷的方式去查看數組中那些文件描述符上的事件就緒了。
        特點(相對于select)1、每次調用poll之前不需要手動設置文件描述符集2、poll將用戶關系的實際和發生的實際進程分離3、支持的文件描述符數量理論上是無上限的,其實也有,因為一個進程能打開的文件數量是有上限的 ulimit -n 查看進程可打開的最大文件數
        1、poll 返回后,也需要輪詢pollfd 來獲取就緒的描述符2、同時連接的大量客戶端,可能只有很少的處于就緒狀態,因此隨著監事的描述符數量的增長,其效率也會線性下降
    • select poll 的共同點
        都做了很多 無效的 輪詢檢測描述符是否就緒的操作
    • epoll
      • 代碼
          #include <sys/epoll.h>int epoll_create(int size);     // 在內核里,一切皆文件。所以,epoll向內核注冊了一個文件系統,//epoll_create的作用是創建一個epoll模型,該模型在底層建立了->//**紅黑樹,就緒隊列,回調機制**//size可以被忽略,不做解釋int epoll_ctl(int epfd, int op, int fd, struct epoll_events *event);//epfd:epoll_create()的返回值(epoll的句柄,本質上也是一個文件描述符)//op:表示動作,用三個宏來表示//    EPOLL_CTL_ADD:注冊新的fd到epfd中//    EPOLL_CTL_MOD:修改已經注冊的fd的監聽事件//    EPOLL_CTL_DEL:從epfd中刪除一個事件//fd:需要監聽的文件描述符//event:具體需要在該文件描述符上監聽的事件int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);//函數調用成功,返回文件描述符就緒的個數,也就是就緒隊列中文件描述符的個數,//返回0表示超時,小于0表示出錯//epoll_event結構體struct epoll_event{uint32_t events;  /* Epoll events */epoll_data_t data;/* User data variable */}__EPOLL_PACKED;//events可以是一堆宏的集合,這里介紹幾個常用的//  EPOLLIN:表示對應的文件描述符可以讀(包括對端socket正常關閉)//  EPOLLOUT:表示對應的文件描述符可以寫//  EPOLLET:將EPOLL設為邊緣觸發(Edge Triggered)模式,//          默認情況下epoll為水平觸發(Level Triggered)模式typedef union epoll_data{void *ptr;int fd;uint32_t u32;uint64_t u64;}epoll_data_t;//聯合體里通常只需要填充fd就OK了,其他參數暫時可以不予理會
      • 工作原理
          1、創建一個epoll 對象,向epoll 對象中添加文件描述符以及我們所關心的在在該文件描述符上發生的事件2、通過epoll_ctl 向我們需要關心的文件描述符中注冊事件(讀,寫,異常等),操作系統將該事件和對象的文件描述符作為一個節點插入到底層建立的紅黑樹中3、添加到文件描述符上的實際都會與網卡建立回調機制,也就是實際發生時會自主調用一個回調方法,將事件所在的文件描述符插入到就緒隊列中4、引用程序調用epoll_wait 就可以直接從就緒隊列中將所有就緒的文件描述符拿到,可以說時間復雜度O(1)
      • 水平觸發工作方式(LT)
          處理socket時,即使一次沒將數據讀完,下次調用epoll_wait時該文件描述符也會就緒,可以繼續讀取數據
      • 邊沿觸發工作方式(ET)
          處理socket時沒有一次將數據讀完,那么下次再調用epoll_wait該文件描述符將不再顯示就緒,除非有新數據寫入在該工作方式,當一個文件描述符就緒是,我們要一次性的將數據讀完
      • 隱患問題
          當我們調用read讀取緩沖去數據時,如果已經讀取完了,對端沒有關系蟹段,read就會堵塞,影響后續邏輯解決方式就是講文件描述符,設置成非堵塞的,當沒有數據的時候,read也不會被堵塞,可以處理后續邏輯(讀取其他的fd或者繼續wait)ET 的性能要好與LT,因為epoll_wait返回的次數比較少,ninx中默認采用ET模式使用epoll
      • 特點
          1、采用了回調機制,與輪詢區別看待2、底層采用紅黑樹結構管理已經注冊的文件描述符3、采用就緒隊列保存已經就緒的文件描述符
      • 優點
          1、文件描述符數目無上限:通過epoll_ctl 注冊一個文件描述符后,底層采用紅黑樹結構管理所有需要監控的文件描述符2、基于實際的就緒通知方式:每當有文件描述符就緒時,該響應事件會調用回調方法將該文件描述符插入到就緒隊列中,不需要內核每次去輪詢式的查看每個被關心的文件描述符3、維護就緒隊列:當文件描述符就緒的時候,就會被放到內核中的一個就緒隊列中,調用epoll_wait可以直接從就緒隊列中獲取就緒的文件描述符,時間復雜度是O(1)

四、總結

nginx 通過 多進程 + io多路復用(epoll) 實現了高并發采用多個worker 進程實現對 多cpu 的利用通過eopll 對 多個文件描述符 事件回調機制和就緒描述符的處理 實現單線程io復用從而實現高并發 

轉載于:https://www.cnblogs.com/xiaobaiskill/p/10969180.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/275026.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/275026.shtml
英文地址,請注明出處:http://en.pswp.cn/news/275026.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

轉載:程序員從初級到中級10個秘訣

Justin James曾發表過一篇博文《10 tips for advancing from a beginner to an intermediate developer》&#xff0c;為我們分享如何才能完成程序員從初級到中級的蛻變&#xff0c;現將中文譯文轉載于此&#xff0c;供大家借鑒。 在一封與TechRepublic會員交流的郵件當中&…

ux設計工具_UX設計中的工具和實用主義

ux設計工具There’s a zillion tools for User Experience and User Interface Design. Don’t take my word for it: a simple Google search for “what are the best tools for wireframing” (to take just one aspect of UX) leads you to endless pages of “The 20 best…

幕后常駐嘉賓配音小姐姐的2021年度總結

大家好&#xff0c;我是若川。這是公眾號幕后常駐嘉賓配音小姐姐&#xff0c;看完了上一個阿源小姐姐的年度總結《一張圖看程序媛阿源的2021個人年度流水賬》&#xff0c;寫的年度總結投稿。點擊以下音頻可以查看收聽往期更多音頻。以下是正文~Hi&#xff0c;大家好呀~我是若川…

java spring cloud版b2b2c社交電商spring cloud分布式微服務:服務注冊與發現(Eureka、Consul)...

Spring Cloud簡介電子商務社交平臺源碼請加企鵝求求&#xff1a;一零三八七七四六二六。Spring Cloud是一個基于Spring Boot實現的云應用開發工具&#xff0c;它為基于JVM的云應用開發中涉及的配置管理、服務發現、斷路器、智能路由、微代理、控制總線、全局鎖、決策競選、分布…

js 全選

<form name"frm" method"post" action"/add" onsubmit"return check()"><table class"titem" ><tr><td class"field"> * 所屬批次</td><td class"value"><sele…

結果規格化_結果

結果規格化If you’ve seen an Instagram story involving a question and people tilting their heads, you probably were looking at the “Who Is More” Instagram filter. In this article, I will share the creative process and decision making behind this filter.如…

2021 年 JavaScript 大事記

大家好&#xff0c;我是 ConardLi&#xff0c;不知不覺中&#xff0c;2021 年已經接近尾聲了&#xff0c;不知道在 2021 這一年&#xff0c;你收獲了什么&#xff1f;又失去了什么呢&#xff1f;又到了開始做年終總結的時候了&#xff0c;今天&#xff0c;我來給 JavaScript 做…

java版spring cloud+spring boot+redis多租戶社交電子商務平臺 (十三)springboot集成spring cache...

電子商務社交平臺源碼請加企鵝求求&#xff1a;三五三六二四七二五九本文介紹如何在springboot中使用默認的spring cache&#xff0c;聲明式緩存Spring 定義 CacheManager 和 Cache 接口用來統一不同的緩存技術。例如 JCache、 EhCache、 Hazelcast、 Guava、 Redis 等。在使用…

windows符號服務器地址

當調試windows程序的時候&#xff0c;有時候會需要一些符號文件。系統的公有符號文件微軟都是提供的&#xff0c;只需在調試器中設置即可&#xff0c;在下次調試時&#xff0c;調試器會自動從網上下載需要的符號文件。可以使用符號文件的調試器有windbg等等。 符號服務器地址&a…

如何融入到更積極的環境,促進技術提升

眾所周知&#xff0c;關注公眾號可以了解學習掌握技術方向&#xff0c;學習優質好文&#xff0c;落實到自己項目中。還可以結交圈內好友&#xff0c;讓自己融入到積極上進的技術氛圍&#xff0c;促進自己的技術提升。話不多說&#xff0c;推薦這些優質前端公眾號前端之神100w閱…

動畫 制作_您希望制作的10個醒目的徽標動畫

動畫 制作重點 (Top highlight)標志設計 (Logo Design) Have you ever watched paint dry? No? I didn’t think so. How about watched a turtle crossing the road? Probably not. Maybe spent an hour standing in line at the post office? Well that’s pretty likely…

NOIP訓練營集訓筆記—信息學基礎算法(倍增與分治算法

本文摘自清北OI學堂內部筆記&#xff0c;作者潘愷璠&#xff0c;來自柳鐵一中曾參加過清北訓練營提高組精英班&#xff0c;主要記錄的是信息學基礎算法。筆記非常詳細&#xff0c;特分享給大家&#xff01; NOIP2019年夏令營正在報名中&#xff0c;6大校區10種班型&#xff0c;…

使用 CSS 用戶選擇控制選擇

IE10 平臺預覽 4 包括一個新的 CSS 屬性的支持-ms-user-select&#xff0c;這使得 Web 開發者控制完全可以選擇什么的文本&#xff0c;在其網站上更容易。如果你是看我一整天都在我的工作站&#xff0c;您會注意到我讀計算機上時&#xff0c;我選擇的文本。我不是只有一個人讀起…

一個在校的普通前端小姐姐的2021

大家好&#xff0c;我是若川。這是我的源碼共讀群里一個大三的前端小姐姐&#xff08;小曹同學&#xff09;的年度總結。她寫了5篇源碼筆記。同時做了很多項目&#xff0c;獲得了很多獎。而且策劃和建立了學校工作室的前端訓練營&#xff0c;40人報名參加。總之就是現在的大學生…

按鈕 交互_SwiftUI中的微交互—菜單按鈕動畫

按鈕 交互Microinteractions have become increasingly important in a world with a dizzying number of digital platforms and an ocean of content. While microinteractions used to be considered an interesting resource in the early days of digital design, in toda…

JavaScript邏輯運算符的使用技巧

前言 !, &&, || 三個運算符是JavaScript中重要的邏輯運算符&#xff0c;本文將介紹這三個運算符在JavaScript實際編程中的有趣使用技巧。 取反運算符&#xff08;!&#xff09; 如果對一個值連續做兩次取反運算&#xff0c;等于將其轉為對應的布爾值&#xff0c;與Bool…

如何接觸到最新的前端動態、最前沿的前端技術

眾所周知&#xff0c;關注公眾號可以了解學習掌握技術方向&#xff0c;學習優質好文&#xff0c;落實到自己項目中。還可以結交圈內好友&#xff0c;讓自己融入到積極上進的技術氛圍&#xff0c;促進自己的技術提升。話不多說&#xff0c;推薦這些優質前端公眾號前端有道社區活…

選擇控件— UI組件系列

重點 (Top highlight)The word “toggle” is a reference to a switch with a short handle that alternates between two states each time it is activated. You encounter it every time you “switch” on the lights.單詞“ toggle”是指帶有短手柄的開關&#xff0c;該開…

linux -- Linux diff與patch的深入分析

diff的輸出格式分為傳統格式和統一格式 1)diff的傳統格式輸出. ############################################ cat before.txt 輸出: This is a line to be deleted This is a line that will be changed This is a line that will be unchanged cat after.txt 輸出: This is …

shell命令之---sed

1. sed編輯器基礎 1.1 替換標記 命令格式&#xff1a;s/pattern/replacement/flags $ cat data4.txt    This is a test of the test script.    This is the second test of the test script.    有4種可用的替換標記&#xff1a; 數字&#xff0c;表明新文本將替…