老曹眼中的緩存技術(shù)
緩存是系統(tǒng)快速響應(yīng)中的一種關(guān)鍵技術(shù),是一組被保存起來以備將來使用的東西,介于應(yīng)用開發(fā)和系統(tǒng)開發(fā)之間,是產(chǎn)品經(jīng)理們經(jīng)常顧及不到的地方,算是技術(shù)架構(gòu)中的非功能性約束吧。
也就是說,緩存是系統(tǒng)調(diào)優(yōu)時(shí)常用且行之有效的手段,無論從操作系統(tǒng)還是應(yīng)用系統(tǒng),緩存策略無處不在。
很多技術(shù)都打著緩存的旗號,所以談起緩存往往似是而非,與語境有著緊密的關(guān)系,換個(gè)說法,來看一看緩存在不同場景的分類。
客戶端緩存
瀏覽器的緩存可以將之前渲染的頁面保存為文件,當(dāng)用戶再次訪問時(shí)可用避開網(wǎng)絡(luò)連接,從而減少負(fù)載。現(xiàn)在的HTML5支持了本地存儲(chǔ),大部分BS 應(yīng)用都可以舉重若輕了。
如何把客戶端緩存對于業(yè)務(wù)組件透明和客戶端緩存數(shù)據(jù)及時(shí)更新,是客戶端緩存能否成功應(yīng)用的關(guān)鍵。
客戶端可以將內(nèi)容緩存在內(nèi)存,文件,或本地?cái)?shù)據(jù)庫(例如Sqlite)中。
例如,iOS 的圖片緩存框架SDWeb架構(gòu)如下:
web代理
web 代理的作用跟瀏覽器的內(nèi)置緩存類似,只是位于瀏覽器和互聯(lián)網(wǎng)之間,網(wǎng)絡(luò)請求通過代理來中繼。對于企業(yè)而言,即可以節(jié)省成本,又能提高性能。
對于Web代理而言,曾經(jīng)流行的是Squid,它支持建立復(fù)雜緩存層級結(jié)構(gòu)的能力,詳細(xì)的日志、高性能緩存以及用戶認(rèn)證支持。Squid同時(shí)支持各種插件,例如Squid Guard就是一個(gè)提供URL過濾的插件,對于屏蔽某些站點(diǎn)和內(nèi)容十分有用。如果想分析Squid的各種指標(biāo),webalizer 應(yīng)該是個(gè)不錯(cuò)的選擇。
Squid 的內(nèi)部機(jī)制如下:
邊緣緩存
邊緣緩存位于應(yīng)用服務(wù)器的前面,可以處理來自不同用戶的請求,主要用于向用戶提供靜態(tài)的內(nèi)容,以減少應(yīng)用服務(wù)器的介入。邊緣緩存的商業(yè)化服務(wù)就是CDN了,例如AWS 的Cloud Front,我國的ChinaCache等。
邊緣緩存的一個(gè)有名的開源工具就是varnish,在默認(rèn)情況下進(jìn)行保守緩存。也就是說,varnish 只緩存它所知的安全內(nèi)容。varnish的一個(gè)特性是使用虛擬內(nèi)存,精妙之處在于利用了操作系統(tǒng)的管理機(jī)制。varnish可以高度定制如何處理請求,緩存哪些內(nèi)容。
Varnish 的內(nèi)部機(jī)制如下:
平臺(tái)緩存
平臺(tái)緩存是用來寫應(yīng)用的框架,或者緩存的專用庫(如PHP中的Smarty模版庫)。
Java 語言中,緩存框架更多,例如EHcache,Cacheonix,Voldemort,JBoss Cache等等。
看一下EHcache的系統(tǒng)結(jié)構(gòu)結(jié)構(gòu):
Ehcache是一個(gè)Java實(shí)現(xiàn)的開源分布式緩存框架,可以讓數(shù)據(jù)保存在不同服務(wù)器的內(nèi)存中,在需要數(shù)據(jù)的時(shí)候可以快速存取。通過聲明配置、在xml中配置、在程序里配置或者調(diào)用構(gòu)造方法時(shí)傳入不同的參數(shù)。
Voldemort是一款基于Java開發(fā)的分布式鍵-值緩存系統(tǒng),像JBoss Cache一樣,Voldemort同樣支持多臺(tái)服務(wù)器之間的緩存同步,以增強(qiáng)系統(tǒng)的可靠性和讀取性能。
簡單來說,就平臺(tái)級緩存而言,只需要在框架側(cè)配置一下屬性即可,而不需要調(diào)用特定的方法或函數(shù)。
應(yīng)用緩存
應(yīng)用級緩存,需要自己通過代碼來實(shí)現(xiàn)緩存。這里是NoSQL的勝場,不論是Redis 還是MongoDB,都可以作為應(yīng)用緩存的工具。一個(gè)典型的方式是,每分鐘或一段時(shí)間后統(tǒng)一生成某類頁面存儲(chǔ)在緩存中,也可以在熱數(shù)據(jù)變化時(shí)更新緩存。
Redis 在應(yīng)用級緩存中的作用舉足輕重,新浪微博有著幾乎世界上最大的redis 集群。 Redis支持主從同步。數(shù)據(jù)可以從主服務(wù)器向任意數(shù)量的從服務(wù)器上同步,從服務(wù)器可以是關(guān)聯(lián)其他從服務(wù)器的主服務(wù)器。這使得Redis可執(zhí)行單層樹復(fù)制。存盤可以有意無意的對數(shù)據(jù)進(jìn)行寫操作。由于完全實(shí)現(xiàn)了發(fā)布/訂閱機(jī)制,使得從數(shù)據(jù)庫在任何地方同步樹時(shí),可訂閱一個(gè)頻道并接收主服務(wù)器完整的消息發(fā)布記錄。同步對讀取操作的可擴(kuò)展性和數(shù)據(jù)冗余很有幫助。
Redis 的客戶端編程語言眾多,可以滿足絕大多數(shù)的應(yīng)用。
數(shù)據(jù)庫緩存
數(shù)據(jù)庫緩存是一類特殊的緩存。大多數(shù)數(shù)據(jù)庫不需要配置就可以快速運(yùn)行,但并沒有為特定的需求進(jìn)行優(yōu)化。在數(shù)據(jù)庫調(diào)優(yōu)的時(shí)候,緩存優(yōu)化是一項(xiàng)很重要的工作。
以MySQL為例,MySQL中使用了查詢緩沖機(jī)制,將SELECT語句和查詢結(jié)果存放在緩沖區(qū)中,以后對于同樣的SELECT語句,將直接從緩沖區(qū)中讀取結(jié)果,以節(jié)省查詢時(shí)間,提高了SQL查詢的效率。
通過調(diào)節(jié)以下幾個(gè)參數(shù)可以知道query_cache_size設(shè)置得是否合理:
- Qcache inserts
- Qcache hits
- Qcache lowmem prunes
- Qcache free blocks
- Qcache total blocks
當(dāng)然,深入數(shù)據(jù)庫還有很多值得學(xué)習(xí)的地方。
緩存的協(xié)議支持
對web應(yīng)用而言,http1.0 提供了一些很基本的緩存特性,例如在服務(wù)器側(cè)設(shè)置Expires 的http頭來告訴客戶端在重新請求文件之前緩存多久是安全的,可以通過if-modified-since 的條件請求來使用緩存。其中,發(fā)送的時(shí)間是文件最初被下載的時(shí)間,而不是即將過期的時(shí)間,如果文件沒有改變,服務(wù)器可以用304-Not Modified 來應(yīng)答??蛻舳耸盏?04代碼,就可以使用緩存的文件版本了。客戶端可以設(shè)置Pragma:no-cache從服務(wù)器之間獲取內(nèi)容。
Http 1.1有了較大的增強(qiáng),緩存系統(tǒng)被形式化了,引入了實(shí)體標(biāo)簽e-tags,是文件或?qū)ο蟮奈ㄒ粯?biāo)識(shí)。這意味著可以請求一個(gè)資源、提供所持有的文件,然后詢問服務(wù)器這個(gè)文件是否有變化。如果某一個(gè)文件的e-tag 是有效的,服務(wù)器會(huì)生成304-Not Modified 應(yīng)答,并提供正確文件的e-tag,否則,發(fā)送200-OK應(yīng)答。以瀏覽器為例的示意圖如下:
關(guān)于HTTP2.0中有關(guān)緩存的技術(shù),還有待研究。
總而言之,緩存——cache,是一種挺復(fù)雜的技術(shù),除了應(yīng)用場景之外,更進(jìn)一步,還要理解命中,Cache Miss,存儲(chǔ)成本,索引成本,失效,替代策略等諸多概念,進(jìn)而了解緩存算法,分布式緩存及其同步,多級緩存的設(shè)計(jì)......真正的掌握緩存技術(shù)。
【本文來自51CTO專欄作者老曹的原創(chuàng)文章,作者微信公眾號:喔家ArchiSelf,id:wrieless-com】