Web服務器主要任務就是處理來自客戶端的請求,一般情況下Web服務器處理並發連接請求的工作模型有以下幾種方式:
1、單線程web服務器(Single-threaded web servers)
此種架構方式中,web服務器一次處理一個請求,結束后讀取並處理下一個請求。在某請求處理過程中,其它所有的請求將被忽略,因此,在並發請求較多的場景中將會出現嚴重的性能問題。(即一次只能處理一個請求)
2、多進程/多線程web服務器
此種架構方式中,web服務器生成多個進程或線程並行處理多個用戶請求,進程或線程可以按需或事先生成。有的web服務器應用程序為每個用戶請求生成一個單獨的進程或線程來進行響應,不過,一旦並發請求數量達到成千上萬時,多個同時運行的進程或線程將會消耗大量的系統資源。(即每個進程只能響應一個請求,並且一個進程對應一個線程)
3、I/O多路復用web服務器
為了能夠支持更多的並發用戶請求,越來越多的web服務器正在采用多種復用的架構———即同步監控所有的連接請求的活動狀態,當一個連接的狀態發生改變時(如數據准備完畢或發生某錯誤),將為其執行一系列特定操作;在操作完成后,此連接將重新變回暫時的穩定態並返回至打開的連接列表中,直到下一次的狀態改變。由於其多路復用的特性,進程或線程不會被空閑的連接所占用,因而可以提供高效的工作模式。(這種架構可以理解為一個進程可以生成多個線程,每個請求交給一個線程進行處理)
4、多路復用多線程web服務器
將多進程和多路復用的功能結合起來形成的web服務器架構,其避免了讓一個進程服務於過多的用戶請求,並能充分利用多CPU主機所提供的計算能力。(這種架構可以理解為有多個進程,並且一個進程又生成多個線程,每個線程處理一個請求)
linux下常用的I/O模型(這里借用下在網上查閱的資料,感覺還好理解):
先引入select和epoll概念:
select和epoll是兩個處理I/O模型的機制,可以加速請求處理,2者處理方式不同:通俗的講,select機制是對沒有處理好的I/O請求在一段時間內進行檢測,並將其狀態通知給用戶,即有沒有完成都會通知。而epool機制則是在該I/O請求完成后才通知給用戶。
在Unix/Linux下共有五種I/O模型,分別是:
1)阻塞I/O
2)非阻塞I/O
3)I/O復用(select和poll)
4)信號驅動I/O(SIGIO)
5)異步I/O(Posix.1的aio_系列函數)
對以上模型的比較:
阻塞I/O:
應用程序調用一個IO函數,導致應用程序阻塞,等待數據准備好。 如果數據沒有准備好,一直等待….數據准備好了,從內核拷貝到用戶空間,IO函數返回成功指示
非阻塞I/O:
我們把一個套接口設置為非阻塞就是告訴內核,當所請求的I/O操作無法完成時,不要將進程睡眠,而是返回一個錯誤。這樣我們的I/O操作函數將不斷的測試數據是否已經准備好,如果沒有准備好,繼續測試,直到數據准備好為止。在這個不斷測試的過程中,會大量的占用CPU的時間。
I/O復用(select和poll):
I/O復用模型會用到select或者poll函數,這兩個函數也會使進程阻塞,但是和阻塞I/O所不同的的,這兩個函數可以同時阻塞多個I/O操作。而且可以同時對多個讀操作,多個寫操作的I/O函數進行檢測,直到有數據可讀或可寫時,才真正調用I/O操作函數。
信號驅動I/O(SIGIO):
首先我們允許套接口進行信號驅動I/O,並安裝一個信號處理函數,進程繼續運行並不阻塞。當數據准備好時,進程會收到一個SIGIO信號,可以在信號處理函數中調用I/O操作函數處理數據。
異步I/O(Posix.1的aio_系列函數):
當一個異步過程調用發出后,調用者不能立刻得到結果。實際處理這個調用的部件在完成后,通過狀態、通知和回調來通知調用者的輸入輸出操作
回顧下apache的工作模塊:
prefork:多進程,每個請求用一個進程響應,這個過程會用到select機制來通知。
worker:多進程,一個進程可以生成多個線程,每個線程響應一個請求。
event:一個進程,每個進程響應多個用戶請求,它是基於事件實現的。
基於事件機制的特性:
一個進程響應多個用戶請求,利用run-loop機制,讓套接字復用,請求過來后進程並不處理請求,而是直接交由其他機制來處理,通過select或epoll機制來通知請求是否完成;在這個過程中,進程本身一直處於空閑狀態,可以一直接收用戶請求。
對於高並發請求的實現:
1、基於線程:即一個進程生成多個線程,每個線程響應用戶的每個請求。如worker模型
2、基於事件的模型,一個進程處理多個請求,並且通過epoll機制來通知用戶請求完成。如event模型
web服務器工作流程:
我們知道web服務器是工作在用戶空間的,用戶空間通過系統調用來與內核打交道。
用戶請求-->送達用戶空間-->系統調用-->內核空間-->內核到磁盤上讀取網頁資源(在此過程中就牽涉到了以上幾種模型的運用)
傳統上基於進程或線程模型架構的web服務通過每進程或每線程處理並發連接請求,這勢必會在網絡和I/O操作時產生阻塞,其另一個必然結果則是對內存或CPU的利用率低下。生成一個新的進程/線程需要事先備好其運行時環境,這包括為其分配堆內存和棧內存,以及為其創建新的執行上下文等。這些操作都需要占用CPU,而且過多的進程/線程還會帶來線程抖動或頻繁的上下文切換,系統性能也會由此進一步下降。
另一種高性能web服務器/web服務器反向代理:Nginx同(Engine X)
nginx的主要着眼點就是其高性能以及對物理計算資源的高密度利用,因此其采用了不同的架構模型。受啟發於多種操作系統設計中基於“事件”的高級處理機制,nginx采用了模塊化、事件驅動、異步、單線程及非阻塞的架構,並大量采用了多路復用及事件通知機制。在nginx中,連接請求由為數不多的幾個僅包含一個線程的進程worker以高效的回環(run-loop)機制進行處理,而每個worker可以並行處理數千個的並發連接及請求。
Nginx會按需同時運行多個進程:一個主進程
(master)和幾個工作進程
(worker),配置了緩存時還會有緩存加載器進程(cache loader)和緩存管理器進程(cache manager)等。所有進程均是僅含有一個線程,並主要通過“共享內存”的機制實現進程間通信。主進程以root用戶身份運行,而worker、cache loader和cache manager均應以非特權用戶身份運行。
主進程主要完成如下工作:
1. 讀取並驗正配置信息;
2. 創建、綁定及關閉套接字;
3. 啟動、終止及維護worker進程的個數;
4. 無須中止服務而重新配置工作特性;
5. 控制非中斷式程序升級,啟用新的二進制程序並在需要時回滾至老版本;
6. 重新打開日志文件;
7. 編譯嵌入式perl腳本;
worker進程主要完成的任務包括:
1. 接收、傳入並處理來自客戶端的連接;
2. 提供反向代理及過濾功能;
3. nginx任何能完成的其它任務;
如果負載以CPU密集型應用為主,如SSL或壓縮應用,則worker數應與CPU數相同;如果負載以IO密集型為主,如響應大量內容給客戶端,則worker數應該為CPU個數的1.5或2倍
Nginx的代碼是由一個核心和一系列的模塊組成, 核心主要用於提供Web Server的基本功能,以及Web和Mail反向代理的功能;還用於啟用網絡協議,創建必要的運行時環境以及確保不同的模塊之間平滑地進行交互。不過,大多跟協議相關的功能和某應用特有的功能都是由nginx的模塊實現的。這些功能模塊大致可以分為事件模塊、階段性處理器、輸出過濾器、變量處理器、協議、upstream和負載均衡幾個類別,這些共同組成了nginx的http功能。事件模塊主要用於提供OS獨立的(不同操作系統的事件機制有所不同)事件通知機制如kqueue或epoll等。協議模塊則負責實現nginx通過http、tls/ssl、smtp、pop3以及imap與對應的客戶端建立會話。
在nginx內部,進程間的通信是通過模塊的pipeline或chain實現的;換句話說,每一個功能或操作都由一個模塊來實現。例如,壓縮、通過FastCGI或uwsgi協議與upstream服務器通信,以及與memcached建立會話等。
緩存機制:
我們知道,用戶請求不止要請求靜態內容,反而大多數請求的都是動態類的網頁,在請求動態內容時,php服務器要和mysql打交道,如果請求數量太多,這勢必會導致響應用戶請求的速度變慢,為了解決這一問題,我們還要引入緩存的概念。
在這里我們引入一個加速緩存的工具
:Memcached
Memcached是一款開源、高性能、分布式內存對象緩存系統,可應用各種需要緩存的場景,其主要目的是通過降低對Database的訪問來加速web應用程序。它是一個基於內存的“鍵值對”存儲,用於存儲數據庫調用、API調用或頁面引用結果的直接數據,如字符串、對象等。
Memcached是一款開發工具,它既不是一個代碼加速器,也不是數據庫中間件。其設計哲學思想主要反映在如下方面:
1. 簡單key/value存儲:服務器不關心數據本身的意義及結構,只要是可序列化數據即可。存儲項由“鍵、過期時間、可選的標志及數據”四個部分組成;
2. 功能的實現一半依賴於客戶端,一半基於服務器端:客戶負責發送存儲項至服務器端、從服務端獲取數據以及無法連接至服務器時采用相應的動作;服務端負責接收、存儲數據,並負責數據項的超時過期;
3. 各服務器間彼此無視:不在服務器間進行數據同步;
4. O(1)的執行效率
5. 清理超期數據:默認情況下,Memcached是一個LRU緩存,同時,它按事先預訂的時長清理超期數據;但事實上,memcached不會刪除任何已緩存數據,只是在其過期之后不再為客戶所見;而且,memcached也不會真正按期限清理緩存,而僅是當get命令到達時檢查其時長;
Memcached提供了為數不多的幾個命令來完成與服務器端的交互,這些命令基於memcached的協議實現。
存儲類命令:set, add, replace, append, prepend
獲取數據類命令:get, delete, incr/decr
統計類命令:stats, stats items, stats slabs, stats sizes
清理命令: flush_all
下一篇內容會介紹到nginx和memcache的配置哦^_^
補充:代理的概念
Web代理服務器工作於web客戶端和web服務器之間,它負責接收來自於客戶端的http請求,並將其轉發至對應的服務;而后接收來自於服務端的響應,並將響應報文回送至客戶端。
客戶端連上web服務器后,若想獲得web服務器中的某個web資源,需遵守一定的通訊格式,HTTP協議用於定義客戶端與web服務器通迅的格式。
WEB瀏覽器與WEB服務器之間的一問一答的交互過程必須遵循一定的規則,這個規則就是HTTP協議
本文出自 “每一步都是新的起點!^_^” 博客,請務必保留此出處http://90112526.blog.51cto.com/6013499/1059700