
本文作者: 喬銳杰 現(xiàn)擔(dān)任上海駐云信息科技有限公司運維總監(jiān)/架構(gòu)師。曾任職過黑客講師、java軟件工程師/網(wǎng)站架構(gòu)師、高級運維、阿里云架構(gòu)師等職位。維護過上千臺服務(wù)器,主導(dǎo)過眾安保險、新華社等千萬級上云架構(gòu)。在云端運維、分布式集群架構(gòu)等方面有著豐富的經(jīng)驗。
以下正文
上次寫了一篇數(shù)據(jù)庫緩存,由于快餐式的風(fēng)格,遭到了廣大讀友的吐槽。上篇風(fēng)格有點 “ 虛 ”,我本身是一個技術(shù)控,偏向經(jīng)驗/干貨的分享,本文主要描述靜態(tài)緩存方面的一些心得及分享。作為系列二,有所不足之處,依舊希望大家踴躍“ 亮磚 ”。
說起靜態(tài)緩存技術(shù),CDN是經(jīng)典代表之作。靜態(tài)緩存技術(shù)面非常廣,涉及的開源技術(shù)包含apache、Lighttpd、nginx、varnish、squid等。
靜態(tài)緩存,一般指 web 類應(yīng)用中,將圖片、js、css、視頻、html等靜態(tài)文件/資源通過磁盤/內(nèi)存等緩存方式,提高資源響應(yīng)方式,減少服務(wù)器壓力/資源開銷的一門緩存技術(shù)。
本文主要通過:瀏覽器緩存、磁盤緩存、內(nèi)存緩存、nginx的內(nèi)存緩存、CDN五個方面圍繞靜態(tài)緩存而展開。
一、瀏覽器緩存
瀏覽器緩存,也稱為客戶端緩存,是靜態(tài)緩存中最常見最直接的表現(xiàn)形式,很多時候都往往被人忽略掉。
案例1:
我們經(jīng)常在nginx的配置文件中看到以下緩存配置:

案例2:
在經(jīng)常寫 jsp 的時候,html 標(biāo)簽中關(guān)于 http 頭信息也可以注意到“ expires ”的字樣:

對于案例1和案例2中(nginx設(shè)置的expires優(yōu)先級大于代碼中設(shè)置的expires優(yōu)先級),expires是給一個資源設(shè)定一個過期時間,也就是說無需去服務(wù)端驗證,直接通過瀏覽器自身確認(rèn)是否過期即可,所以不會產(chǎn)生額外的流量。此種方法非常適合不經(jīng)常變動的資源。如果文件變動較頻繁,就不要使用 expires 來緩存。
比如對于常見類web網(wǎng)站來說,css 樣式和 js 腳本基本已經(jīng)定型,所以最適合的方法是 expires 來緩存一些內(nèi)容到訪問者瀏覽器。
案例3:
通過 chrome 訪問服務(wù)器端的一張圖片,用F12鍵打開開發(fā)者前端調(diào)試工具:

第一次訪問,響應(yīng)200狀態(tài),當(dāng)?shù)诙渭昂罄m(xù)訪問的時候,變成304狀態(tài),客戶端已經(jīng)開始獲取瀏覽器緩存內(nèi)容,而不需要去服務(wù)器端獲取對應(yīng)的請求內(nèi)容,即 nginx 中 expires 參數(shù)設(shè)置已經(jīng)生效。等待客戶端緩存時間過期后,會再次請求服務(wù)器端內(nèi)容來更新本地緩存。

介紹到這里,突然想起一個有意思的需求。比如,訪問一張靜態(tài)文件,不想客戶端緩存,需要每次都去服務(wù)器端取數(shù)據(jù)。我們可以用“ last-modified ”參數(shù)來實現(xiàn),即“ last-modified ”是根據(jù)文件更新時間來確定是否再次發(fā)送加載。
Nginx核心配置如下:

我們更改掉服務(wù)器傳回客戶端的“ last-modified ”文件修改時間參數(shù)的值,這樣導(dǎo)致客戶端本地保存的文件時間每次跟服務(wù)器端傳回來的時間不一致,所以每次客戶端“ 誤認(rèn)為 ”服務(wù)器端有靜態(tài)文件更新,每次都會去服務(wù)器端取“ 所謂的最新數(shù)據(jù) ”。這樣我們可以看到,不管在瀏覽器訪問多少次,返回的 http 狀態(tài)都是200,再也找不到304狀態(tài)了。
誤區(qū):在 nginx 中設(shè)置 expires,并不是指把靜態(tài)內(nèi)容緩存在 nginx 中,而是設(shè)置客戶端瀏覽器緩存的時間,這是很多人的誤區(qū)所在。
二、磁盤緩存
除了存儲在客戶端的靜態(tài)緩存(瀏覽器靜態(tài))技術(shù)外,在服務(wù)器端的靜態(tài)緩存技術(shù)主要分為磁盤緩存和內(nèi)存緩存兩大類。單純圍繞 nginx 的 squid、varnish 等一類中間件,處理靜態(tài)數(shù)據(jù)的性能十分優(yōu)秀。核心是 nginx 基于 epoll 網(wǎng)絡(luò)模型,而相比 apache 基于 select 網(wǎng)絡(luò)模型。所以 apache 的優(yōu)勢在于密計算型,穩(wěn)定性好。而 nginx 偏向靜態(tài)處理,反向代理,高并發(fā)。比如 apache+php 的穩(wěn)定性比 nginx+php 要好,而性能是明顯 nginx 要優(yōu)秀許多。
以上僅單純是對磁盤中靜態(tài)數(shù)據(jù)處理的能力,所謂磁盤緩存,指另外的一種緩存靜態(tài)文件的技術(shù)。以 nginx 配置為例:

