標籤: 結束 ast gen 動態 高效能 資料請求 3.2 運行
對於沒有做過web開發的人來說,web開發涉及到的名詞似乎特別多,apache。nginx,cgi,php,http,cookie。session。這一大坨東西究竟是什麼,這裡我們就從網路的層面去理清楚這些東西。
1. 什麼是HTTP
對於web來說貫穿始終的東西就是HTTP,那麼什麼是HTTP?官方說法就是Hyper Text Transfer Protocol,從這個名字上面還推斷,HTTP是一種協議。而且是一種應用程式層協議,其相應的傳輸層協議TCP。
所以說究竟。HTTP就是建立在TCP基礎上的一種應用程式層協議。
所以簡單點說,就是client發起串連,然互連過tcp發過來一個資料報,server處理以後再回複一個資料報。並關閉串連。這樣一次http請求就結束了。
所以最初的http模型是一次請求相應一次串連。也就是我們常常看到的,http無狀態的特點。
1.1 資料報的格式
依據上面說的過程。就須要在server和client之間規定一種格式,兩方都依照這樣的格式來解包,http規定的協議格式例如以下:
用不論什麼一個抓包工具都能看到一個包的全貌,比方頭部欄位名會包含Accept, Accept-Encoding, Accept-language, cache-control, connection, cookie, host, user-agent等。
而伺服器回複的資料報一定含有一個status code。包頭包括cache-control, connection, content-encoding, content-type, date, pragma, server, setcookie, transfer-encoding等欄位。
後面會挑幾個有意思的欄位進行說明。
1.2 HTTP之COOKIE
先說cookie。cookie是用來做什麼的呢?我們知道http協議本身是說每一次請求都是無狀態的。即兩次請求之間沒有不論什麼邏輯上的關聯,http server不知道第二次請求和第一次請求是否來自同一個client。可是作為一個web應用無狀態是肯定不滿足需求的。一個最典型的範例就是使用者的登入態,我們不能要求每次使用者想要擷取一個頁面的時候都又一次登入,所以須要一些機制來記錄這些狀態,cookie和session是最主要的解決方式。
cookie是由瀏覽器來管理的,其一般儲存在client記憶體中,所以生命週期為瀏覽器會話期間,關閉瀏覽器以後。cookie會自己主動消失。
當然假設cookie設定了到期時間。也會由瀏覽器同步在磁碟其中。
在每次http請求的過程其中,瀏覽器會依照一定的原則選擇一部分cookie放在http包頭其中發給webserver。
所以cookie過長導致的直接結果就是http包體過大,因此http協議對cookie的長度是有限制的。
怎樣改動cookie呢?我們常常能看到用js或者php來改動cookie的sample code。用js來改動cookie是比較直觀的,由於cookie由瀏覽器來管理,js也是由瀏覽器來解析的。可是為什麼php作為server side的script也能改動cookie呢?就是由於http回包中的set-cookie這個欄位,通過這個欄位能夠告訴瀏覽器須要改動cookie的哪些欄位。
既然提到cookie,就一起說一下session。
session也是為了實現狀態儲存而設計的機制。不過它是存在server端的而已。
session能夠看做是server端的一個hash表,預設是以檔案的形式儲存的,這個hash表的key就是session id。session id會儲存在cookie其中,所以每次server解開http包以後,依據cookie中的session id就能夠在hash表中資料。那麼問題就來了,假設使用者在瀏覽器禁掉了cookie。是不是就找不到session了呢?當然不是,不過禁掉cookie還有非常多其它的方式能夠將其拼在http包其中傳回來呀,能夠放在包頭的其它欄位裡比方說get參數。也能夠放在包體其中,比如post參數,這樣的事情是不能難倒程式猿的
1.3 HTTP之長/短串連
在http1.0其中是沒有connection這個欄位的,由於在http1.0其中還是一次請求相應一次串連的,即在server發出相應以後會主動中斷連線。這樣會
而在http1.1版本號碼中添加了connection這個欄位,而且預設值是keep-alive。它另一個值是close。
keep-alive就是告訴對方這次請求的方式是長串連。即發送對應包以後不要中斷連線,即使是錯誤響應也不要中斷連線。
舉個範例:
Request
- connection: keep-alive表示這次請求過後請不要中斷連線
- connection: close表示這次請求後請中斷連線
Response
- connection: keep-alive這次請求以後我不會中斷連線
- connection: close 這次請求以後我會中斷連線。
所以說究竟request和response其中僅僅要有一個close,就意味著這次請求以後串連會斷開。
當第一個request和response對都是keep-alive的時候。一個長串連就建立了。這個時候用戶端就能夠採用pipeline的方式向server來發包了。pipeline方式指的是client無需等待回應而持久性的發送請求,server會依照request的順序來回複。
長串連帶來了新的問題。
1.3.1 逾時保護
假設串連建立以後一直處於inactive的狀態怎麼辦?浪費了server一個fd和client的port。所以須要有逾時保護機制,比如在nginx其中能夠配置其keepalive_timeout的值。http協議並沒有規定server和client的逾時時間。能夠由開發人員隨意指定。
1.3.2 分包協議
在短串連模式的時候。因為每次server響應後直接關閉串連,所以client的短僅僅須要推斷EOF來推斷response包是否結束。而對於keep alive模式,繼續用這樣的方式會極大減少效率。所以引入了content-length和transfer-encoding兩個欄位。
1.4 HTTP之資料報結束符
當用戶端請求一個server的靜態資源時。server清楚響應的訊息長度。所以能夠用content-length欄位告訴client響應資料的長度。
然而假設請求的是一個動態網頁,server預先是不可能知道對應包的長度。所以能夠才用transfer-encoding: trunked模式來傳遞資料,即一邊產生資料一邊發送。一次對應由多個trunk構成,終於由一個長度為0的trunk標記結束。每一個trunk是一個資料區塊。在trunk頭標記了當前資料區塊的長度。
2. 什麼是Apache和Nginx
假設他們作為http server(當然還有其它的feature),比較簡單地理解就是他們是對http協議的一種實現,比如nginx的HTTP模組基本就是依照HTTP協議的RFC文檔,把各種情況cover一遍。簡單點說。即解包->過濾->轉包->過濾->拼包。是nginx的一個簡要。
3. 一般的web架構是如何的
是一個常見的web架構,由反向 Proxyserver。httpserver組成。httpserver又分成nginx進程和php進程。
首先,暴露給使用者的是一個反向 Proxyserver。反向 Proxy的存在有幾個作用,一是負載平衡。反向 Proxyserver收到資料包以後會依照一定的負載平衡演算法轉寄到真正的業務server上面去,還有一個作用是防止攻擊。它會依照一定的規則過濾掉非常多不合法的請求,從而減少業務機的負載,由於其僅僅是簡單地轉寄,沒有真正的商務邏輯,所以即使駭客攻擊到了這一層也沒有太大的危害。同一時候反向 Proxyserver也能夠緩衝一些靜態資源。進一步減少業務機的負載。
nginx作為httpserver,在整個架構中主要負責hold串連。並不做請求的真正處理,在中被畫成了一個方塊。但其本身也是多進程的結構。
假如對同一台機器上面配置了8個nginx worker。每一個worker配置的串連數是1024,那麼這台機器hold串連的能力大概是8*1024。
nginx worker和php-fpm的通訊方式是通過socket來通訊的,所以說nginx和php-fpm能夠部署在同一台機器上也能夠部署在不同的機器上。
php-fpm是php的一個外掛程式,如今已經整合到了php的核心代碼中,是fast-cgi的一種實現。其進程結構和nginx基本類似,都是由一個master進程和多個worker進程構成的。fastcgi規定每過來一個請求,都從進程池裡挑選一個進程。來載入並運行一段php指令碼,指令碼結束以後將進城歸還給進程池。所以php-fpm說究竟就是一個進程管理器,正如其名字所看到的(FastCGI Process Manager)。
php-fpm對於其worker進程數的配置由兩種static和dynamic。若配置成static表示在fpm啟動的時候由master直接fork出max_children的worker數,而且在執行其中這個數字是不變的。
而dynamic則表示依據詳細的請求動態fork worker進程,最大值為max_children。那麼,這個max_children該怎樣配置呢?假設worker數過少,那麼php-fpm收到nginx的資料請求時發現進程池裡面已經沒有進程了,直接就會拒絕服務,導致此次http請求以502告終。
假設max_children配置過多的話,會佔用多餘的系統資源,尤其是在static情況下。所以比較適中的辦法就是將這個值先配得大一些,然後去觀察active的進程數。最後選擇一個合適的值。
我們能夠看到在fastcgi模式下。一個進程是相應一個請求的,假如說在一台機器上我們配置了300個fastcgi進程,那麼其能同一時候處理的最大請求數就是300個,是遠遠小於nginx的接入能力的。
假設php有一些堵塞調用(如檔案上傳下載等),當前進程不能處理其它的請求,所以說php-fpm在在這套架構裡是瓶頸,怎樣在此提高效能是一個值得探討的問題。
當瀏覽器出現一個錯誤頁或者白頁的時候。有可能是不論什麼一個環節出現故障。這就要慢慢的查了。
深入淺出web服務