使用快取(Cache)的幾種方式,回顧一下~~~

Code綜藝圈發表於2022-03-31

前言

如今快取成為了優化網站效能的首要利器,快取使用的好,不僅能讓網站效能提升,讓使用者體驗變好,而且還能節約成本(增加一臺快取伺服器可能就節約好幾臺機器);那平時小夥伴們都使用哪些快取方式呢?這裡就來和小夥伴們一起來回顧一下。

正文

快取的作用其實很明確,如下兩方面:

  • 提升資料的獲取速度

    通常用在獲取資料速度要求比較高的場景,比如一些和裝置通訊的軟體,對時間的要求比較高,如果每次都從資料庫讀資料會導致消耗多餘的時間。

  • 減輕後臺應用或資料庫伺服器的負載

    對於高併發場景的系統,如果每次請求都打到資料庫,資料庫伺服器負載會變大,到達一定瓶頸之後可能讓系統體驗變差或不可用。

1. 瀏覽器快取

1.1 簡述

通過控制響應頭資訊,告訴瀏覽器讓其將對應的資料快取到本地,在指定時間範圍內,可直接從本地快取中取即可,但瀏覽器方可以不選擇走快取。

1.2 案例演示

本文中還是使用WebAPI專案進行演示,只是通過不同的API來區分不同案例。

建立好專案中,在預設的WeatherForecastController中新增一個Action方法,如下:

這個時候還沒有做快取處理,所以只要訪問都會呼叫介面獲取最新的資料。

在介面方法上只需新增ResponseCache特性就可以實現瀏覽器快取,如下:

這樣就可以實現客戶端快取了,可能會有小夥伴會點選瀏覽器的重新整理和F5進行測試,這個時候並沒有看到快取效果,其實這個時候瀏覽器是以新的請求發出的,並不會去快取裡取,但其實請求獲取到的資料已經存快取了。

那怎麼去測試呢?每次都 開啟多個瀏覽器標籤或用Swagger的形式,如下:

第一次訪問:

每次都開啟新標籤,再訪問介面:

除了根據資料沒變來判定是快取資料外,還可以通過請求確定是否從本地快取中取資料,如下:

Swagger演示,關於如何整合Swagger,之前有專門分享過(跟我一起學.NetCore之Swagger讓前後端不再煩惱及介面自定義):

瀏覽器快取的原理其實就是在響應頭中增加Cache-Control(ResponseCache的方式是通過Action過濾器的形式設定的響應頭),告訴瀏覽器進行資料快取,在指定時間範圍內可以從快取中取,我們也可以自己手動設定響應頭資訊來達到同樣的效果,如下:

儘管資料已經快取,瀏覽器也可以選擇不從快取取,如下:

2. 伺服器快取

2.1 簡述

瀏覽器快取只是將資料儲存在單臺電腦的不同位置,如果開啟不同的瀏覽器或不同的電腦訪問時,還是起不到快取的效果,所以搞個伺服器快取肯定是個不錯的選擇。

將資料快取到站點伺服器中,當請求過來時,如果命中快取,直接獲取返回即可,不呼叫對應的後臺API

2.2 案例

其實這只是在原來瀏覽器快取的基礎上增加了一箇中介軟體的處理,如下:

程式碼如下:

執行效果:

由於不同的瀏覽器儲存的資料位置不一樣,如果僅僅是本地快取,那麼兩個瀏覽器的資料會返回不一樣;另外第一個瀏覽器訪問之後,其他瀏覽器在時間範圍內獲得結果是一樣的,也不會呼叫後臺介面。

這種伺服器端的快取在有些情況是不生效的,如:請求Method不是Get或Head的不快取,返回狀態碼不是200的不快取,請求頭包含Authorization的不快取等,所以基本很少用這種方式進行快取操作。

3. 應用記憶體快取

3.1 簡述

對於上面說到的瀏覽器快取和伺服器快取,如果是友好的使用者訪問,沒問題,能起到一定的效果;但如果有人要使壞,不設定對應的請求頭訪問API(禁用快取),最終還是會給應用伺服器和資料庫伺服器帶來壓力。所以需要一種能主動控制的快取方式,後端程式就是下手的物件,在後端程式中寫快取邏輯,這樣快取策略就由我們自己控制了。

雖然每次請求都會進入應用程式,但會先從快取中進行獲取資料,如果命中快取,就不再進行資料庫訪問,直接將快取資料返回。

3.2 案例

其實框架中針對記憶體快取這塊已經做好了封裝,只需註冊相關的服務就可以用了,如下:

註冊完成之後,只需要注入就可以使用了,這裡增加一個Action方法進行演示:

效果就不截圖了,在20秒內,單程式部署情況下,不管怎麼訪問都會是一樣的結果。如果想更多瞭解MemoryCache的使用,可以看看這篇文章《因MemoryCache鬧了個笑話》。

4. 分散式快取

4.1 簡述

記憶體快取雖然能解決瀏覽器和伺服器快取的缺點,但只對單體部署程式比較適用,對於需要分散式部署的程式來說,程式記憶體之間的快取資料不能共享,快取的效果肯定就沒那麼盡人意,所以分散式快取就出來了,採用對應的中介軟體,如Memcache、Redis等,而Redis成為了快取的首選。

請求的邏輯和記憶體快取差不多一樣,只是分散式快取會採用第三方中介軟體進行資料儲存,保證分散式部署的程式共用一套快取。

4.2 案例

這裡還是用最火的Redis做演示,所以需要提前安裝Redis,關於Redis系列的文章,小夥伴們可以看這《給我一起學Redis》。

框架也提供了統一操作分散式快取的介面IDistributedCache,用法和上面的記憶體快取基本一樣。

這裡用的是Redis,所以需要安裝對應的Nuget包Microsoft.Extensions.Caching.StackExchangeRed,然後註冊相關服務就可以用了,如下:

註冊完成之後,只需要注入就可以使用了,這裡也增加一個Action方法進行演示:

訪問對應的介面,在設定的時間範圍內從Redis中讀取到的資料一致,過期之後就會清空,程式又會設定新的值,如下:

關於快取的幾種用法就先暫時說這麼多,也有小夥伴根據業務場景自己實現的。

例項的原始碼:https://gitee.com/CodeZoe/dot-net-core-study-demo/tree/main/CacheDemo

總結

快取之所以現在這麼火,其主要目的還是提升資料訪問效率,緩解應用和資料庫的壓力,但同時也會帶來一些問題,比如快取穿透、快取擊穿、快取雪崩及快取資料與資料庫不一致等問題,後續我們會逐個說說,關注“Code綜藝圈”,和我一起學習吧。

相關文章