【ASP.NET Core】ASP.NET Core中Redis分布式緩存的應用

系列文章目錄

鏈接: 【ASP.NET Core】REST與RESTful詳解,從理論到實現
鏈接: 【ASP.NET Core】深入理解Controller的工作機制
鏈接: 【ASP.NET Core】內存緩存(MemoryCache)原理、應用及常見問題解析


文章目錄

  • 系列文章目錄
  • 前言
  • 一、Redis
    • 1.1 Redis簡介
    • 1.2 常用數據結構
    • 1.3 Redis的持久化
      • 1.3.1 RDB
      • 1.3.2 AOF
    • 1.4 常用應用場景
      • 1.4.1 緩存
      • 1.4.2 計數器
      • 1.4.2 訂閱發布
  • 二、ASP.NET Core中應用Redis【使用IDistributedCache接口】
    • 2.1 安裝依賴
    • 2.2 Program.cs 注冊
    • 2.3 IDistributedCache
    • 2.4 ASP.NET Core Controller中操作Redis
      • 2.4.1 獲取緩存
      • 2.4.2 設置緩存
      • 2.4.3 刪除緩存
      • 2.4.4 刷新緩存
    • 2.4.5 完整代碼
  • 總結


前言

分布式緩存是將緩存數據存儲后供多個外部應用服務器中的服務共享使用。比起內存緩存僅支持本服務使用,分布式緩存擴展多服務器,多應用。故因此得名分布式緩存。本文將介紹ASP.NET Core中如何應用Redis作為分布式緩存服務。


一、Redis

在分享ASP.NET Core中應用Redis作為分布式緩存服務前,先簡單介紹一下Redis。

1.1 Redis簡介

Redis(Remote Dictionary Server)直譯過來就是遠程字典服務。作為一款開源的高性能內存數據結構存儲系統,支持字符串、哈希表、列表等多種數據結構,支持持久化保存功能。并且由于數據存儲在內存中,Redis的讀寫速度遠超傳統關系型數據庫。

1.2 常用數據結構

  • 字符串(String)
    • 二進制字符串,存儲文本、JSON、數字或二進制圖片數據等
  • 哈希(Hash)
    • 鍵值對集合,存儲對象結構的數據。
  • 列表(List)
    • 有序的字符串列表,一般用作存儲消息隊列,或者記錄時間線。
  • 集合(Set)
    • 無序且唯一的字符串集合,支持交并差操作。因為集合的特性,方便去重的場景使用。
  • 有序集合(Sorted Set)
    • 類似于普通的集合,但每個成員都關聯了一個分數(score),一般用作排行榜

1.3 Redis的持久化

Redis的持久化分為兩種。一種是RDB,通過將內存中的數據快照寫入磁盤達到數據的保存;另外一種是AOF,Redis 將每個寫操作追加到 AOF 文件的末尾,通過日志的方式記錄操作。

1.3.1 RDB

RDB,既Redis Database,是一種快照持久化機制。是Redis在某一個規則下將某一時刻的內存數據以二進制形式寫入磁盤,生成RDB文件。

RDB的配置項內容在在Redis根目錄下的名為redis.windows-service.conf的文件里。找到如下的結構

save 900 1		# 900秒內至少1個key被修改
save 300 10		# 300秒內至少10個key被修改
save 60 10000	# 60秒內至少10000個key被修改stop-writes-on-bgsave-error yes	#當RDB 快照生成過程中發生錯誤時(如磁盤已滿、權限不足)停止接受新的寫操作,防止數據不一致(默認值:yes)rdbcompression yes	#對RDB文件中的字符串對象啟用 LZF 壓縮算法rdbchecksum yes	#在RDB文件末尾添加 CRC64 校驗和,用于加載時驗證文件完整性dbfilename dump.rdb

RDB是默認開啟的,執行快照存儲的時候會在根目錄下新建dump.rdb文件記錄快照。

1.3.2 AOF

AOF,既Append Only File。Redis通過將每個寫操作(如 SET、INCR)追加到 AOF 文件的末尾,實現日志的記錄。顯然這種方式的數據安全性最高。

AOF的配置項內容在在Redis根目錄下的名為redis.windows-service.conf的文件里。找到如下的結構

appendonly yesappendfilename "appendonly.aof"

AOF并不是默認開啟的。考慮到每一步操作寫操作都會記錄日志。該生成的日志文件會隨著服務的運行變得十分巨大。

1.4 常用應用場景

1.4.1 緩存

