.net 溫故知新【14】:Asp.Net Core WebAPI 緩存

来源:https://www.cnblogs.com/SunSpring/archive/2023/11/24/17848185.html
-Advertisement-
Play Games

一、緩存 緩存指在中間層中存儲數據的行為,該行為可使後續數據檢索更快。 從概念上講,緩存是一種性能優化策略和設計考慮因素。 緩存可以顯著提高應用性能,方法是提高不常更改(或檢索成本高)的數據的就緒性。 二、RFC9111 在最新的緩存控制規範文件RFC9111中,詳細描述了瀏覽器緩存和伺服器緩存控制 ...


一、緩存

緩存指在中間層中存儲數據的行為,該行為可使後續數據檢索更快。 從概念上講,緩存是一種性能優化策略和設計考慮因素。 緩存可以顯著提高應用性能,方法是提高不常更改(或檢索成本高)的數據的就緒性。

二、RFC9111

在最新的緩存控制規範文件RFC9111中,詳細描述了瀏覽器緩存和伺服器緩存控制的規範,其中有一個最重要的響應報文頭Cache-Control

該報文頭的設置會影響我們的緩存,包括瀏覽器端和服務端。

RFC911:https://www.rfc-editor.org/rfc/rfc9111#name-cache-control

image

三、網頁端緩存

Cache-Control中,如果設置max-age=10,則表示告訴瀏覽器緩存10s,而為什麼瀏覽器要認這個表示呢,就是上面我們說的前後端都要根據RFC標準規範去實現,就是硬體的統一插口,不然其他生成出來的就用不了。

那麼在Asp.net Core 中只需要在介面上打上ResponseCacheAttribute並設置max-age的時間即可。

首先建一個Asp.Net Core WebAPI 項目,寫一個獲取學生的Get介面。

image

namespace WebAPI_Cache.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class CacheController : ControllerBase
    {

        public CacheController()
        {

        }

        [HttpGet]
        public ActionResult<Student> GetStudent()
        {

            return new Student()
            {
                Id = 1,
                Name = "Test",
                Age = Random.Shared.Next(0, 100),
            };
        }
    }
}
namespace WebAPI_Cache.Model
{
    public class Student
    {
        public int Id { get; set; }
        public string? Name { get; set; }
        public int Age { get; set; }
    }
}

在介面中我返回Studentage為1-100的隨機數。啟動項目測試,短時間內兩次調用返回的age不一樣

第一次age:

image

第二次age:

image

當我在介面方法打上[ResponseCache(Duration = 10)],再次調用介面返回的信息可以看到已經有了cache-control: public,max-age=10 的Header。

image

並且我在10秒內的請求,只有第一次請求過伺服器,其他都是從緩存中取的,查看edge瀏覽器網路訪問如下:

image

四、伺服器緩存

網頁端緩存是放在瀏覽器端的,對於單點請求會有用,但是如果是多個不同前端請求呢。這個時候我們可以將緩存放置在後端服務中,在ASP.NET Core 中配置響應緩存中間件。

在 Program.cs中,將響應緩存中間件服務 AddResponseCaching 添加到服務集合,並配置應用,如果使用 CORS 中間件時,必須在 UseResponseCaching 之前調用 UseCors。

如果header包含 Authorization,Set-Cookie 標頭,也不會緩存,因為這些用戶信息緩存會引起數據混亂。

image

然後對於我們需要伺服器緩存的介面打上ResponseCache屬性,和設置瀏覽器緩存一樣,還有其他參數可設置。我們通過兩個進程來測試,一個用瀏覽器swagger,一個用postman,可以看到兩個請求的age都是等於18的。所以可以確定伺服器端確實存在緩存。

image

但是在用postman測試的時候記得在settings裡面把Send no-cache header勾掉,如果不去掉,發送的時候就會在請求頭裡麵包含Cache-Control:no-cache,這樣服務端即便有緩存也不會使用緩存。

