1、進程、線程html
進程是具備必定獨立功能的,在計算機中已經運行的程序的實體。在早期系統中(如linux 2.4之前),進程是基本運做單位,在支持線程的系統中(如windows,linux2.6)中,線程纔是基本的運做單位,
而進程只是線程的容器。程序自己只是指令、數據及其組織形式的描述,進程纔是程序(那些指令和數據)的真正運行實例。若干進程有可能與同一個程序相關係,且每一個進程皆能夠同步(循序)或異步(平行)的方式獨立運行。
現代計算機系統可在同一段時間內以進程的形式將多個程序加載到存儲器中,並藉由時間共享(或稱時分複用),以在一個處理器上表現出同時(平行性)運行的感受。
一樣的,使用多線程技術(多線程即每個線程都表明一個進程內的一個獨立執行上下文)的操做系統或計算機架構,一樣程序的平行線程,可在多 CPU 主機或網絡上真正同時運行(在不一樣的CPU上)。linux
2、常見Web服務方式nginx
2.1 三種工做模型比較:web
Web服務器要爲用戶提供服務,必須以某種方式,工做在某個套接字上。通常Web服務器在處理用戶請求時,通常有以下三種方式可選擇:多進程方式、多線程方式、異步方式。apache
多進程方式:爲每一個請求啓動一個進程來處理。因爲在操做系統中,生成進程、銷燬進程、進程間切換都很消耗CPU和內存,當負載高時,性能會明顯下降。windows
優勢:穩定性!因爲採用獨立進程處理獨立請求,而進程之間是獨立的,單個進程問題不會影響其餘進程,所以穩定性最好。後端
缺點: 資源佔用!當請求過大時,須要大量的進程處理請求,進程生成、切換開銷很大,並且進程間資源是獨立的,形成內存重複利用。緩存
多線程方式:一個進程中用多個線程處理用戶請求。因爲線程開銷明顯小於進程,並且部分資源還能夠共享,所以效率較高。服務器
優勢:開銷較小!線程間部分數據是共享的,且線程生成與線程間的切換所需資源開銷比進程間切換小得多。
缺點:穩定性!線程切換過快可能形成線程抖動,且線程過多會形成服務器不穩定。網絡
異步方式:使用非阻塞方式處理請求,是三種方式中開銷最小的。但異步方式雖然效率高,但要求也高,由於多任務之間的調度若是出現問題,就可能出現總體故障,
所以使用異步工做的,通常是一些功能相對簡單,但卻符合服務器任務調度、且代碼中沒有影響調度的錯誤代碼存在的程序。
優勢:性能最好!一個進程或線程處理多個請求,不須要額外開銷,性能最好,資源佔用最低。
缺點:穩定性!某個進程或線程出錯,可能致使大量請求沒法處理,甚至致使整個服務宕機。
(1)客戶發起請求到服務器網卡;
(2)服務器網卡接受到請求後轉交給內核處理;
(3)內核根據請求對應的套接字,將請求交給工做在用戶空間的Web服務器進程
(4)Web服務器進程根據用戶請求,向內核進行系統調用,申請獲取相應資源(如index.html)
(5)內核發現web服務器進程請求的是一個存放在硬盤上的資源,所以經過驅動程序鏈接磁盤
(6)內核調度磁盤,獲取須要的資源
(7)內核將資源存放在本身的緩衝區中,並通知Web服務器進程
(8)Web服務器進程經過系統調用取得資源,並將其複製到進程本身的緩衝區中
(9)Web服務器進程造成響應,經過系統調用再次發給內核以響應用戶請求
(10)內核將響應發送至網卡
(11)網卡發送響應給用戶
用戶請求-->送達到用戶空間-->系統調用-->內核空間-->內核到磁盤上讀取網頁資源->返回到用戶空間->響應給用戶。
客戶端向Web服務器請求的過程當中,有兩個I/O過程,一個就是客戶端請求的I/O,另外一個就是Web服務器請求頁面的磁盤I/O
3、各類I/O模型詳解
用戶空間中的進程或線程是沒法直接操做I/O的,須要經過系統調用內核發起。
即進程向內核進行系統調用申請IO,內核將資源從IO調度到內核的buffer中(wait階段)
內核還需將數據從內核buffer中複製到web服務器進程所在的用戶空間,纔算完成一次IO調度(copy階段)。
這幾個階段都是須要時間的。根據wait和copy階段的處理等待的機制不一樣,可將I/O動做分爲以下五種模式:
(1)阻塞I/O
(2)非阻塞I/O
(3)I/O複用(select和poll)
(4)信號(事件)驅動I/O(SIGIO)
(5)異步I/O(aio)
3.1 I/O模型簡介
3.1.1 阻塞和非阻塞:
阻塞和非阻塞指的是執行一個操做是等操做結束再返回,仍是立刻返回。
好比餐館的服務員爲用戶點菜,當有用戶點完菜後,服務員將菜單給後臺廚師,此時有兩種方式:
第一種:就在出菜窗口等待,直到廚師炒完菜後將菜送到窗口,而後服務員再將菜送到用戶手中(阻塞)
第二種:等一會再到窗口來問廚師,某個菜好了沒?若是沒有先處理其餘事情,等會再去問一次(非阻塞)
3.1.2 同步和異步:
同步和異步又是另一個概念,它是事件自己的一個屬性。還拿前面點菜爲例,服務員直接跟廚師打交道,菜出來沒出來,服務員直接知道,但只有當廚師將菜送到服務員手上,這個過程纔算正常完成,這就是同步的事件。
一樣是點菜,有些餐館有專門的傳菜人員,當廚師炒好菜後,傳菜員將菜送到傳菜窗口,並通知服務員,這就變成異步的了。
其實異步還能夠分爲兩種:帶通知的和不帶通知的。
對於同步的事件,你只能以阻塞的方式去作。
對於異步的事件,阻塞和非阻塞都是能夠的。
3.1.3 全異步I/O
回到I/O,無論是I仍是O,對外設(磁盤)的訪問均可以分紅請求和執行兩個階段。請求就是看外設的狀態信息(好比是否準備好了),執行纔是真正的I/O操做。
linux2.6以後才引入AIO(asynchronous I/O )把「執行」異步化。別看Linux/Unix是用來作服務器的,這點上比Windows落後了好多。
3.1.4 I/O的五種模型
阻塞I/O:全部過程全阻塞
非阻塞I/O:若是沒有數據buffer,則當即返回EWOULDBLOCK
I/O複用(select和poll):在wait和copy階段分別阻塞
信號驅動I/O(SIGIO):在wait階段不阻塞,但copy階段阻塞(信號驅動I/O,即通知)
異步I/O(aio):徹底無阻塞方式,當I/O完成時提供信號
Linux上的前四種I/O模型的「執行」階段都是同步的,只有最後一種才作到了真正的全異步。第一種阻塞式是最原始的方法,也是最累的辦法。固然累與不累要看針對誰。應用程序是和內核打交道的。對應用程序來講,這種方式是最累的,
但對內核來講這種方式偏偏是最省事的。還拿點菜這事爲例,你就是應用程序,廚師就是內核,若是你去了一直等着,廚師就省事了(不用同時處理其餘服務員的菜)。
固然如今計算機的設計,包括操做系統,愈來愈爲終端用戶考慮了,爲了讓用戶滿意,內核慢慢的承擔起愈來愈多的工做,IO模型的演化也是如此。
非阻塞I/O ,I/O複用,信號驅動式I/O其實都是非阻塞的,固然是針對「請求」這個階段。非阻塞式是主動查詢外設狀態。I/O複用裏的select,poll也是主動查詢,
不一樣的是select和poll能夠同時查詢多個fd(文件句柄)的狀態,另外select有fd個數的限制。epoll是基於回調函數的。信號驅動式I/O則是基於信號消息的。這兩個應該能夠歸到「被動接收消息」那一類中。
最後就是偉大的AIO的出現,內核把什麼事都幹了,對上層應用實現了全異步,性能最好,固然複雜度也最高。
3.2 Unix下共有五種I/O模型
阻塞I/O
非阻塞I/O
I/O複用(select和poll)
信號驅動I/O(SIGIO)
異步I/O(Posix.1的aio_系列函數)
(1)阻塞I/O
應用程序調用一個IO函數,致使應用程序阻塞,等待數據準備好。
若是數據沒有準備好,一直等待。。。。
數據準備好了,從內核拷貝到用戶空間
IO函數返回成功指示
(2)非阻塞I/O模型
咱們把一個套接口設置爲非阻塞就是告訴內核,當所請求的I/O操做沒法完成時,不要將進程睡眠,而是返回一個錯誤。
這樣咱們的I/O操做函數將不斷的測試數 據是否已經準備好,若是沒有準備好,繼續測試,直到數據準備好爲止。在這個不斷測試的過程當中,會大量的佔用CPU的時間。
(3)I/O複用模型
I/O 複用模型會用到select或者poll函數,這兩個函數也會使進程阻塞,可是和阻塞I/O所不一樣的,這兩個函數能夠同時阻塞多個I/O操做。
並且能夠 同時對多個讀操做,多個寫操做的I/O函數進行檢測,直到有數據可讀或可寫時,才真正調用I/O操做函數。
(4)信號驅動I/O模型
首先咱們容許套接口進行信號驅動I/O,並安裝一個信號處理函數,進程繼續運行並不阻塞。當數據準備好時,進程會收到一個SIGIO信號,能夠在信號處理函數中調用I/O操做函數處理數據。
(5)異步I/O模型
調用aio_read函數,告訴內核描述字,緩衝區指針,緩衝區大小,文件偏移以及通知的方式,而後當即返回。當內核將數據拷貝到緩衝區後,再通知應用程序。
3.3 幾種I/O模型的比較
前四種模型的區別是第一階段基本相同,第二階段基本相同,都是將數據從內核拷貝到調用者的緩衝區。而異步I/O的兩個階段都不一樣於前四個模型。
3.3.1 同步I/O和異步I/O
a.同步I/O操做引發請求進程阻塞,直到I/O操做完成。異步I/O操做不引發請求進程阻塞。
b.咱們的前四個模型都是同步I/O,只有最後一個異步I/O模型是異步I/O。
3.4 Linux I/O模型的具體實現
3.4.1 主要實現方式有如下幾種:
select
poll
epoll
kqueue
/dev/poll
iocp
注,其中iocp是Windows實現的,select、poll、epoll是Linux實現的,kqueue是FreeBSD實現的,/dev/poll是SUN的Solaris實現的。
select、poll對應第3種(I/O複用)模型,iocp對應第5種(異步I/O)模型
epoll、kqueue、/dev/poll,能夠看做有了第4種(信號驅動I/O)模型的某些特性
3.4.2 爲何epoll、kqueue、/dev/poll比select高級?
答案是,他們無輪詢。由於他們用callback取代了。想一想看,當套接字比較多的時候,每次select()都要經過遍歷FD_SETSIZE個Socket來完成調度,無論哪一個Socket是活躍的,都遍歷一遍。
這會浪費不少CPU時間。若是能給套接字註冊某個回調函數,當他們活躍時,自動完成相關操做,那就避免了輪詢,這正是epoll、kqueue、/dev/poll作的。
假設你在大學讀書,住的宿舍樓有不少間房間,你的朋友要來找你。select版宿管大媽就會帶着你的朋友挨個房間去找,直到找到你爲止。
而epoll版宿管大媽會先記下每位同窗的房間號,你的朋友來時,只需告訴你的朋友你住在哪一個房間便可,不用親自帶着你的朋友滿大樓找人。
若是來了10000我的,都要找本身住這棟樓的同窗時,select版和epoll版宿管大媽,誰的效率更高,不言自明。
同理,在高併發服務器中,輪詢I/O是最耗時間的操做之一,select、epoll、/dev/poll的性能誰的性能更高,一樣十分明瞭。
3.4.3 Windows or *nix (IOCP or kqueue、epoll、/dev/poll)?
Windows的IOCP很是出色,目前不多有支持asynchronous I/O的系統,可是因爲其系統自己的侷限性,大型服務器仍是在UNIX下。
並且正如上面所述,kqueue、epoll、/dev/poll 與 IOCP相比,就是多了一層從內核copy數據到應用層的阻塞,從而不能算做asynchronous I/O類。
可是,這層小小的阻塞無足輕重,kqueue、epoll、/dev/poll 已經作得很優秀了。
3.4.4 總結一些重點
只有IOCP(windows實現)是asynchronous I/O,其餘機制或多或少都會有一點阻塞。
select(Linux實現)低效是由於每次它都須要輪詢。但低效也是相對的,視狀況而定,也可經過良好的設計改善
epoll(Linux實現)、kqueue(FreeBSD實現)、/dev/poll(Solaris實現)是Reacor模式,IOCP是Proactor模式。
Apache 2.2.9以前只支持select模型,2.2.9以後支持epoll模型
Nginx 支持epoll模型
Java nio包是select模型
4、Apache Httpd的工做模式
4.1 apache三種工做模式
咱們都知道Apache有三種工做模塊,分別爲prefork、worker、event。
prefork:多進程,每一個請求用一個進程響應,這個過程會用到select機制來通知。
worker:多線程,一個進程能夠生成多個線程,每一個線程響應一個請求,但通知機制仍是select不過能夠接受更多的請求。
event:基於異步I/O模型,一個進程或線程,每一個進程或線程響應多個用戶請求,它是基於事件驅動(也就是epoll機制)實現的。
4.2 prefork的工做原理
若是不用「--with-mpm」顯式指定某種MPM,prefork就是Unix平臺上缺省的MPM.它所採用的預派生子進程方式也是 Apache1.3中採用的模式。
prefork自己並無使用到線程,2.0版使用它是爲了與1.3版保持兼容性;另外一方面,prefork用單獨的子進程來處理不一樣的請求,進程之間是彼此獨立的,這也使其成爲最穩定的MPM之一。
4.3 worker的工做原理
相對於prefork,worker是2.0版中全新的支持多線程和多進程混合模型的MPM。因爲使用線程來處理,因此能夠處理相對海量的請求,而系統資源的開銷要小於基於進程的服務器。
可是,worker也使用了多進程,每一個進程又生成多個線程,以得到基於進程服務器的穩定性,這種MPM的工做方 式將是Apache2.0的發展趨勢。
4.4 event 基於事件機制的特性
一個進程響應多個用戶請求,利用callback機制,讓套接字複用,請求過來後進程並不處理請求,而是直接交由其餘機制來處理,經過epoll機制來通知請求是否完成;
在這個過程當中,進程自己一直處於空閒狀態,能夠一直接收用戶請求。能夠實現一個進程程響應多個用戶請求。支持持海量併發鏈接數,消耗更少的資源。
5、如何提升Web服務器的併發鏈接處理能力
基於線程,即一個進程生成多個線程,每一個線程響應用戶的每一個請求。
基於事件的模型,一個進程處理多個請求,而且經過epoll機制來通知用戶請求完成。
基於磁盤的AIO(異步I/O)
支持mmap內存映射,mmap傳統的web服務器,進行頁面輸入時,都是將磁盤的頁面先輸入到內核緩存中,再由內核緩存中複製一份到web服務器上,mmap機制就是讓內核緩存與磁盤進行映射,
web服務器,直接複製頁面內容便可。不須要先把磁盤的上的頁面先輸入到內核緩存去。
恰好,Nginx 支持以上全部特性。因此Nginx官網上說,Nginx支持50000併發,是有依據的。
6、Nginx優異之處
6.1 簡介
傳統上基於進程或線程模型架構的web服務經過每進程或每線程處理併發鏈接請求,這勢必會在網絡和I/O操做時產生阻塞,其另外一個必然結果則是對內存或CPU的利用率低下。
生成一個新的進程/線程須要事先備好其運行時環境,這包括爲其分配堆內存和棧內存,以及爲其建立新的執行上下文等。這些操做都須要佔用CPU,並且過多的進程/線程還會帶來線程抖動或頻繁的上下文切換,系統性能也會由此進一步降低。
另外一種高性能web服務器/web服務器反向代理:Nginx(Engine X),nginx的主要着眼點就是其高性能以及對物理計算資源的高密度利用,所以其採用了不一樣的架構模型。
受啓發於多種操做系統設計中基於「事件」的高級處理機制,nginx採用了模塊化、事件驅動、異步、單線程及非阻塞的架構,並大量採用了多路複用及事件通知機制。
在nginx中,鏈接請求由爲數很少的幾個僅包含一個線程的進程worker以高效的迴環(run-loop)機制進行處理,而每一個worker能夠並行處理數千個的併發鏈接及請求。
6.2 Nginx 工做原理
Nginx會按需同時運行多個進程:一個主進程(master)和幾個工做進程(worker),配置了緩存時還會有緩存加載器進程(cache loader)和緩存管理器進程(cache manager)等。
全部進程均是僅含有一個線程,並主要經過「共享內存」的機制實現進程間通訊。主進程以root用戶身份運行,而worker、cache loader和cache manager均應以非特權用戶身份運行。
主進程主要完成以下工做:
讀取並驗正配置信息;
建立、綁定及關閉套接字;
啓動、終止及維護worker進程的個數;
無須停止服務而從新配置工做特性;
控制非中斷式程序升級,啓用新的二進制程序並在須要時回滾至老版本;
從新打開日誌文件;
編譯嵌入式perl腳本;
worker進程主要完成的任務包括:
接收、傳入並處理來自客戶端的鏈接;
提供反向代理及過濾功能;
nginx任何能完成的其它任務;
注:若是負載以CPU密集型應用爲主,如SSL或壓縮應用,則worker數應與CPU數相同;若是負載以IO密集型爲主,如響應大量內容給客戶端,則worker數應該爲CPU個數的1.5或2倍。
6.3 Nginx 架構
Nginx的代碼是由一個核心和一系列的模塊組成, 核心主要用於提供Web Server的基本功能,以及Web和Mail反向代理的功能;
還用於啓用網絡協議,建立必要的運行時環境以及確保不一樣的模塊之間平滑地進行交互。不過,大多跟協議相關的功能和某應用特有的功能都是由nginx的模塊實現的。
這些功能模塊大體能夠分爲事件模塊、階段性處理器、輸出過濾器、變量處理器、協議、upstream和負載均衡幾個類別,這些共同組成了nginx的http功能。
在Nginx內部,進程間的通訊是經過模塊的pipeline或chain實現的;換句話說,每個功能或操做都由一個模塊來實現。
例如,壓縮、經過FastCGI或uwsgi協議與upstream服務器通訊,以及與memcached創建會話等。
6.4 Nginx 基礎功能
處理靜態文件,索引文件以及自動索引;
反向代理加速(無緩存),簡單的負載均衡和容錯;
FastCGI,簡單的負載均衡和容錯;
模塊化的結構。過濾器包括gzipping, byte ranges, chunked responses, 以及 SSI-filter 。在SSI過濾器中,到同一個 proxy 或者 FastCGI 的多個子請求併發處理;
SSL 和 TLS SNI 支持;
6.5 Nginx IMAP/POP3 代理服務功能
使用外部 HTTP 認證服務器重定向用戶到 IMAP/POP3 後端;
使用外部 HTTP 認證服務器認證用戶後鏈接重定向到內部的 SMTP 後端;
6.6 Nginx 其餘HTTP功能
基於IP 和名稱的虛擬主機服務;
Memcached 的 GET 接口;
支持 keep-alive 和管道鏈接;
靈活簡單的配置;
從新配置和在線升級而無須中斷客戶的工做進程;
可定製的訪問日誌,日誌寫入緩存,以及快捷的日誌回捲;
4xx-5xx 錯誤代碼重定向;
基於 PCRE 的 rewrite 重寫模塊;
基於客戶端 IP 地址和 HTTP 基本認證的訪問控制;
PUT, DELETE, 和 MKCOL 方法;
支持 FLV (Flash 視頻);
帶寬限制;
6.7 爲何選擇Nginx (1)在高鏈接併發的狀況下,Nginx是Apache服務器不錯的替代品: Nginx在美國是作虛擬主機生意的老闆們常常選擇的軟件平臺之一. 可以支持高達 50,000 個併發鏈接數的響應, 感謝Nginx爲咱們選擇了 epoll and kqueue 做爲開發模型。 (2)Nginx做爲負載均衡服務器: Nginx 既能夠在內部直接支持 Rails 和 PHP 程序對外進行服務, 也能夠支持做爲 HTTP代理 服務器對外進行服務. Nginx採用C進行編寫, 不管是系統資源開銷仍是CPU使用效率都比 Perlbal 要好不少。 (3)做爲郵件代理服務器: Nginx 同時也是一個很是優秀的郵件代理服務器(最先開發這個產品的目的之一也是做爲郵件代理服務器), Last.fm 描述了成功而且美妙的使用經驗. (4)Nginx 是一個 [#installation 安裝] 很是的簡單 , 配置文件 很是簡潔(還可以支持perl語法),Bugs 很是少的服務器: Nginx 啓動特別容易, 而且幾乎能夠作到7*24不間斷運行,即便運行數個月也不須要從新啓動. 你還可以 不間斷服務的狀況下進行軟件版本的升級 。 (5)Nginx 的誕生主要解決C10K問題