標籤:

apache和nginx那點事兒--阻塞和非同步

先明白的事兒:當一個程序在執行的時候,一般會創建一個進程,也可以有多個進程。一個進程至少會創建一個線程,多個線程共享一個程序進程的內存。程序的運行最終是靠線程來完成操作的。線程的數量跟CPU核數有關,一個核最多能發出兩個線程。線程的操作主要分為:一:給CPU進行程序命令的執行。二:IO的操作(讀取或輸出數據)或者請求網路數據。

什麼是阻塞:就是線程在執行IO操作獲取數據時,這個IO可能會需要一定的時間才能等到數據返回,然後才能接著執行下面的命令。那麼,此時,這個線程的等待狀態我們就把它稱為阻塞。沒有充分利用起cpu的資源。

什麼是非阻塞:還是這個線程在進行 IO操作時,無需等待數據的返回,可以接著往下執行代碼命令。cpu資源一直在充分利用。

但是總要知道數據什麼時候返回吧,常見的兩個解決方案:

第一:如果程序是單線程的情況下,在接著執行下面的代碼過程中,需要額外不斷的輪詢查看這個IO請求的數據是否返回。

第二:使用多線程,一個進程繼續等待數據返回,另一個線程繼續操作執行下面的代碼。cpu資源一直在充分利用。

什麼是同步和非同步:同步指的當線程進行IO操作請求數據時,是你主動"關心"數據的返回。非同步是當前線程無需主動關心數據是否返回,當數據返回時,會有相關的事件通知你。

舉個通俗的例子:

你打電話問書店老闆有沒有《分散式系統》這本書,如果是同步通信機制,書店老闆會說,你稍等,」我查一下",然後開始查啊查,等查好了(可能是5秒,也可能是一天)告訴你結果(返回結果)。

而非同步通信機制,書店老闆直接告訴你我查一下啊,查好了打電話給你,然後直接掛電話了(不返回結果)。然後查好了,他會主動打電話給你。在這裡老闆通過「回電」這種方式來回調。

由此可見:阻塞並不等於同步,非阻塞也不等於非同步。阻塞不阻塞的區別點在於:線程當遇到IO操作,需要等待IO返回數據時,是否能繼續往下執行代碼。而同步與非同步的區別點在於:IO要返回的數據是需要線程主動等待,還是被動的等待數據處理完之後主動通知你。

最好的理想方案就是:非同步非阻塞。而nginx就使用的非阻塞+非同步。apache使用的是同步阻塞。這也就是為什麼nginx能比apache處理更多的請求更高的並發的原因。

apache與nginx的工作原理:

假如下面是類似apache和nginx的偽代碼:

listen //監聽埠

while(true){

$conn = accept() //一直循環接收連接

$read_content = read(conn)//讀取請求的文件

$esponse = process(conn) # 執行業務邏輯

echo $espnse //返回客戶端內容

}

apache:

每一個連接,apache就會創建一個進程,每個進程內單線程,apache最多能創建256個進程。對於一個負載相對較高的網站來說,256的進程,也就是256個線程,因為線程處理請求時,是同步阻塞模式,接收請求之後,會一直等待該請求讀取程序文件(IO)(同步),執行業務邏輯,返回客戶端,所有操作完成之後才能處理下一個請求(阻塞)如果伺服器已經達到256的極限,那麼接下去的訪問就需要排隊這也就是為什麼某些伺服器負載不高的原因了。

nginx:

nginx接收一個請求後,不會等待這個請求的文件讀取操作完成之後才接收下一個請求,它不會等待這個請求的後續的處理結果。而是會馬上循環處理下一個請求(不阻塞)。請求的程序文件執行完成之後,會主動通知該線程,不用你主動去等待或者輪詢查看(非同步)。最後返回給客戶端。這樣做,每個請求過來就不需要等待很長的時間排隊,而是馬上就能接收,開始進行處理了。等處理完成之後,會主動通知回調這個線程進行數據返回。


推薦閱讀:

開發人員學Linux(8):CentOS7編譯安裝Subversion1.9.5及Apache2.4.25並集成
React 路/粉/黑 都該了解的 React license 爭議
python如何抓取本地數據包?
Apache新成員:LinkedIn分散式數據集成框架Gobblin
怎樣通俗的講解 PHP 和 Apache 的關係?

TAG:PHP | Apache | Nginx |