將數據庫熱點數據緩存到 Redis,減少數據庫訪問壓力。Redis存儲空值得時候會記錄NULL,自動解決緩存穿透得問題。

1.4.2 計數器

Redis中INCR是用于將存儲在指定鍵中的數值遞增 1 的命令。如果鍵不存在,Redis會先將其初始化為 0,然后再執行 INCR 操作。由于指令是原子性的,這就為我們實現一個計數器提供很好的先決條件。以及接口限流等這種需要使用到計算的功能。

1.4.2 訂閱發布

當出現新的報警通知之類的,發布消息通知所有訂閱的客戶端。

二、ASP.NET Core中應用Redis【使用IDistributedCache接口】

在ASP.NET Core中應用Redis還是比較簡單的,本文應用StackExchangeRedis這個庫來對Redis進行操作。

2.1 安裝依賴

通過這個指令按照StackExchangeRedis包

dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis

2.2 Program.cs 注冊

在Program.cs中,我們通過AddStackExchangeRedisCache這個靜態擴展方法注冊Redis服務。通過觀察AddStackExchangeRedisCache源碼,我們發現實際上這個擴展方法往DI容器里注冊的是IDistributedCache接口以及實現類RedisCacheImpl。生命周期是singleton。

builder.Services.AddStackExchangeRedisCache(options =>
{options.Configuration = builder.Configuration["Redis:ConnectionStrings"];options.InstanceName = builder.Configuration["Redis:InstanceName"];
});
/// <summary>
/// Adds Redis distributed caching services to the specified <see cref="IServiceCollection" />.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
/// <param name="setupAction">An <see cref="Action{RedisCacheOptions}"/> to configure the provided
/// <see cref="RedisCacheOptions"/>.</param>
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
public static IServiceCollection AddStackExchangeRedisCache(this IServiceCollection services, Action<RedisCacheOptions> setupAction)
{ArgumentNullThrowHelper.ThrowIfNull(services);ArgumentNullThrowHelper.ThrowIfNull(setupAction);services.AddOptions();services.Configure(setupAction);services.Add(ServiceDescriptor.Singleton<IDistributedCache, RedisCacheImpl>());return services;
}

2.3 IDistributedCache

IDistributedCache是ASP.NET Core框架提供的一個接口,用于實現分布式緩存,支持多種緩存提供者。也就是說不僅僅是Redis能夠通過這個接口被操作。
這個接口定義很簡單,總的來說就四種方法。Get,Set,Refresh,Remove。以及對應的四個異步方法。

/// <summary>
/// Represents a distributed cache of serialized values.
/// </summary>
public interface IDistributedCache
{/// <summary>/// Gets a value with the given key./// </summary>/// <param name="key">A string identifying the requested value.</param>/// <returns>The located value or null.</returns>byte[]? Get(string key);/// <summary>/// Gets a value with the given key./// </summary>/// <param name="key">A string identifying the requested value.</param>/// <param name="token">Optional. The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>/// <returns>The <see cref="Task"/> that represents the asynchronous operation, containing the located value or null.</returns>Task<byte[]?> GetAsync(string key, CancellationToken token = default(CancellationToken));/// <summary>/// Sets a value with the given key./// </summary>/// <param name="key">A string identifying the requested value.</param>/// <param name="value">The value to set in the cache.</param>/// <param name="options">The cache options for the value.</param>void Set(string key, byte[] value, DistributedCacheEntryOptions options);/// <summary>/// Sets the value with the given key./// </summary>/// <param name="key">A string identifying the requested value.</param>/// <param name="value">The value to set in the cache.</param>/// <param name="options">The cache options for the value.</param>/// <param name="token">Optional. The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = default(CancellationToken));/// <summary>/// Refreshes a value in the cache based on its key, resetting its sliding expiration timeout (if any)./// </summary>/// <param name="key">A string identifying the requested value.</param>void Refresh(string key);/// <summary>/// Refreshes a value in the cache based on its key, resetting its sliding expiration timeout (if any)./// </summary>/// <param name="key">A string identifying the requested value.</param>/// <param name="token">Optional. The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>Task RefreshAsync(string key, CancellationToken token = default(CancellationToken));/// <summary>/// Removes the value with the given key./// </summary>/// <param name="key">A string identifying the requested value.</param>void Remove(string key);/// <summary>/// Removes the value with the given key./// </summary>/// <param name="key">A string identifying the requested value.</param>/// <param name="token">Optional. The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>Task RemoveAsync(string key, CancellationToken token = default(CancellationToken));
}

