聊聊 HTTP 性能優(yōu)化
哈嘍大家好,我是咸魚。
作為用戶的我們在 "上網(wǎng)沖浪" 的時(shí)候總是希望快一點(diǎn),尤其是搶演唱會門票的時(shí)候,但是現(xiàn)實(shí)并非如此,有時(shí)候我們會遇到頁面加載緩慢、響應(yīng)延遲的情況。
而 HTTP 協(xié)議作為互聯(lián)網(wǎng)世界的基礎(chǔ),從網(wǎng)站打開速度到移動(dòng)應(yīng)用的響應(yīng)時(shí)間,HTTP 性能的優(yōu)化直接關(guān)系到我們在網(wǎng)絡(luò)世界的舒適體驗(yàn)程度。
更快的響應(yīng)時(shí)間和速度能夠提供更好的用戶體驗(yàn),不但如此,還可以降低服務(wù)器和網(wǎng)絡(luò)帶寬的使用,從而節(jié)省相關(guān)的成本。
那么今天我們就來聊聊 HTTP 性能如何進(jìn)行優(yōu)化。
數(shù)據(jù)壓縮
隨著互聯(lián)網(wǎng)的發(fā)展,網(wǎng)路上傳輸?shù)臄?shù)據(jù)越來越大,隨隨便便一個(gè)文件幾個(gè) G 甚至上百 G,就算你是百兆、千兆帶寬也扛不住。
如何能夠在有限的帶寬里傳輸更多的數(shù)據(jù),常見的解決方式是數(shù)據(jù)壓縮。
如果壓縮率能有 50%,例如 100K 的數(shù)據(jù)能夠壓縮成 50K 的大小,那么就相當(dāng)于在帶寬不變的情況下網(wǎng)速提升了一倍,加速的效果是非常明顯的。
使用常見的壓縮算法(如 gzip 和 br )對數(shù)據(jù)進(jìn)行壓縮,不但如此,我們可以對 HTTP 中傳輸?shù)母鞣N數(shù)據(jù)進(jìn)行針對性地壓縮,做到【對癥下藥】。
- HTML/CSS/JS
對于這類純文本格式數(shù)據(jù),我們在進(jìn)行壓縮時(shí)通常會去除其中多余的空格、換行和注釋等元素。盡管壓縮后的文本可能看起來比較混亂,對人類可讀性較差,但這對計(jì)算機(jī)并不影響流暢閱讀。
- JPG/JPEG/PNG
對于這類圖片格式數(shù)據(jù),雖然它本身已經(jīng)被壓縮過了,不能被 gzip、br 處理,但仍然有優(yōu)化的空間。
例如,可以考慮去除圖片中的拍攝時(shí)間、地點(diǎn)、機(jī)型等元數(shù)據(jù),適度降低分辨率和縮小尺寸。
此外,盡量采用高壓縮率的格式,有損格式可以選擇 JPEG,而無損格式則可以考慮使用 webp 格式。
- 小數(shù)據(jù)
對于較小的數(shù)據(jù),HTTP 中有一種被稱為 “資源合并”(Concatenation)的優(yōu)化方式,即將多個(gè)小資源合并成一個(gè)大資源,通過單個(gè)請求下載到客戶端,隨后由客戶端使用 JavaScript、CSS 等進(jìn)行拆分使用。
這種方式雖然減少了請求的次數(shù),但是處理起來比較麻煩。
需要注意的是,在數(shù)據(jù)壓縮的時(shí)候應(yīng)當(dāng)注意選擇適當(dāng)?shù)膲嚎s率,不要追求最高壓縮比,否則會耗費(fèi)服務(wù)器的計(jì)算資源,增加響應(yīng)時(shí)間,反而會“得不償失”。
上面講的都是針對 HTTP 報(bào)文里的 body 的壓縮方式,對于 header 的壓縮在 HTTP/1 里是沒有的(HTTP/2 才有)。
不過我們可以采取一些手段來減少 header 的大小,不必要的字段就盡量不發(fā)(例如 User-Agent、Server、X-Powered-By)
使用緩存
數(shù)據(jù) “千里迢迢” 從服務(wù)端到客戶端,我們可以把這些 “來之不易” 的數(shù)據(jù)【暫時(shí)保存】起來,以便在下次請求時(shí)直接復(fù)用,從而避免多次請求帶來的高昂成本。
比如說網(wǎng)站上訪問量最高的網(wǎng)頁、熱點(diǎn)新聞,尤其是【讀多寫少】的數(shù)據(jù),把它們緩存下來能夠把巨大的流量擋在外面,減輕服務(wù)器的壓力,對性能的改善是非常顯著
的。
HTTP 傳輸?shù)拿恳粋€(gè)環(huán)節(jié)基本上都會有緩存,不過大致可以分成:
- 瀏覽器端緩存
- 服務(wù)端緩存
- 中間傳輸緩存
在瀏覽器端,通過與服務(wù)端協(xié)商相關(guān)的緩存策略,將一些資源緩存到本地,以便在下次訪問時(shí)進(jìn)行復(fù)用。
常見的緩存策略包括 HTTP 頭中的 Cache-Control、Expires 以及 ETag 等,通過這些標(biāo)識,瀏覽器可以判斷是否需要從服務(wù)端重新獲取資源,或者直接使用本地緩存。
在服務(wù)端,可以借助專門的緩存中間件,如 Memcache 或 Redis,將計(jì)算得到的中間結(jié)果和資源存儲在內(nèi)存或硬盤中。
這樣,Web 服務(wù)器在處理請求時(shí)會首先檢查緩存,如果找到相應(yīng)的數(shù)據(jù),就能夠立即返回給客戶端,避免了訪問后端服務(wù)或數(shù)據(jù)庫的時(shí)間開銷。
而關(guān)于中間傳輸?shù)木彺?,常見的?HTTP 代理緩存和 CDN(Content Delivery Network,內(nèi)容分發(fā)網(wǎng)絡(luò))。
HTTP 代理緩存,通過使用增加了緩存功能的 HTTP 代理服務(wù)器(例如 Nginx),緩存源服務(wù)器的數(shù)據(jù),分發(fā)給下游的客戶端。
而使用 CDN 把源服務(wù)器的內(nèi)容逐級緩存到網(wǎng)絡(luò)中的每一個(gè) CDN 節(jié)點(diǎn)中,這樣用戶在上網(wǎng)的時(shí)候就不直接訪問源站,而是訪問離它最近的一個(gè) CDN 節(jié)點(diǎn)(其實(shí)就是緩存了源服務(wù)器內(nèi)容的代理服務(wù)器)
圖片
使用高性能 web 服務(wù)器
除了傳輸過程中對數(shù)據(jù)進(jìn)行壓縮和使用緩存,我們還可以在服務(wù)端下手。
首先我們應(yīng)該選擇高性能的 Web 服務(wù)器,最常見的應(yīng)該就是 Nginx 了。
作為一款【高性能,輕量級】的 Web 服務(wù)器,【進(jìn)程池+單線程】的工作模式讓 Nginx 消耗較少的 CPU 和內(nèi)存,非常輕量,而【I/O 多路復(fù)用】又使得 Nginx 的工作效率大大提升。
我們還可以通過 Nginx 實(shí)現(xiàn)【動(dòng)靜分離】:把動(dòng)態(tài)頁面和靜態(tài)頁面交給不同的服務(wù)器來解析,來加快解析速度,提高請求的訪問效率,降低原來單個(gè)服務(wù)器的壓力。
# Nginx 動(dòng)靜分離配置
server {
listen 80 ;
location ~* \.(png)$ {
root /var/images/png/;
}
location ~* \.(php)$ {
proxy_pass http://php_back_end;
}
}
不但如此,在配置 Nginx 的時(shí)候還應(yīng)該開啟 HTTP 長連接。
這樣做可以平均握手成本到多次請求中,避免了每個(gè)請求都要進(jìn)行 TCP 連接建立和斷開的開銷,從而提高了性能。連接的復(fù)用使得后續(xù)的請求不再需要進(jìn)行完整的三次握手過程,減少了連接建立的延遲。
升級 HTTP/2
除了上面的【數(shù)據(jù)壓縮】、【使用緩存】、【使用高性能 web 服務(wù)器】,HTTP 性能優(yōu)化還有一個(gè)選擇,那就是【把協(xié)議由 HTTP/1 升級到 HTTP/2】
HTTP/2 基于 Google 的 SPDY 協(xié)議,完全兼容 HTTP/1,我們來看看它的一些優(yōu)點(diǎn)。
- 頭部壓縮
報(bào)文 Header 一般會攜帶 “User Agent”、“Cookie”、“Accept”、“Server” 等許多固定的頭字段,多達(dá)幾百字節(jié)甚至上千字節(jié),但 Body 卻經(jīng)常只有幾十字節(jié)(比如 GET 請求)
更要命的是,成千上萬的請求響應(yīng)報(bào)文里有很多字段值都是重復(fù)的,非常浪費(fèi),導(dǎo)致大量帶寬消耗在了這些冗余度極高的數(shù)據(jù)上。
為了壓縮頭部,HTTP/2 開發(fā)了專門的 “HPACK” 算法:在客戶端和服務(wù)器兩端建立“字典”,用索引號表示重復(fù)的字符串,還釆用哈夫曼編碼來壓縮整數(shù)和字符串,可以達(dá)到 50%~90% 的高壓縮率。
- 二進(jìn)制格式
相較于 HTTP/1 里純文本形式的報(bào)文,HTTP/2 全面采用二進(jìn)制格式,既方便計(jì)算機(jī)解析,而且體積小、速度快,使性能大大提高。
除此之外,HTTP/2 使用虛擬的流(stream)傳輸消息,解決了“隊(duì)頭阻塞”問題,同時(shí)實(shí)現(xiàn)了“多路復(fù)用”,提高連接的利用率;
圖片
今天這篇文章講了 HTTP 性能優(yōu)化的一些方法,希望能對你有幫助!