首頁體育 > 正文

快取有那麼多種,分別是幹什麼的?

2021-10-20由 國民看新聞 發表于 體育

只要是位正兒八經的程式設計師應該都知道“快取”是什麼,甚至我司的很多做運營的小姐姐現在和程式設計師小哥哥交流中都時不時冒出“快取”這個詞,讓人壓力山大。

當然,這裡討論的是指軟體層面的快取。大家都知道的一點是,快取可以讓原本開啟很慢的頁面,變得能“秒開”。你平時訪問的 APP 與網站幾乎都有涉及到快取的運用。

那麼,快取除了能加速資料的訪問之外,還有什麼作用呢?

另外,任何事物都有兩面性,我們如何才能將快取的優點發揮得淋淋盡致,同時避免掉到它的弊端中呢?

本文接下來就給大家分享一下如何理解快取,以及它的運用思路,希望對你有所啟發。

快取能做什麼?

正如前面所說,大家最普遍的理解就是當我們遇到某個頁面開啟很慢的時候,會想到引入快取,這樣頁面開啟就快了。

其實快和慢都是相對的,從技術角度來說,快取之所以快是因為快取是基於記憶體去建立的,而記憶體的讀寫速度比硬碟快 X 倍,所以用記憶體來代替硬碟作為讀寫的介質自然能大大提高訪問資料的速度。

這個過程大致是這樣的,透過

在記憶體中儲存被訪問過的資料供後續訪問時使用,以此來達到提速的效果

快取有那麼多種,分別是幹什麼的?

開啟搜狗搜尋APP,檢視更多精彩資訊

其實除此之外,快取還有另外 2 個重要的運用方式:

預讀取

延遲寫

預讀取

預讀取就是預先讀取將要載入的資料,也可以稱作“快取預熱”,它是

在系統中先將硬碟中的一部分資料載入到記憶體中,然後再對外提供服務

快取有那麼多種,分別是幹什麼的?

為什麼要這樣做呢?因為有些系統一旦啟動就要面臨上千上萬的請求進來(在一些 toC 的專案尤其如此),如果直接讓這些請求打到資料庫上,非常大的可能是資料庫壓力暴增,直接被幹趴,無法正常響應。

為了緩解這個問題,就需要透過“預讀取”來解決。

可能你會問,哪怕用了快取還是扛不住呢?那就是做橫向擴充套件+負載均衡的時候到了,這不是本文討論的內容,有機會再專門分享吧。

如果說“預讀取”是在“資料出口”加了一道前置的緩衝區的話,那麼下面要說的“延遲寫”就是在“資料入口”後面加了一道後置的緩衝區。

延遲寫

你可能知道,資料庫的寫入速度是慢於讀取速度的,因為寫入的時候有一系列的保證資料準確性的機制。

所以,如果想提升寫入速度的話,要麼做分庫分表,要麼就是透過快取來進行一道緩衝,再一次性批次寫到磁碟,以此來提速。

題外話:由於分庫分表對跨表操作以及多條件組合查詢的副作用巨大,所以引入它的複雜度遠大於引入快取,我們應當

優先考慮引入快取的方案

那麼,透過快取機制來加速“寫”的過程就可以稱作“延遲寫”,它是

預先將需要寫入到磁碟或者資料庫的資料,暫時寫入到記憶體,然後就返回成功,再定時將記憶體中的資料批次寫入到磁碟

快取有那麼多種,分別是幹什麼的?

可能你會想,寫到記憶體就認為成功,萬一中途出現意外、斷電、停機等導致程式異常終止的情況,資料不就丟了嗎?

是的。所以“

延遲寫”一般僅用於對資料完整性要求不是那麼苛刻的場景,

比如點贊數啊、參與使用者數啊等等,可以大大緩解對資料庫頻繁修改所帶來的壓力。

其實在我們熟知的分散式快取 Redis 中,其預設運用的持久化機制——RDB,也是這樣的思路。

在一個成熟的系統中,能夠運用到快取的地方其實並不是一處。下面就來梳理一下我們在哪些地方可以“加快取”。

哪裡可以加快取?

在說哪裡可以加快取之前我們先搞清楚一個事情,我們要快取什麼?也就是符合什麼特點的資料才需要加快取?畢竟加快取是一個額外的成本投入,得物有所值。

一般來說你可以用這兩個標準來判斷:

熱點資料:

被高頻訪問,如幾十次/秒以上

靜態資料:

很少變化,讀遠大於寫,如幾天變更一次

接下去就可以替它們找到合適的地方加快取了。

