Apache httpd 是如何實現高併發服務的

原創:花括號MC(微信公衆號:huakuohao-mc)。關注JAVA基礎編程及大數據,注重經驗分享及我的成長。apache

進行網絡通訊的時候,須要創建一個socket,這是你們都知道的。若是一個套接字只能被一個監聽進(線)程監聽,那麼豈不是同一時刻httpd只能處理一個請求,處理完這個請求以後,釋放80端口在給其餘請求使用。但是顯然httpd 沒有那麼笨,那麼apache httpd 是如何支持高併發的呢?編程

簡單的說就是有兩種套接字,一種是監聽套接字,供監聽進(線)程監聽使用。另外一種是連接套接字,供傳輸數據使用。監聽進(線)程比如麗春院裏面接客的老鴇,而爲客人提供彈唱服務的姑娘至關於worker模式下的工做線程。老鴇能夠有一個,可是姑娘有不少。在apache httpdworker模式下,每一個進程會產生多個工做線程及一個監聽線程。監聽線程負責監聽,其餘工做線程負責傳輸數據。問題回答完了,就這麼簡單。服務器

那麼監聽套接字鏈接套接字是如何配合工做的呢? 要回答這個問題,須要有兩個背景知識作鋪墊,網絡編程TCP三次握手微信

背景知識1-網絡編程

有過網絡編程經驗的同窗都知道,把'大象放冰箱'通常是以下幾個步驟。網絡

  1. 經過socket() 函數創建監聽套接字;
  2. 經過bind()函數綁定剛剛生成的監聽套接字;
  3. 經過listen()函數監聽剛剛生成的監聽套接字;
  4. 經過accept() 函數生成鏈接套接字;
  5. 經過recv()/send()函數利用鏈接套接字收發數據;
  6. 經過close()函數斷開鏈接。

你們記住這幾個步驟,後面用的到。如今來講TCP的三次握手過程。併發

背景知識2-TCP三次握手

咱們常常見到的TCP三次握手過程都是這樣的。 以下圖:socket

上面這張圖,只是表面現象。下面我把這張圖沒有體現出來的細節給各位說一說,這對回答上面的問題相當重要。tcp

TCP的協議棧中維護着兩個隊列。一個是半鏈接隊列,一個是全連接隊列。 客戶端發送SYN報文到服務端指定端口好比httpd的默認80端口;此時客戶端的狀態變爲SYN-SEND;服務端收到SYN報文以後,將這個鏈接狀態,存儲到半鏈接隊列中,同時服務端的狀態變動爲SYN-RECV;而後服務端馬上回一個ACK報文給客戶端;客戶端收到ACK以後,回給服務端一個ACK,服務端收到這個ACK以後,客戶端跟服務端都變爲ESTABLISHE狀態;代表TCP三次握手成功。這個時候會把半鏈接隊列中的鏈接,轉移到全連接隊列。全連接隊列中的鏈接都是已經完成三次握手的鏈接。監聽進(線)程監聽監聽套接字,就是工做在上面這個過程的。編輯器

全連接隊列當中的鏈接都是能夠用來直接進行數據傳輸的鏈接了。這個時候可使用accept()函數,將全連接當中的鏈接取出來,生成鏈接socket,進行數據傳輸。傳輸完畢以後,通過四次揮手,關掉鏈接,釋放資源。這就是一次完整的TCP傳輸過程。函數

俗話說的好,一圖勝千言。我將上面的過程簡單的畫了一個流程圖出來。

圖中標綠的部分分別是三次握手過程跟四次揮手過程。這兩個階段發生在內核空間。

Linux 2.2之前,listen()函數有一個backlog的參數,用於設置這兩個隊列的最大總長度,從Linux 2.2開始,這個參數只表示全連接隊列的最大長度,而/proc/sys/net/ipv4/tcp_max_syn_backlog則用於設置半鏈接隊列的最大長度。/proc/sys/net/core/somaxconn則是硬限制已完成隊列的最大長度,默認爲128,若是backlog大於somaxconn,則backlog會被強制等於somaxconn

回到apache httpd
prefork模式

apache httpdprefork模式會建立子進程處理http請求。每一個子進程,即負責監聽又負責處理數據。也就是說從創建三次握手到數據傳輸,再到四次揮手,一個子進程負責到底。若是傳輸的數據量比較大,同時系統高併發有比較高,那就須要創建不少子進程,對服務器的硬件資源是個不小的考驗。

worker模式

worker模式是進線程混合模式,主進程會建立子進程,每一個子進程會建立多個工做子線程及一個監聽進程。監聽進程專門負責處理監聽套接字,數據傳輸過程交給其餘工做線程。因此worker模式要比prefork模式在性能上提升很多。

event模式

event模式跟worker模式基本相同,都是進線程混合模式,不一樣的是,該模式還會生成一個專門處理keep-alive的線程。keep-alive雖好,可是某些狀況下存在站着茅坑不拉屎的狀況,這樣能夠把保持keep-alive的空閒鏈接資源進行回收。keep-alive的問題能夠看我這篇文章

結束

既然eventworker都是進線程混合模式,那麼爲何event模塊的性能要比worker模塊的性能好不少呢?我將在下篇博文中詳細說明。

·END·
 

花括號MC

Java·大數據·我的成長

微信號:huakuohao-mc
相關文章
相關標籤/搜索