- HTTP/2 in Action 中文版
- (美)Barry Pollard(巴里·波拉德)
- 3171字
- 2020-08-06 15:52:07
2.2 解決HTTP/1.1性能問題的方案
如前所述,HTTP/1.1不是一種高效的協(xié)議,因?yàn)樗鼮榈却憫?yīng)會阻塞發(fā)送。導(dǎo)致在當(dāng)前請求完成之前,無法發(fā)送另一個請求。如果網(wǎng)絡(luò)或服務(wù)器速度較慢,HTTP性能會比較差。由于通過HTTP訪問的服務(wù)器通常距離客戶端較遠(yuǎn),因此網(wǎng)絡(luò)緩慢是HTTP必須面對的事實(shí)。在起初使用HTTP時(shí)(單個HTML文檔時(shí)代),這種緩慢并不是一個大問題。但隨著網(wǎng)頁變得越來越復(fù)雜,渲染頁面需要的資源越來越多,速度慢的問題就突顯出來了。
由于網(wǎng)站響應(yīng)緩慢而催生了網(wǎng)絡(luò)性能優(yōu)化行業(yè),市面上有許多關(guān)于如何改進(jìn)網(wǎng)絡(luò)性能的書籍和教程。雖然克服HTTP/1.1的問題并不是唯一的網(wǎng)絡(luò)性能優(yōu)化方法,但它是一個重要的問題。隨著時(shí)間的推移,已經(jīng)有各種突破HTTP/1.1的性能限制的技術(shù),這些技術(shù)分為以下兩類:
? 使用多個HTTP連接。
? 合并HTTP請求。
其他的和HTTP關(guān)聯(lián)不大的性能優(yōu)化技術(shù),包括優(yōu)化用戶請求資源的方式(比如先請求關(guān)鍵CSS),減小下載資源的大小(壓縮和使用響應(yīng)式圖片),減少瀏覽器的渲染任務(wù)(更高效的CSS和JavaScript)。這些技術(shù)的細(xì)節(jié)超出了本書的討論范圍,但我們會在第6章涉及一些。Manning出版社所出版的Web Performance in Action(Jeremy Wagner著)一書[9],是學(xué)習(xí)這些技術(shù)的絕佳資料。
2.2.1 使用多個HTTP連接
打開多個連接是解決HTTP/1.1阻塞問題的最簡單方法,這樣可以同時(shí)開啟多個HTTP請求。另外,與管道化技術(shù)不同,該技術(shù)不會導(dǎo)致HOL阻塞,因?yàn)槊總€HTTP連接都獨(dú)立于其他HTTP連接。因此,大多數(shù)瀏覽器可以為每個域名打開6個連接。
為了進(jìn)一步突破6個連接的限制,許多網(wǎng)站從子域(例如,static.example.com)提供靜態(tài)資源,如圖像、CSS和JavaScript,Web瀏覽器從而可以為每個新域名打開另外6個連接。這種技術(shù)稱為域名分片(盡管性能原因相似,但非Web背景的讀者不要與數(shù)據(jù)庫分片混淆)。除了提高并發(fā)數(shù),域名發(fā)散還有其他優(yōu)勢,比如減小HTTP請求首部(如cookies)(參見2.3節(jié))。通常,這些域名托管在同一臺服務(wù)器上。共享相同的資源但使用不同的域名會讓瀏覽器誤以為服務(wù)器是相互獨(dú)立的。如圖2.7所示的stackoverflow.com網(wǎng)站使用多個域:從Google域加載JQuery,從cdn.static.net域加載腳本和樣式表,從i.stack.imgur.com域加載圖像。
圖2.7 stackoverflow.com使用多個域名加載資源
使用多個HTTP連接聽起來不錯,但它也有缺點(diǎn)。當(dāng)開啟多個HTTP連接時(shí),客戶端和服務(wù)器都有額外的開銷:打開TCP連接需要時(shí)間,維護(hù)連接需要更多的內(nèi)存和CPU資源。
開啟多個HTTP連接的主要問題是,沒有充分利用底層的TCP協(xié)議。TCP是一種可靠的協(xié)議。在TCP中,發(fā)送數(shù)據(jù)包時(shí)會附一個序列號,如果序列中哪個數(shù)據(jù)包丟了,其會要求重發(fā)。TCP要求三次握手來建立連接,如圖2.8所示。
圖2.8 TCP三次握手
TCP三次握手的過程:
1. 客戶端發(fā)送一個同步(SYN)消息,并附上首個序列號,在這個TCP連接之后的數(shù)據(jù)包都會基于此序列號。
2. 服務(wù)器向客戶端確認(rèn)收到發(fā)來的序列號(ACK),并發(fā)送一個服務(wù)器同步消息(SYN),告訴客戶端它要使用的序列號。這兩個消息被合并為一個SYN-ACK消息。
3. 最后,客戶端確認(rèn)收到服務(wù)器的序列號,發(fā)送一個ACK消息。
這個過程需要三次網(wǎng)絡(luò)消息傳遞(或者1.5次往返),發(fā)生在發(fā)送HTTP請求之前。
另外,TCP在開啟連接時(shí)比較小心,在確認(rèn)網(wǎng)絡(luò)不擁堵之前只會發(fā)送比較少的數(shù)據(jù)包。CWND(Congestion Window,擁塞窗口)隨著時(shí)間的推移逐漸增加,只要連接沒發(fā)現(xiàn)丟包,就可以處理更大的流量。TCP擁塞窗口的大小受TCP慢啟動算法控制。因?yàn)門CP是一個不會讓網(wǎng)絡(luò)過載的可靠協(xié)議,所以在擁塞窗口中的TCP數(shù)據(jù)包需要在收到ACK消息之后發(fā)送。這些數(shù)據(jù)包使用在三次握手過程中協(xié)商的遞增的序列號。所以,在CWND比較小時(shí),可能需要多個TCP ACK消息才能發(fā)出一個完整的HTTP請求。因?yàn)镠TTP響應(yīng)常常比請求大很多,所以它同樣也會受到擁塞窗口的影響。由于TCP連接的應(yīng)用更加廣泛,所以人們提升了擁塞窗口的大小以使它更高效,但是在創(chuàng)建它時(shí)是給它限流了的,不管它所處環(huán)境的網(wǎng)絡(luò)有多快,帶寬有多大。在第9章,我們會再次討論TCP,這里只是為了說明使用多個HTTP連接的問題。
最后,就算沒有TCP建立連接的開銷和慢啟動的問題,使用多個獨(dú)立的連接也可能導(dǎo)致帶寬問題。例如,如果所有帶寬都用掉了,就會導(dǎo)致TCP超時(shí),和其他的連接上的重傳。在這些獨(dú)立的連接之間,沒有優(yōu)先級的概念,這就無法更高效地利用帶寬。
創(chuàng)建TCP連接之后,安全的網(wǎng)站要求建立HTTPS連接。這個過程可以節(jié)約開銷,比如,重用TCP連接的參數(shù),不從零開始。但這個過程依然需要更多的網(wǎng)絡(luò)往返,這意味著更多的時(shí)間。這里不討論HTTPS握手的細(xì)節(jié),在第4章我們會深入研究。
所以,在TCP和HTTPS的層面,開啟多個連接并不高效,盡管在HTTP的層面這么做是一種很棒的優(yōu)化。這個解決HTTP/1.1延遲問題的方案需要更多額外的請求和響應(yīng),所以這個方案反而可能會導(dǎo)致延遲問題,這本是它應(yīng)該解決的問題。
另外,當(dāng)這些新增的TCP連接達(dá)到了TCP的最佳效率,網(wǎng)頁所需要的大量資源已經(jīng)加載完成后,這些增加的連接就沒用了。如果公用的資源被緩存起來,那么甚至連后續(xù)的頁面也不需要請求更多的資源。Mozilla的Patrick McManus在對HTTP/1的監(jiān)控中發(fā)現(xiàn),“74%的活躍連接僅傳輸一個會話。”在本章后面,會展示一些實(shí)際的案例。
所以,開啟多個TCP連接并不是解決HTTP/1問題的滿意方案,盡管在沒有更好的解決方案時(shí),它確實(shí)可以提升性能。另外,這也說明了為什么瀏覽器限制每個域名開啟的連接數(shù)為6。盡管可以增大這個數(shù)字(一些瀏覽器允許這么做),但考慮到每個連接的額外開銷,收益會比較低。
2.2.2 發(fā)送更少的請求
另外一個常見的優(yōu)化技術(shù)是發(fā)送更少的請求,包括:減少不必要的請求(比如在瀏覽器中緩存靜態(tài)資源),以更少的HTTP請求獲取同樣的資源。前一種方法會使用到HTTP首部配置,在第1章中簡單介紹過它,在第6章還會詳細(xì)說明。后一種方法需要打包合并靜態(tài)資源。
對于圖片來說,這種打包技術(shù)叫作精靈圖。例如,如果你網(wǎng)站上有很多社交網(wǎng)站圖標(biāo),則每個網(wǎng)站圖標(biāo)都可以使用一個單獨(dú)的圖片。但這種方式會導(dǎo)致很多低效的HTTP請求排隊(duì),因?yàn)閳D片比較小,所以相對于下載這些圖片所需要的時(shí)間,發(fā)送請求的時(shí)間可能會較長。所以,可以將它們合并到一張大的圖片里面,然后使用CSS來定位圖片位置,讓它們看起來像是獨(dú)立的圖片,這樣更高效。圖2.9顯示了一個TinyPNG上面的精靈圖,它將通用的圖標(biāo)合并到了一個文件中。
圖2.9 TinyPNG的精靈圖
如果是CSS和JavaScript文件,很多網(wǎng)站就將多個文件合并為一個文件,這樣需要的請求數(shù)就少了,但是總的代碼量并不少。在合并文件的時(shí)候,通常還會去掉代碼中不必要的空格、注釋和其他不必要的元素,以減小CSS和JavaScript的文件尺寸。這些方法都會提升效率,但是會增加配置的難度。
其他的技術(shù)還包括內(nèi)聯(lián)資源到其他文件。比如,Critical CSS經(jīng)常直接被內(nèi)聯(lián)在HTML的<style>標(biāo)簽中。圖片可以包含在CSS中,通過行內(nèi)SVG,或者轉(zhuǎn)換為Base64編碼,也能減少HTTP請求數(shù)。
這個方案的主要問題是它引入的復(fù)雜度。創(chuàng)建精靈圖需要額外的操作,通過獨(dú)立的文件來提供圖片更簡單。不是所有的網(wǎng)站都有做優(yōu)化(如合并CSS文件)的自動化工作流。如果你的網(wǎng)站使用一個內(nèi)容管理系統(tǒng)(CMS,Content Management System),它可能不會自動合并JavaScript,或者合并圖片。
另外一個問題是,合并會導(dǎo)致文件的浪費(fèi)。一些網(wǎng)頁可能只用到一張精靈圖中的一兩個圖標(biāo),但卻要下載整張精靈圖。我們很難知道精靈圖中哪些元素還在用,哪些需要刪掉。當(dāng)有新的精靈圖時(shí),還要重寫CSS文件,以防止新的精靈圖中圖標(biāo)的位置發(fā)生變化。同樣,如果合并了太多文件,JavaScript也可能會變得臃腫。有時(shí)候我們只需要其中的很少一部分,卻要下載一個大得多的文件。無論是從網(wǎng)絡(luò)的方面(特別在開始的時(shí)候,TCP啟動慢)還是從瀏覽器執(zhí)行的方面(瀏覽器需要處理它不需要的代碼)來說,這種技術(shù)都不夠高效。
最后一個問題是緩存。如果把精靈圖緩存了很長一段時(shí)間(這樣用戶就不需要頻繁下載它),當(dāng)需要添加一個圖標(biāo)的時(shí)候,必須讓瀏覽器再次下載整個精靈圖,但訪客并不需要。可以使用很多技術(shù)來解決這個問題,比如添加版本號或者使用查詢參數(shù)[10],但是這些技術(shù)也會浪費(fèi)資源。使用CSS和JavaScript也一樣,改變一行代碼就需要重新下載整個合并文件。
2.2.3 HTTP/1性能優(yōu)化總結(jié)
歸根到底,優(yōu)化HTTP/1性能的方法是一些解決HTTP/1基礎(chǔ)缺陷的小技巧。應(yīng)該有更好的辦法在協(xié)議層面解決這個問題,從而節(jié)省時(shí)間,這正是HTTP/2要做的。
- 手把手教你學(xué)AutoCAD 2010:機(jī)械實(shí)戰(zhàn)篇
- 贏在測試2:中國軟件測試專家訪談錄
- 計(jì)算機(jī)應(yīng)用基礎(chǔ)實(shí)驗(yàn)指導(dǎo)
- 隨手查:系統(tǒng)重裝與維護(hù)技巧
- 策略三十六計(jì)和算法三十六計(jì)
- 大學(xué)計(jì)算機(jī)基礎(chǔ)(第2版)(微課版)
- 光榮與夢想:互聯(lián)網(wǎng)口述系列叢書·劉韻潔篇
- 知識圖譜:方法、實(shí)踐與應(yīng)用
- 邊緣計(jì)算:一種應(yīng)用視角
- 計(jì)算機(jī)文化基礎(chǔ)(Windows 7+Office 2010)
- 大學(xué)計(jì)算機(jī)應(yīng)用基礎(chǔ)
- Android面試寶典
- 計(jì)算機(jī)應(yīng)用基礎(chǔ)(Windows 7+Office 2010)
- 計(jì)算光刻與版圖優(yōu)化
- Windows Server 2008操作系統(tǒng)項(xiàng)目教程