image

對於瀏覽器端相當於禁用緩存,如果禁用了緩存,發送的請求頭也會帶上Cache-Control:no-cache,服務端看到no-cache 後便不會再使用緩存進行響應。

而這個約定就是RFC9111的規範,所以這個後端緩存策略比較雞肋,如果用戶禁用緩存就沒用了,因此我們還可以使用記憶體緩存。

五、記憶體緩存

記憶體緩存基於 IMemoryCache。 IMemoryCache 表示存儲在 Web 伺服器記憶體中的緩存。

  • 首先Nuget安裝包
Install-Package Microsoft.Extensions.Caching.Memory
  • 在Program.cs中添加依賴
builder.Services.AddMemoryCache();
  • 緩存數據
    我添加一個Post方法模擬id查詢Student

image

這樣我就將數據緩存到了記憶體,可以設置緩存的絕對過期時間,也可以設置滑動過期,稍後我們會看到過期策略的使用。

六、緩存擊穿

緩存擊穿是指熱點key在某個時間點過期的時候,而恰好在這個時間點對這個Key有大量的併發請求過來,或者是查詢了不存在的數據,緩存裡面沒有,從而大量的請求打到資料庫上形成資料庫壓力。

上面記憶體緩存中的寫法我們可以看到,如果查詢緩存等於null就會再去查詢數據(我這裡只是模擬,沒有去寫真的資料庫查詢),如果這樣暴力請求攻擊就會有問題。

對於這個問題我們可以使用ImemoryCacheGetOrCreate方法,當然它還有非同步方式。通過該方法傳入緩存的key和func 委托方法返回值來進行查詢並緩存,如果沒查詢到返回的null也會存儲在緩存中,防止惡意查詢不存在的數據。

        [HttpPost]
        public ActionResult<Student> GetStudent2(int id)
        {
            //查詢並創建緩存
            var student = _memoryCache.GetOrCreate("student_" + id, t =>
            {
                t.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(20);
                //模擬只有id=1有數據
                if (id == 1)
                {
                    return new Student()
                    {
                        Id = 1,
                        Name = "Test",
                        Age = Random.Shared.Next(0, 100),
                    };
                }
                else
                {
                    //其他的返回空,但是空值也會緩存,比如查詢 id=2,id=3 都會緩存
                    return null;
                }

            });
            if (student == null)
            {
                return NotFound("未找到");
            }
            else
            {
                return student;
            }
        }

七、緩存雪崩

緩存雪崩是指緩存中數據大批量到過期時間,導致所有請求都會去查資料庫,而查詢數據量巨大,引起資料庫壓力過大甚至down機。

對於雪崩情況我們對緩存的策略主要是設置過期時間,部分不重要的站點,比如新聞網站我們將絕對過期時間AbsoluteExpiration設置的久一點。

對於要一定靈活性,能在請求不頻繁的時候進行失效以更新數據的,我們可以用滑動過期時間,就是如果頻繁請求就一值滑動過期時間。

當然為了避免滑動時間一直不過期,還可以兩種方式混合使用。上面的例子,我們設置絕對過期時間是20秒,我們將滑動過期設置5秒,在5秒內有持續訪問就一直續命,直到20秒絕對過期。

那麼如果沒人訪問,在5秒後就過期了,這樣數據下次訪問也能及時查詢最新數據。

image

八、分散式緩存

有了上面的緩存方案,對付一些小的簡單業務系統完全夠用了,但是如果你是分散式部署服務,那麼像記憶體緩存訪問的數據就是單個伺服器的緩存。

你可能需要多個伺服器的請求之間保持一致、在進行伺服器重啟和應用部署後仍然有效、不使用本地記憶體等情況。

這個時候我們可以使用第三方緩存,比如memecache,Redis等。Asp.Net Core 使用 IDistributedCache 介面與緩存進行交互。

  • NuGet安裝包