觀察以上代碼,我們發現返回的RedisValue類型都是byte[]字節數組。這是因為分布式緩存通常運行在獨立的服務,與應用服務器可能使用不同的技術棧。為確保數據能被不同語言或框架正確解析,需要一種通用的數據表示形式。這也是IDistributedCache支持多種緩存提供者的原因。

也就是說實際上從分布式緩存里取到的結果從字節數組需要解析成指定格式的數據,存儲的時候也需要序列化成字節數組。這樣操作尤其麻煩,好在微軟提供了一個名為DistributedCacheExtensions的靜態擴展,內部幫我們通過 Encoding.UTF8.GetBytes(value)和Encoding.UTF8.GetString(data, 0, data.Length)的形式將結果集和字符串形成轉換,相當于少轉了一步。

DistributedCacheExtensions源碼片段【namespace Microsoft.Extensions.Caching.Distributed】

public static Task SetStringAsync(this IDistributedCache cache, string key, string value, DistributedCacheEntryOptions options, CancellationToken token = default(CancellationToken))
{ThrowHelper.ThrowIfNull(key);ThrowHelper.ThrowIfNull(value);return cache.SetAsync(key, Encoding.UTF8.GetBytes(value), options, token);
}public static async Task<string?> GetStringAsync(this IDistributedCache cache, string key, CancellationToken token = default(CancellationToken))
{byte[]? data = await cache.GetAsync(key, token).ConfigureAwait(false);if (data == null){return null;}return Encoding.UTF8.GetString(data, 0, data.Length);
}

2.4 ASP.NET Core Controller中操作Redis

2.4.1 獲取緩存

根據key獲取值,并且轉型

	// 嘗試從分布式緩存獲取數據var cachedData = await _distributedCache.GetStringAsync(cacheKey);Movie? movie = null;if (!string.IsNullOrEmpty(cachedData)){// 反序列化緩存數據movie = JsonSerializer.Deserialize<Movie>(cachedData);_logger.LogInformation("從緩存中獲取了電影數據");}

2.4.2 設置緩存

	// 緩存未命中,從數據源獲取movie = await _movieAssert.GetMovieAsync(id);if (movie != null){// 設置緩存選項var cacheOptions = new DistributedCacheEntryOptions{// 同時設置絕對過期和滑動過期AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10),SlidingExpiration = TimeSpan.FromMinutes(5)};// 序列化并存儲到分布式緩存var serializedData = JsonSerializer.Serialize(movie);await _distributedCache.SetStringAsync(cacheKey, serializedData, cacheOptions);_logger.LogInformation("已將電影數據存入緩存");}

2.4.3 刪除緩存

根據key刪除緩存

	await _distributedCache.RemoveAsync(cacheKey);

2.4.4 刷新緩存

一般是碰到需要手動續滑動過期時間的場景才會使用。Redis中如果請求了一個被設置了滑動過期時間的緩存,會自動刷新滑動過期時間的。

	await _distributedCache.RefreshAsync(cacheKey);

2.4.5 完整代碼

