IO複用
首先用python演示普通worker的socket操作,是如何應對請求的?
從上述代碼可以看出worker進程一共進行了四步:
- accpet() 與客戶端進行連接
- recv() 接收客戶端發過來的數據
- send() 向客戶端發送數據
- close() 關閉此次連接
經歷這四步時,如果在recv()時,發生了IO堵塞,那麼請求就會一直等待,直到close(),才會建立新連接。那麼如何在IO阻塞時,也能處理其他客戶的連接?
以上代碼演示了IO複用(多線程處理),這種方式解決了多個用戶併發請求一個WEB網站,讓每一個 socket複用完每個IO流的請求。nginx正是採取了這種方式,只是它的源碼更復雜。
IO複用和epoll模型
在介紹nginx的epoll模型時,我們要先看一下傳統IO多路複用模型的select和poll。
舉個例子:有大量用戶(100萬個)同時與一個進程保持TCP連接,而在某一時刻只有少量(幾十上百)是活躍的(即能接收數據包),那麼在這一時刻只需處理這些少量請求即可!
傳統select和poll:每次收集事件,都把這100萬連接的套接字傳給操作系統(用戶態內存到內核內存的大量複製),而由操作系統內核尋找這些鏈接上沒有處理的事件(浪費內存)。
epoll:將select和poll結合起,使用三步來操作。
- 調用epoll_creat建立一個epoll對象。
- 調用epoll_ctl向epoll對象中添加這100萬個連接的套接字。
- 調用epoll_wait收集發生事件的連接。這是主要的步驟,將事件的連接放入一個鏈表,只要在鏈表中尋找發生連接的事件,不用去遍歷這100萬個連接。
總結
nginx正是採用了多路IO複用+epoll方式來應對高併發。以master控制多個worker,實現對多核CPU的利用。
閱讀更多 李老師tome 的文章