Install-Package Microsoft.Extensions.Caching.StackExchangeRedis
  • 在 Program.cs 中註冊 IDistributedCache 實現
    image

Configuration: 為連接配置。
InstanceName: 為存儲鍵首碼。

編寫測試方法GetStuden3

image

IDistributedCache 接受字元串鍵並以 byte[] 數組的形式添加或檢索緩存項,所以數據是以byte[]形式訪問,但是擴展了一個string類型的方法可以進行使用,我這裡用字元串進行操作。

以上這些就是關於asp.net core 當中使用緩存的重要點和基礎使用方法,詳細參數和文檔可參看官方文檔:ASP.NET Core 中的緩存概述

作者:孫泉

出處:https://www.cnblogs.com/SunSpring/p/17848185.html

如果你喜歡文章歡迎點擊推薦,你的鼓勵對我很有用!

本文版權歸作者所有,轉載需在文章頁面明顯位置給出原文鏈接。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 就在今天凌晨,Spring Boot 3.2正式發佈了!該版本是在Java 21正式發佈之後的重要支持版本,所以在該版本中包含大量對Java 21支持的優化。 下麵,我們分別通過Spring官方發佈的博文和Josh Long長達80+分鐘的介紹視頻,一起認識一下Spring Boot 3.2最新版本 ...
  • 作者:敲敲敲敲暴你腦袋 鏈接:https://juejin.cn/post/7290758270577557539 一入國企深似海,捆綁越多,你走得越難,有的人甚至終身被困於此,任人搓揉捏扁。離職就要走得乾脆點,不要回頭,通常更煩的事情可能還在後頭,早走早解脫! 1.國企怎樣的? 有人說進國企,基本 ...
  • 在深度學習中,PyTorch和NumPy是兩個常用的工具,用於處理和轉換數據。PyTorch是一個基於Python的科學計算庫,用於構建神經網路和深度學習模型。NumPy是一個用於科學計算的Python庫,提供了一個強大的多維數組對象和用於處理這些數組的函數。 在深度學習中,通常需要將數據從NumP ...
  • 作為一名有著Java背景的開發者,你無疑已經習慣了Java那嚴格的類型系統和細緻的訪問控制機制。轉向Python,你會發現一個截然不同的編程世界。Python的面向對象編程(OOP)方式為代碼組織提供了更高的自由度和靈活性,這種變化可能會給你帶來新鮮感,同時也是一個挑戰。需要註意的是,Python的... ...
  • C++ 動態實例化(new 和 malloc) malloc / free 工作原理 malloc 是 stdlib.h 庫中的函數,聲明為 void *__cdecl malloc(size_t _Size); 原理: malloc 函數沿空閑鏈表(位於記憶體 堆空間 中)申請一塊滿足需求的記憶體塊, ...
  • 一:背景 1. 講故事 最近接連遇到了幾起 2G 虛擬地址緊張 導致的程式崩潰,基本上 90% 都集中在醫療行業,真的很無語,他們用的都是一些上古的 XP,Windows7 x86,我也知道技術人很難也基本無法推動硬體系統和設備的升級,這裡蘊含了巨大的人情世故。 寫這一篇的目的是想系統化的整理一下如 ...
  • 介紹 C#跨平臺UI框架 提供NETStandard2.0和net4的庫,通過Netcore可以跨平臺,支持Windows、Mac、Linux,Net4的可以支持XP。 各個平臺運行效果一致,不依賴系統控制項。 支持窗體,控制項任意透明,支持異形窗體,支持SVG圖標顯示。 支持動畫,數據綁定,Mvvm模 ...
  • ConfigureAwait in .NET8 ConfigureAwait(true) 和 ConfigureAwait(false) 首先,讓我們回顧一下原版 ConfigureAwait 的語義和歷史,它採用了一個名為 continueOnCapturedContext 的布爾參數。 當對任務 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...