快取的本質是一個“防禦性”的機制,而系統之間的資料流轉是一個有序的過程,所以,

選擇在哪裡加快取就相當於選擇在一條馬路的哪個位置設路障

。在這個路障之後的道路都能受到保護,不被車流碾壓。

那麼在以終端使用者為起點,系統所用的資料庫為終點的這條道路上可以作為快取設立點的位置大致有以下這些:

快取有那麼多種,分別是幹什麼的?

每個設立點可以擋掉一些流量,最終形成一個漏斗狀的攔截效果,以此保護最後面的系統以及最終的資料庫。

快取有那麼多種,分別是幹什麼的?

下面簡要描述一下每個運用場景以及需要注意的點。

瀏覽器快取

這是離使用者最近的可以作為快取的地方,而且藉助的是使用者的“資源”(快取的資料在使用者的終端裝置上),價效比可謂最好,讓使用者幫你分擔壓力。

快取有那麼多種,分別是幹什麼的?

當你開啟瀏覽器的開發者工具,看到 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 儲存。

資料庫快取

資料庫本身是自帶快取模組的,否則也不會叫它記憶體殺手,基本上你給多少記憶體就能吃多少。資料庫快取是資料庫的內部機制,一般都會給出設定快取空間大小的配置來讓你進行干預。

最後,其實磁碟本身也有快取。所以你會發現,為了讓資料能夠平穩地寫到物理磁碟中真的是一波三折,不知道什麼時候可以有“快”到不需要程式來考慮快取的磁碟出現來拯救我們程式設計師呢。

快取是銀彈嗎?

可能你會想快取那麼好,那麼應該多多益善,只要慢就上快取來解決?

一個事物看上去再好,也有它負面的一面,快取也有一系列的副作用需要考慮。除了前面提到的“快取更新”和“快取與資料的一致性”問題,還有諸如下邊的這些問題:

快取雪崩

。在大量的請求併發進入時,由於某些原因未起到預期的緩衝效果,哪怕只是很短的一段時間,導致請求全部流轉到資料庫,造成資料庫壓力過重。解決它可以透過“加鎖排隊”或者“快取時間增加隨機值”。

快取穿透

。和“快取雪崩”比較類似,區別是這會持續更長的時間,因為每次“cache miss”後依然無法從資料來源載入資料到快取,導致持續產生“cache miss”。解決它可以透過“布隆過濾器”或者“快取空物件”。

快取併發

。一個快取 Key 下的資料被同時 set,怎麼保證業務的準確性?再加上資料庫的話呢?程序內快取、程序外快取與資料庫三者皆用的情況下呢?用一句話來概括建議的方案是:使用“先 DB 再快取”的方式,並且快取操作用 delete 而不是 set。

快取無底洞

。雖然分散式快取是可以無限橫向擴充套件的,但是,叢集下的節點真的是越多越好嗎?當然不是,快取也是符合“邊際效應遞減”規律的。

快取淘汰

。記憶體總是有限的,如果資料量很大,那麼根據具體的場景定製合理的淘汰策略是必不可少的,如 LRU、LFU 與 FIFO 等等。

所以快取不是銀彈,對快取的使用也需要先考慮各種問題。總結一下,本文先向你介紹了運用快取的三種思路,然後梳理了在一個完整的系統中可以設立快取的幾個位置,並且分享了關於瀏覽器、CDN 與閘道器(代理)等快取的一些使用經驗,沒有具體展開來講細節,只是希望你對快取有一個更加體系化的認識,希望能讓你看得更加全面。

作者介紹

張帆(Zachary),7 年電商行業經驗,5 年開發團隊管理經驗,4 年網際網路架構經驗,目前任職某垂直電商技術總監。專注大型系統架構與分散式系統,堅持用心打磨每一篇原創。個人公眾號:跨界架構師(ID:Zachary_ZF)。

送書

讀完文章先別走,歡迎大家就文章相關內容進行討論與轉發

,我們後續會從評論區抽取

4 名評論優質的讀者

贈送《架構修煉之道——億級閘道器、平臺開放、分散式、微服務、容錯等核心技術修煉實踐》一書。感謝 @博文視點 提供的獎品。

快取有那麼多種,分別是幹什麼的?

簡介:

《架構修煉之道——億級閘道器、平臺開放、分散式、微服務、容錯等核心技術修煉實踐》結合實際的生產實踐,分別對閘道器、平臺開放、分散式、MQ、RPC、I/O、微服務、容錯的內容做了詳細介紹。其中的內容不限於概念,而是會下沉到實踐背後的感悟與總結。

參與討論:「連結」

頂部