如果這是第二次看到我的文章,歡迎文末掃碼訂閱我個人的公衆号(跨界架構師)喲~
每周五11:45 按時送達。當然了,也會時不時加個餐~
本文長度為3578字,建議閱讀10分鐘。
堅持原創,每一篇都是用心之作~
此前的「伸縮性」章節結束了,此文是「高性能」章節的第一篇。
隻要是位正兒八經的程式員自然知道「緩存」是什麼,甚至我司的很多做營運的小姐姐現在和程式員小哥哥的交流中都時不時冒出「緩存」字眼,讓人壓力山大
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIuVzRjVXSU1kZKpHT0Q2MYBHcyIGdWJDTzZVbihmQzgVd5cVYwkzVixWOpJmdxclY25kMMVXOykFc5k3YsR2VZRHbywUd5cVYww2RaxGeXJGMoJDT6ZVbjdXMywEd5ITW1VEWjV3ZzQWdNhlW5lTeMZTTINGMShUYvwlbj5yZtlmbkN3YuQnclZnbvN2Ztl2Lc9CX6MHc0RHaiojIsJye.jpg)
。(本文讨論的「緩存」皆指的是軟體層面運用的緩存)
大家都知道的一點是,緩存可以讓原本打開很慢的頁面,變得能“秒開”。你平時通路的APP、網站幾乎都有涉及到緩存的運用。
那麼,緩存除了能加速資料的通路之外,還有什麼作用呢?
另外,任何事物都有兩面性,我們如何才能将緩存的優點發揮得淋淋盡緻,同時避免掉到它的弊端中呢?
Z哥今天想分享給你的就是我對緩存的了解和運用的思路,希望對你有所啟發。
「緩存」能做什麼?
正如前面所說,大家最普遍的了解就是當我們遇到某個頁面打開很慢的時候,會想到引入緩存,這樣頁面打開就快了。
其實快和慢都是相對的,從技術角度來說,緩存之是以快是因為緩存是基于記憶體去建立的,而記憶體的讀寫速度比硬碟快X倍,是以用記憶體來代替硬碟作為讀寫的媒體自然能大大提高通路資料的速度。
這個過程大緻是這樣的,通過在記憶體中存儲訪被問過的資料供後續通路時使用,以此來達到提速的效果。
其實除此之外,緩存還有另外2個重要的運用方式,「預讀取」和「延遲寫」。
預讀取
預讀取就是預先讀取将要載入的資料,也可以稱作「緩存預熱」。就是在系統對外提供服務之前,先将硬碟中的一部分資料加載到記憶體中,然後再對外提供服務。
為什麼要這樣做呢?因為有些系統一旦啟動就要面臨上千上萬的請求進來(在一些toC的項目尤其如此),如果直接讓這些請求打到資料庫上,非常大的可能是資料庫壓力暴增,直接被幹趴,無法正常響應。
為了緩解這個問題,需要通過「預讀取」來解決。
可能你會問,哪怕用了緩存還是扛不住呢?那就是做橫向擴充+負載均衡的時候到了。(可以點選文末連結閱讀之前的《彈性架構》系列
)
如果說「預讀取」是在「資料出口」加了一道前置的緩沖區的話,那麼顧名思義,下面要說的「延遲寫」就是在「資料入口」後面加了一道後置的緩沖區。
延遲寫
你可能知道,資料庫的寫入速度是慢于讀取速度的,因為寫入的時候有一系列的保證資料準确性的機制。
是以,如果想提升寫入速度的話,要麼做分庫分表,要麼就是通過緩存來進行一道緩沖,再一次性批量寫到磁盤,以此來提速。
題外話:由于分庫分表對跨表操作以及多條件組合查詢的副作用巨大,是以引入它的複雜度遠大于引入緩存,我們應當優先考慮引入緩存的方案。
那麼,通過緩存機制來加速“寫”的過程就可以稱作「延遲寫」。就是預先将需要寫入到磁盤或者資料庫的資料,先暫時寫入到記憶體,然後就傳回成功。再定時将記憶體中的資料批量寫入到磁盤。
可能你會想,寫到記憶體就認為成功,萬一中途出現意外、斷電、停機等導緻程式異常終止的情況,資料不就丢了嗎?
是的。是以,「延遲寫」一般僅用于對資料完整性要求不是那麼苛刻的場景。比如點贊數啊、參與使用者數啊等等,可以大大緩解對資料庫頻繁修改所帶來的壓力。
其實在我們熟知的分布式緩存Redis中,其預設運用的持久化機制——RDB,也是這樣的思路。
在一個成熟的系統中,能夠運用到緩存的地方其實并不是一處。下面Z哥就來幫你梳理一下我們在哪些地方可以“加緩存”。
哪裡可以加「緩存」?
在說哪裡可以加緩存之前我們先搞清楚一個事情,我們要緩存什麼?也就是符合什麼特點的資料才需要加緩存?畢竟加緩存是一個額外的成本投入,得物有所值。
一般來說你可以用這兩個标準來判斷:熱點(被高頻通路,如幾十次/秒以上)資料、靜态(很少變化,讀遠大于寫,如幾天變更一次)資料。
接下去就可以替它們找到合适的地方加緩存了。
緩存的本質是一個“防禦性”的機制,而系統之間的資料流轉是一個有序的過程。是以,選擇在哪裡加緩存就相當于選擇在一條馬路的哪個位置設路障。在這個路障之後的道路都能受到保護,不被車流碾壓。
那麼在以終端使用者為起點,系統所用的資料庫為終點的這條道路上可以作為緩存設立點的位置大緻有以下這些。
每個設立點可以擋掉一些流量,最終形成一個漏鬥狀的攔截效果,以此保護最後面的系統以及最終的資料庫。
下面Z哥來簡要描述下每一個的運用場景以及需要注意的點。
浏覽器緩存
這是離使用者最近的可以作為緩存的地方,而且借助的是使用者的“資源”(緩存的資料在使用者的終端裝置上),成本效益可謂最好,讓使用者幫你分擔壓力
。
當你打開浏覽器的開發者工具,看到from cache或者from memory cache、from disk cache的時候,就意味着這些資料已經被緩存在了使用者的終端裝置上了(沒網的時候也能通路到一部分内容就是這個原因)。
這個過程是浏覽器替我們完成的,一般用于緩存圖檔、js、css這些。我們可以通過Http消息頭中的Cache-Control來控制它,具體細節這裡就不展開了。
js裡的全局變量、以及cookie等運用也屬于該範疇。
浏覽器緩存是在于使用者側的緩存點,是以我們對其的掌控力就差很多,在沒有發起新請求的情況下,你無法主動去更新資料。
CDN緩存
提供CDN服務的服務商,在全國甚至是全球部署着大量的伺服器節點(可以叫做「邊緣伺服器」)。
那麼将資料分發到這些遍布各地伺服器上作為緩存,讓使用者通路就近的伺服器上的緩存資料,就可以起到壓力分攤和加速效果。這在ToC類型的系統上運用,效果格外顯著。
但是需要注意的是,由于節點衆多,更新緩存資料比較緩慢,一般至少是分鐘級别。是以一般僅适用于不經常變動的靜态資料。
題外話:解決方式也是有的,就是在url後面帶個自增數或者唯一标示,如?v=1001。因為不同的url會被視作“新”的資料和檔案,被重新create出來。
網關(代理)緩存
到這裡做緩存就是在你自己的地盤了。很多時候我們會在源站前面架一層網關(或者說反向代理、正向代理),為的是做一些安全機制或者統一分流政策的入口。
同時這裡也是做緩存的一個好場所。畢竟網關是“業務無關性”的,它能夠攔下來的請求,對背後的源站也是很大的受益,減少了大量的CPU運算。
常用的網關(代理)緩存有Varnish,Squid,Ngnix。一般情況下,簡單的緩存運用場景,用nginx即可,因為大部分時候我們會用它來做負載均衡,能少引入一個技術就少一份複雜度嘛。如果是大量的小檔案可以使用Varnish,而Squid則相對大而全,運用成本也更高一些。
程序内緩存
一個請求能走到這裡說明他是“業務相關”的,需要經過業務邏輯的運算。
也正因為如此,從這裡開始對緩存的引入成本比前面3種大大增加,因為對緩存與資料庫之間的「資料一緻性」要求更高了。
可能我們大多數程式員第一次刻意使用緩存的場景就是這個時候
。程序内和程序外的緩存運用中有很多的細節需要注意,這些也是我們後續文章的内容,是以我們後續再詳聊。
程序外緩存
這個大家也熟悉,就是redis、memcached之類,甚至也可以自己單獨寫一個程式來專門存放緩存資料,供其他程式遠端調用。
同樣,這裡的細節我們後續再聊,這裡先多說幾句關于redis和memcached該怎麼選擇的建議。
對資源(cpu、記憶體等)使用率格外重視的話可以使用Memcached,但程式在使用的時候需要容忍可能發生的資料丢失,因為是純記憶體的機制。如果無法容忍這點,并且對資源使用率也比較豪放的話可以使用redis。而且redis的資料庫結構更多,Memcached隻有key value,更像是一個nosql存儲。
資料庫緩存
資料庫本身自帶緩存子產品的,否則也不會叫它記憶體殺手,基本上你給多少記憶體就能吃多少。
資料庫緩存是資料庫的内部機制,我們這裡就不深入下去了。一般都會給出設定緩存空間大小的配置來讓你進行幹預。
最後,其實磁盤本身也有緩存。是以你會發現,為了讓資料能夠平穩的寫到實體磁盤中真的是一波三折,不知道什麼時候可以有“快”到不需要程式來考慮緩存的磁盤出現來拯救我們程式員呢
。
「緩存」是Silver bullet嗎?
可能你會想緩存那麼好,那麼應該多多益善,隻要慢就上緩存來解決?
一個事物看上去再好,也有它負面的一面。緩存也有一系列的副作用需要考慮。除了上面提到的「緩存更新」和「緩存與資料的一緻性」問題,還有諸如:
- 緩存雪崩
- 緩存穿透
- 緩存并發
- 緩存無底洞
- 緩存淘汰
- ...
等等問題,這些Z哥會在接下去的文章中和你一起深入剖析。
想第一時間了解這些的可以「關注」Z哥一波~
總結
好了,我們總結一下。
這次呢,Z哥先向你介紹了運用緩存的三種思路。
然後梳理了在一個完整的系統中可以設立緩存的幾個位置,并且分享了關于浏覽器緩存、CDN緩存、網關(代理)緩存的一些使用經驗。
希望對你有所啟發。
後續的文章我将着重深入「程序内緩存」和「程序外緩存」的最佳實踐,等我再次出現
。
相關文章:
- 分布式系統關注點——僅需這一篇,吃透「負載均衡」妥妥的
- 分布式系統關注點——如何去實施「負載均衡」?
- 分布式系統關注點——做了「負載均衡」就可以随便加機器了嗎?
- 分布式系統關注點——「無狀态」詳解
- 分布式系統關注點——「高内聚低耦合」詳解
- 分布式系統關注點——彈性架構
作者:Zachary
出處:https://www.cnblogs.com/Zachary-Fan/p/cache.html
如果你喜歡這篇文章,可以點一下右側的「大拇指」。
這樣可以給我一點回報。: )
謝謝你的舉手之勞。
▶關于作者:張帆(Zachary,個人微信号:Zachary-ZF)。堅持用心打磨每一篇高品質原創。歡迎掃描下方的二維碼~。
定期發表原創内容:架構設計丨分布式系統丨産品丨營運丨一些思考。
如果你是初級程式員,想提升但不知道如何下手。又或者做程式員多年,陷入了一些瓶頸想拓寬一下視野。歡迎關注我的公衆号「跨界架構師」,回複「技術」,送你一份我長期收集和整理的思維導圖。
如果你是營運,面對不斷變化的市場束手無策。又或者想了解主流的營運政策,以豐富自己的“倉庫”。歡迎關注我的公衆号「跨界架構師」,回複「營運」,送你一份我長期收集和整理的思維導圖。