可以看出 nginx 主要通過 proxy_cache 來實現(xiàn) web cache,熟悉 nginx 的同學(xué),不難看出,以上配置在 location 這里,不僅可以實現(xiàn)靜態(tài)文件的緩存,還可以實現(xiàn)動態(tài)文件的緩存(這里放在下章節(jié)詳細(xì)介紹)。我們編寫個 test.html測試文件,然后并訪問。test.html 源碼如下:

我們發(fā)現(xiàn)服務(wù)器的 cache 目錄里面,多了兩個緩存文件:

有意思的,這兩個文件里面的內(nèi)容分別為(通過 less 命令查看):

(b0ad5d3e7f099bfff9e4fc6a159d868c)

(53edc39ed253e14415a29412cfc01faf)
所以不難看出,nginx 把 html 內(nèi)容和圖片二進制全部緩存到本地磁盤上了。下次用戶再次來訪問 test.html 的時候,nginx 直接將緩存在本地磁盤的文件返回給用戶。特別是后端如若是部署的 tomcat、iis 等,nginx 強大的靜態(tài)緩存能力,有效減少了服務(wù)器壓力。
三、內(nèi)存緩存
緊接上面描述的磁盤緩存,內(nèi)存緩存顧名思義,就是把靜態(tài)文件緩存在服務(wù)器端的內(nèi)存中。所以這種緩存,如若命中緩存的話,取內(nèi)存中的緩存數(shù)據(jù)返回比取磁盤中的緩存數(shù)據(jù)返回,性能要高很多。以 varnish 為例,varnish 核心配置如下:
啟動命令:

參數(shù)簡介:

default.vcl核心配置如下:

Varnish對.gif、.jpg、.jpeg、.png等結(jié)尾的 URL 緩存時間設(shè)置1小時。varnish設(shè)置完畢后,我們用命令行方式,通過查看網(wǎng)頁頭來查看命中情況:


最后,我們可以通過 varnishadm 命令來清理緩存,也可以通過 varnishstat 命令來查看 varnish 系統(tǒng)緩存狀態(tài)。
四、Nginx 的內(nèi)存緩存
以上主要以 Varnish 為例,介紹了內(nèi)存緩存靜態(tài)資源的方法。其實 nginx 也有內(nèi)存緩存,相比 squid、varnish 而言,nginx 的內(nèi)存緩存需要通過編碼實現(xiàn)。如下配置:

memcached_pass 指定服務(wù)器地址,使用變量 $memcache_key 為 key 查詢值,去 memcache 查詢對應(yīng) value 值。
如我們訪問:http://***.***.***.***/image/test.jpg ,則 nginx 去 memcache 中查詢key 為“ test.jpg ”的 value 值并返回。如果沒有相應(yīng)的值,則返回 error_page 404。介紹到這里,關(guān)鍵在于存儲在 memcache 中的靜態(tài)文件,需要通過代碼寫入 memcache 中。怎么樣通過 php/java 等代碼把靜態(tài)資源的數(shù)據(jù)寫入 memcache 中,關(guān)于這塊的示例就不再過多介紹了。
Nginx的內(nèi)存緩存因為需要通過編碼實現(xiàn),所以靈活性特別高。這塊可以結(jié)合自身業(yè)務(wù)系統(tǒng)的特點,讓靜態(tài)緩存的靈活性和效率都能得到保障。可能唯一的缺陷就是,通過編碼實現(xiàn)的方式,給我們維護管理帶來了負(fù)擔(dān)。在之前我曾參與的一個電商系統(tǒng),就是把客戶的訂單照片通過 php 代碼寫入 memcache,客戶訪問取圖的時候,從 memcache 中獲取,速度效率特別高。Nginx 作為一款在七層無所不能且輕量級高性能的中間件,能夠直接去 memcache 中取數(shù)據(jù),來實現(xiàn)靜態(tài)緩存的效果,這塊相應(yīng)的功能是其他軟件無法相媲美的。
五、CDN
說起 CDN,大家都不陌生,它是靜態(tài)緩存加速最典型的代表。CDN技術(shù)并不是一門新的技術(shù),它是基于傳統(tǒng) nginx、squid、varnish 等 web 緩存技術(shù),結(jié)合 DNS 智能解析的靜態(tài)緩存加速技術(shù)。值得注意的是,他對動態(tài)鏈接訪問并沒有加速效果。架構(gòu)原理圖如下:

所以CDN的靜態(tài)緩存技術(shù)核心主要在于兩點:
節(jié)點緩存:對需要加速的網(wǎng)站應(yīng)用,相應(yīng)的靜態(tài)資源通過內(nèi)存緩存+磁盤緩存的方式緩存在服務(wù)器端。
精準(zhǔn)調(diào)度:對訪問的用戶 ip 進行智能解析調(diào)度,實現(xiàn)就近緩存節(jié)點訪問。比如以上圖例中,北京用戶訪問 www.a.com。通過 dns 解析的時候,分析用戶 ip,發(fā)現(xiàn)是北京用戶。則 dns 返回對應(yīng)北京緩存節(jié)點的 ip 地址給到用戶,則用戶 www.a.com 默認(rèn)訪問北京服務(wù)器上面的緩存數(shù)據(jù),實現(xiàn)就近訪問的策略,大大提升了訪問速度。
杜絕抄襲,支持開源,我為自己吶喊,百分百原創(chuàng)作者:喬銳杰
好啦~本文到這里就結(jié)束了,同時,如果喜歡我們的話就趕緊訂閱我們吧~~~每天定時推送新鮮干貨~~~也可以關(guān)注我們的微信公眾號:架構(gòu)云專家頻道 每天同步更新喲~~~
您也可以關(guān)注我們的官方微信公眾號(ID:ctoutiao),給您更多好看的內(nèi)容。