[Route("api/[controller]")]
[ApiController]
public class MovieController : ControllerBase
{private readonly ILogger<MovieController> _logger;private readonly IMovieAssert _movieAssert;private readonly IDistributedCache _distributedCache;public MovieController(ILogger<MovieController> logger, IMovieAssert movieAssert, IDistributedCache distributedCache = null){_logger = logger;_movieAssert = movieAssert;_distributedCache = distributedCache;}[HttpGet("{id}")]public async Task<ActionResult<Movie?>> Movies(int id){_logger.LogDebug("開始獲取數據");var cacheKey = $"Movie:{id}";// 嘗試從分布式緩存獲取數據var cachedData = await _distributedCache.GetStringAsync(cacheKey);Movie? movie = null;if (!string.IsNullOrEmpty(cachedData)){// 反序列化緩存數據movie = JsonSerializer.Deserialize<Movie>(cachedData);_logger.LogInformation("從緩存中獲取了電影數據");}else{// 緩存未命中,從數據源獲取movie = await _movieAssert.GetMovieAsync(id);if (movie != null){// 設置緩存選項var cacheOptions = new DistributedCacheEntryOptions{// 同時設置絕對過期和滑動過期AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10),SlidingExpiration = TimeSpan.FromMinutes(5)};// 序列化并存儲到分布式緩存var serializedData = JsonSerializer.Serialize(movie);await _distributedCache.SetStringAsync(cacheKey, serializedData, cacheOptions);_logger.LogInformation("已將電影數據存入緩存");}}if (movie is null){return NotFound("沒有數據");}return movie;}
}

總結

本文介紹了 Redis 的基本情況及在ASP.NET Core 中借助IDistributedCache接口使用Redis作為分布式緩存的具體操作。

IDistributedCache作為微軟封裝的一個通用的分布式緩存接口,只能說應用了Redis的一些基礎服務。之后我們會討論如何通過直接注冊ConnectionMultiplexer這種方式獲取Redis連接對象,使用Redis的那些高級用法。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/915638.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/915638.shtml
英文地址,請注明出處:http://en.pswp.cn/news/915638.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

5.6 指令流水線 (答案見原書 P267)

5.6 指令流水線 (答案見原書 P267) 01. 下列關于流水CPU基本概念的描述中&#xff0c;正確的是&#xff08; D &#xff09;。 題目原文 下列關于流水CPU基本概念的描述中&#xff0c;正確的是&#xff08; &#xff09;。 A. 流水CPU是以空間并行性為原理構造的處理器 B. 流水…

NIO簡單介紹和運用

NIO簡單介 NIO 非阻塞IO模型&#xff0c;基于緩沖區(Buffer)讀寫數據&#xff0c;讀寫后的數據通過通道(Channel)進行傳輸&#xff0c;采用選擇器(Selector)管理多個通道從而實現高并發。 核心組件&#xff1a;1. Buffer 為一個內存數組作為數據容器&#xff0c;代替傳統的Inpu…

LeetCode 658.找到K個最接近的元素

給定一個 排序好 的數組 arr &#xff0c;兩個整數 k 和 x &#xff0c;從數組中找到最靠近 x&#xff08;兩數之差最小&#xff09;的 k 個數。返回的結果必須要是按升序排好的。 整數 a 比整數 b 更接近 x 需要滿足&#xff1a; |a - x| < |b - x| 或者 |a - x| |b - x| …

制作一款打飛機游戲83:炸彈機制

游戲中的炸彈系統&#xff0c;包括以下核心功能&#xff1a;炸彈爆炸效果與動畫實現炸彈傷害范圍判定機制子彈轉化為能量道具的系統炸彈使用時的無敵幀處理各種邊界情況的修復與優化技術實現細節1. 炸彈基礎系統?炸彈動畫狀態機?&#xff1a; 我們采用三階段狀態機控制炸彈效…

Linux CentOS 虛擬機升級內核至4.x以上版本

1、安裝組件 yum install -y wget && yum install -y net-tools yum groupinstall “Development Tools” yum install ncurses-devel bc openssl-devel elfutils-libelf-devel yum install -y ncurses-devel yum install -y elfutils-libelf-devel yum install -y ope…

QT跨平臺應用程序開發框架(11)—— Qt系統相關

目錄 一&#xff0c;事件 1.1 關于事件 1.2 處理事件 1.3 處理鼠標事件 1.3.1 點擊事件 1.3.2 釋放事件 1.3.3 雙擊事件 1.3.4 滾輪事件 1.3.5 注意事項 1.4 處理鍵盤事件 1.5 定時器事件 1.6 窗口移動和大小改變事件 二&#xff0c;文件操作 2.1 文件操作概述 2.2 QFile 介紹…

sqli-labs通關筆記-第11關 POST字符型注入(單引號閉合 手工注入+腳本注入兩種方法)

目錄 一、字符型注入 二、limit函數 三、GET方法與POST方法 四、源碼分析 1、代碼審計 2、SQL注入安全分析 五、滲透實戰 1、進入靶場 2、注入點分析 &#xff08;1&#xff09;SQL語句 &#xff08;2&#xff09;萬能密碼登錄 3、手工注入 &#xff08;1&#xf…

網絡安全基礎作業三

回顧web前端的代碼<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>用戶登錄</title><st…

基于單片機的溫濕度報警系統設計與實現

摘 要 本項研究對溫濕度警報系統的需求進行了詳盡分析&#xff0c;并成功研制出一套以單片機為技術核心的溫濕度警報系統。該系統由硬件搭建和軟件編程兩大模塊構成。在硬件搭建方面&#xff0c;系統整合了STM32主控芯片、DS18B20溫度傳感器、濕敏電阻、按鍵組件、OLED顯示屏、…

(八)復習(拆分微服務)

文章目錄項目地址一、Ticketing模塊拆分1.1 創建web api1. 添加引用2. 添加需要的包和配置3. program.cs4. docker-compose修改項目地址 教程作者&#xff1a;教程地址&#xff1a; 代碼倉庫地址&#xff1a; 所用到的框架和插件&#xff1a; dbt airflow一、Ticketing模塊拆…

DearMom以“新生兒安全系統”重塑嬰兒車價值,攬獲CBME雙項大獎

7月16日&#xff0c;在剛剛開幕的2025 CBME中國孕嬰童展上&#xff0c;備受矚目的CBME中國孕嬰童產業獎正式揭曉。深耕嬰兒車品類的專業品牌DearMom&#xff0c;憑借其卓越的創新實力與對新生兒安全出行的深刻洞察&#xff0c;一舉摘得重量級獎項——“杰出品牌創新獎”。同時&…

瀚高數據庫開啟Oracle兼容模塊

文章目錄環境癥狀問題原因解決方案環境 系統平臺&#xff1a;Linux x86-64 Red Hat Enterprise Linux 7 版本&#xff1a;4.5 癥狀 不能使用Oracle兼容&#xff1b; 問題原因 在瀚高數據庫V45中oracle兼容模塊需要單獨開啟默認是關閉狀態。 解決方案 使用sysdba執行修改…

final修飾符不可變的底層

final修飾符的底層原理在 Java 中&#xff0c;final 修飾符的底層實現涉及 編譯器優化 和 JVM 字節碼層面的約束其核心目標是保證被修飾元素的【不可變性】或 【不可重寫 / 繼承性】一、final 修飾類&#xff1a;禁止繼承的底層約束當一個類被 final 修飾時&#xff0c;例如 St…

如何排查服務器 CPU 飆高

服務器 CPU 飆高&#xff08;CPU 使用率持續超過 80% 甚至接近 100%&#xff09;是典型的性能瓶頸問題&#xff0c;可能由應用邏輯缺陷、資源競爭、外部壓力或硬件/系統異常引起。以下是系統化的排查步驟&#xff0c;覆蓋從現象確認到根因定位的全流程。?一、確認 CPU 飆高的現…

【DataWhale】快樂學習大模型 | 202507,Task05筆記

前言 今天是Transformer的編碼實戰階段&#xff0c;照著示例代碼執行一遍吧 embedding self.tok_embeddings nn.Embedding(args.vocab_size, args.dim)把token向量轉為embedding矩陣&#xff08;一個token一個embedding向量&#xff09; 位置編碼 為了解決“我喜歡你”和…

用ffmpeg 進行視頻的拼接

author: hjjdebug date: 2025年 07月 22日 星期二 17:06:02 CST descrip: 用ffmpeg 進行視頻的拼接 文章目錄1. 指定協議為concat 方式.1.1 協議為concat 模式,會調用 concat_open 函數1.2 當讀數據時,會調用concat_read2. 指定file_format 為 concat 方式2.1 調用concat_read_…

HTTP與HTTPS技術細節及TLS密鑰交換與證書校驗全流程

HTTP與HTTPS技術細節及TLS密鑰交換與證書校驗全流程 引言 文檔目的與范圍 核心技術棧概述 本文檔的核心技術棧圍繞傳輸層安全協議&#xff08;TLS&#xff09;展開。TLS協議作為安全套接字層&#xff08;SSL&#xff09;的后繼標準&#xff0c;是現代網絡安全通信的基礎&am…

廣播分發中心-廣播注冊流程

廣播是怎么注冊的呢&#xff1f;階段組件/數據結構作用描述存儲位置/關聯關系App進程階段BroadcastReceiver開發者自定義的廣播接收器&#xff0c;實現onReceive方法處理事件。App進程&#xff08;Activity/Service等組件內&#xff09;ReceiverDispatcher將BroadcastReceiver封…

OpenCV計算機視覺實戰(16)——圖像分割技術

OpenCV計算機視覺實戰&#xff08;16&#xff09;——圖像分割技術0. 前言1. 分水嶺算法1.1 應用場景1.2 實現過程2. GrabCut 交互式分割2.1 應用場景2.2 實現過程3. FloodFill3.1 應用場景3.2 實現過程小結系列鏈接0. 前言 圖像分割是計算機視覺中將像素劃分為具有特定語義或…

Coturn打洞服務器

* 概念理解&#xff1a;1. SDP協議&#xff1a;會話描述協議&#xff0c;視頻通話的雙方通過交換SDP信息進行媒體協商&#xff0c;從而選擇使用某一相同的媒體協議進行通信&#xff1b;TLS協議&#xff1a;基于TCP的安全層傳輸協議DTLS協議&#xff1a;基于UDP的安全層傳輸協議…