本文說明如何在 ASP.NET Core 應用程式中設定和使用 HybridCache 程式庫。 如需程式庫的簡介,請參閱快取概觀的 HybridCache 區段。
取得程式庫
安裝 Microsoft.Extensions.Caching.Hybrid 套件。
dotnet add package Microsoft.Extensions.Caching.Hybrid
註冊服務
藉由呼叫 HybridCache,將 AddHybridCache 服務新增至容器中:
// Add services to the container.
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddAuthorization();
builder.Services.AddHybridCache();
上述程式碼會使用預設選項註冊 HybridCache 服務。 註冊 API 也可以設定選項和序列化。
取得和儲存快取條目
此 HybridCache 服務提供兩個多載的 GetOrCreateAsync 方法,接受索引鍵及:
- 工廠方法。
- 狀態和工廠方法。
方法會使用索引鍵嘗試從主要快取擷取物件。 如果在主要快取中找不到項目 (快取遺失),則會檢查是否已設定次要快取。 如果找不到該處的資料 (另一個快取遺失),它會呼叫 Factory 方法,以從資料來源取得物件。 然後,它會將物件儲存在主要和次要快取中。 如果在主要或次要快取中找到物件 (快取命中),則永遠不會呼叫 Factory 方法。
HybridCache 服務可確保只有一個指定機碼的並發呼叫者會呼叫製造方法,其他呼叫者則會等候該呼叫的結果。 傳遞到 CancellationToken 的 GetOrCreateAsync 代表著所有同時呼叫者的合併取消。
主要 GetOrCreateAsync 超載
在大部分情況下,建議使用 GetOrCreateAsync 的無狀態重載。 要呼叫的程式碼相對簡單。 以下是範例:
public class SomeService(HybridCache cache)
{
private HybridCache _cache = cache;
public async Task<string> GetSomeInfoAsync(string name, int id, CancellationToken token = default)
{
return await _cache.GetOrCreateAsync(
$"{name}-{id}", // Unique key to the cache entry
async cancel => await GetDataFromTheSourceAsync(name, id, cancel),
cancellationToken: token
);
}
public async Task<string> GetDataFromTheSourceAsync(string name, int id, CancellationToken token)
{
string someInfo = $"someinfo-{name}-{id}";
return someInfo;
}
}
快取金鑰指引
傳遞至 key 的 GetOrCreateAsync 必須唯一識別要快取的數據:
- 就用來從其來源擷取該數據的標識碼值而言。
- 就應用程式中快取的其他資料而言。
這兩種類型的唯一性通常透過串連字串的方式來確保,將不同部分合併成單一鍵字串。 例如:
cache.GetOrCreateAsync($"/orders/{region}/{orderId}", ...);
或
cache.GetOrCreateAsync($"user_prefs_{userId}", ...);
呼叫者有責任確保密鑰配置有效,而且無法造成數據變得混淆。
避免直接在快取索引鍵中使用外部用戶輸入。 例如,請勿使用使用者介面的原始字串作為快取索引鍵。 這麼做可能會讓您的應用程式面臨安全性風險,例如未經授權的存取或拒絕服務攻擊,因為快取中含有隨機或無意義的密鑰。 在上述有效範例中, 順序 和 用戶喜好設定 數據會清楚分隔並使用受信任的標識碼:
-
orderid和userId是內部產生的標識碼。 -
region可能是已知區域預先定義清單中的枚舉或字串。
標記如/或_沒有被當作重要的。 整個索引鍵值會被視為不透明的識別字串。 在此情況下,您可以省略 / 和 _,而不會改變快取的功能方式,但通常會使用分隔符來避免模稜兩可。例如,$"order{customerId}{orderId}" 可能會導致混淆:
-
customerId42,orderId123 -
customerId421 與orderId23
此兩個範例都會產生快取索引鍵 order42123。
本指南同樣適用於任何以 string為基礎的快取 API,例如 HybridCache、IDistributedCache和 IMemoryCache。
請注意,內嵌的內插字串語法($"...",位於上述有效索引鍵的範例中)直接在 GetOrCreateAsync 調用中。 使用 HybridCache時,建議使用這個語法,因為它允許規劃的未來改善,以略過在許多案例中為密鑰配置 string 的需求。
其他重要考慮
- 金鑰可以限制為有效的最大長度。 例如,預設
HybridCache實作(透過AddHybridCache(...))預設會將索引鍵限製為1024個字元。 該數目可透過HybridCacheOptions.MaximumKeyLength來設定,較長的鍵會略過快取機制,以避免飽和。 - 索引鍵必須是有效的 Unicode 序列。 如果傳遞無效的 Unicode 序列,則行為是未定義的。
- 使用進程外次要快取時,例如
IDistributedCache,後端實作可能會施加額外的限制。 作為假設的範例,特定後端可能會使用不區分大小寫的索引鍵邏輯。 預設HybridCache(透過AddHybridCache(...))會偵測此情境,以防止混淆攻擊或別名攻擊(使用位元字串等於性)。 不過,此情況可能仍然會導致衝突的鍵值被覆寫或收回的速度比預期更快。
替代的 GetOrCreateAsync 多載
替代的過載可能會降低捕獲變數和每個實例回調的一些負擔,但代價是更複雜的程式碼。 在大部分情況下,效能提升不會超過程式代碼的複雜度。 以下是使用替代重載的範例:
public class SomeService(HybridCache cache)
{
private HybridCache _cache = cache;
public async Task<string> GetSomeInfoAsync(string name, int id, CancellationToken token = default)
{
return await _cache.GetOrCreateAsync(
$"{name}-{id}", // Unique key to the cache entry
(name, id, obj: this),
static async (state, token) =>
await state.obj.GetDataFromTheSourceAsync(state.name, state.id, token),
cancellationToken: token
);
}
public async Task<string> GetDataFromTheSourceAsync(string name, int id, CancellationToken token)
{
string someInfo = $"someinfo-{name}-{id}";
return someInfo;
}
}
SetAsync 方法
在許多情況下,GetOrCreateAsync 是唯一需要的 API。 但 HybridCache 也必須具有 SetAsync 以將物件儲存在快取中,而不需要先嘗試擷取它。
依機碼移除快取項目
當快取項目的基礎資料在到期前變更時,可透過使用機碼呼叫RemoveAsync 來明確移除此項目。 過載允許您指定一組鍵值集合。
移除項目時,它會從主要和次要快取中移除。
依標籤移除快取項目
標籤可用來將快取項目分組,並使其一起失效。
呼叫 GetOrCreateAsync 時設定標籤,如下列範例所示:
public class SomeService(HybridCache cache)
{
private HybridCache _cache = cache;
public async Task<string> GetSomeInfoAsync(string name, int id, CancellationToken token = default)
{
var tags = new List<string> { "tag1", "tag2", "tag3" };
var entryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromMinutes(1),
LocalCacheExpiration = TimeSpan.FromMinutes(1)
};
return await _cache.GetOrCreateAsync(
$"{name}-{id}", // Unique key to the cache entry
async cancel => await GetDataFromTheSourceAsync(name, id, cancel),
entryOptions,
tags,
cancellationToken: token
);
}
public async Task<string> GetDataFromTheSourceAsync(string name, int id, CancellationToken token)
{
string someInfo = $"someinfo-{name}-{id}";
return someInfo;
}
}
使用標籤值呼叫 RemoveByTagAsync,以移除指定標籤的所有項目。 函式多載允許您指定一組標籤值。
IMemoryCache和IDistributedCache都不直接支援標籤概念,因此基於標籤的失效僅僅是一個邏輯的操作。 它不會主動從本機或分散式快取中移除值。 相反地,它會確保以這類標籤上繼數據時,數據會被視為來自本機和遠端快取的快取遺漏。 這些值會根據設定的存留期,以一般的方式從IMemoryCache和IDistributedCache到期。
移除所有快取項目
星號標記 (*) 會保留為通配符,不允許針對個別值。 呼叫 RemoveByTagAsync("*") 會讓 所有數據HybridCache 失效,甚至是沒有任何標籤的數據。 如同個別標記,這是 邏輯 作業,而個別值會繼續存在,直到它們自然過期為止。 不支援 Glob 樣式匹配。 例如,您無法使用 RemoveByTagAsync("foo*") 來移除所有以 foo 開頭的內容。
其他標記考慮
- 系統不會限制您可以使用的標籤,但大量標記可能會對效能造成負面影響。
- 標記不能是空的、只有空格符或保留的值
*。
選項
AddHybridCache 方法可用來設定全域預設值。 下列範例示範如何設定一些可用的選項:
// Add services to the container.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthorization();
builder.Services.AddHybridCache(options =>
{
options.MaximumPayloadBytes = 1024 * 1024;
options.MaximumKeyLength = 1024;
options.DefaultEntryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromMinutes(5),
LocalCacheExpiration = TimeSpan.FromMinutes(5)
};
});
GetOrCreateAsync 方法也可以採用 HybridCacheEntryOptions 物件來覆寫特定快取項目的全域預設值。 以下是範例:
public class SomeService(HybridCache cache)
{
private HybridCache _cache = cache;
public async Task<string> GetSomeInfoAsync(string name, int id, CancellationToken token = default)
{
var tags = new List<string> { "tag1", "tag2", "tag3" };
var entryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromMinutes(1),
LocalCacheExpiration = TimeSpan.FromMinutes(1)
};
return await _cache.GetOrCreateAsync(
$"{name}-{id}", // Unique key to the cache entry
async cancel => await GetDataFromTheSourceAsync(name, id, cancel),
entryOptions,
tags,
cancellationToken: token
);
}
public async Task<string> GetDataFromTheSourceAsync(string name, int id, CancellationToken token)
{
string someInfo = $"someinfo-{name}-{id}";
return someInfo;
}
}
如需選項的詳細資訊,請參閱原始程式碼:
限制
下列 HybridCacheOptions 屬性可讓您設定適用於所有快取項目的限制:
- MaximumPayloadBytes - 快取項目的大小上限。 預設值為 1 MB。 系統會記錄嘗試儲存超過此大小的值,且該值不會儲存在快取中。
- MaximumKeyLength - 快取索引鍵的最大長度。 預設值為 1024 個字元。 系統會記錄嘗試儲存超過此大小的值,且該值不會儲存在快取中。
序列化
使用次要的外部快取需要序列化。 序列化設定為註冊 HybridCache 服務的一部分。 特定類型和一般用途的序列化器可以透過 AddSerializer 和 AddSerializerFactory 方法來進行設定,並從 AddHybridCache 呼叫鏈結。 根據預設,程式庫會在內部處理 string 和 byte[],並針對其他所有項目使用 System.Text.Json。
HybridCache 也可以使用其他序列化程式,例如 protobuf 或 XML。
下列範例會將服務設定為使用類型特定的 protobuf 序列化程式:
// Add services to the container.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthorization();
builder.Services.AddHybridCache(options =>
{
options.DefaultEntryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromSeconds(10),
LocalCacheExpiration = TimeSpan.FromSeconds(5)
};
}).AddSerializer<SomeProtobufMessage,
GoogleProtobufSerializer<SomeProtobufMessage>>();
下列範例會將服務設定為使用可處理許多 protobuf 類型的一般用途 protobuf 序列化程式:
// Add services to the container.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthorization();
builder.Services.AddHybridCache(options =>
{
options.DefaultEntryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromSeconds(10),
LocalCacheExpiration = TimeSpan.FromSeconds(5)
};
}).AddSerializerFactory<GoogleProtobufSerializerFactory>();
二級快取需要數據存放區,例如 Redis、SQL Server 或 Postgres。 若要使用 Azure Cache for Redis,例如:
安裝
Microsoft.Extensions.Caching.StackExchangeRedis套件。建立 Azure Cache for Redis 的執行個體。
取得連線至 Redis 實體的連接字串。 在 Azure 入口網站的 [概觀] 頁面上選取 [顯示存取金鑰],以尋找連接字串。
將連接字串儲存在應用程式的組態中。 例如,使用類似下列 JSON 的使用者祕密檔案,以及
ConnectionStrings區段中的連接字串。 將<the connection string>取代為實際的連接字串:{ "ConnectionStrings": { "RedisConnectionString": "<the connection string>" } }在 DI 中註冊 Redis 套件所提供的
IDistributedCache實作。 若要這樣做,請呼叫AddStackExchangeRedisCache,並傳入連接字串。 例如:builder.Services.AddStackExchangeRedisCache(options => { options.Configuration = builder.Configuration.GetConnectionString("RedisConnectionString"); });Redis
IDistributedCache實作現在可從應用程式的 DI 容器取得。HybridCache會使用它作為次要快取,並使用為其設定的序列化程式。
如需詳細資訊,請參閱 HybridCache 序列化範例應用程式。
快取存放區
根據預設,HybridCache 會針對其主要快取儲存體使用 MemoryCache。 快取項目儲存在進程內,因此每部伺服器都有個別的快取,每當伺服器程序重新啟動時就會清除。 針對次要的分散式儲存,例如 Redis、SQL Server 或 Postgres,HybridCache 會使用 已設定的 IDistributedCache 實作(若有配置)。 但是,即使沒有 IDistributedCache實作,HybridCache 服務仍會提供過程中快取和 突發流量保護。
注意
依索引鍵或標記使快取項目失效時,它們會在目前伺服器和次要的進程外儲存中失效。 不過,其他伺服器中的記憶體內部快取不會受到影響。
最佳化效能
若要將效能最佳化,請將 HybridCache 設定為重用物件,並避免 byte[] 分配。
重複利用物件
藉由重複使用執行個體,HybridCache 即可降低與每次呼叫的還原序列化相關聯的 CPU 和物件配置額外負荷。 在快取物件很大或受到頻繁存取的案例中,這可以提高效能。
在使用 IDistributedCache 的一般現有程式碼中,每次從快取中擷取物件都會導致還原序列化。 此行為表示每個並行呼叫者都會取得物件的不同執行個體,而該執行個體無法與其他執行個體互動。 結果是執行緒安全,因為不會有對相同物件執行個體進行並行修改的風險。
由於會根據現有的 HybridCache 程式碼來調整許多 IDistributedCache 使用方式,因此 HybridCache 預設會保留此行為,以避免引進並行錯誤 (bug)。 不過,若符合下列條件,物件本質上就是執行緒安全的:
- 它們是不可變的類型。
- 程式碼不會修改它們。
在這種情況下,請通知 HybridCache 重複使用執行個體是安全的,方法是進行下列兩項變更:
- 將類型標示為
sealed。 C# 中的sealed關鍵字表示無法繼承該類別。 - 將
[ImmutableObject(true)]屬性套用至型別。[ImmutableObject(true)]屬性表示物件的狀態在建立之後即無法變更。
避免 byte[] 分配
HybridCache 也提供選擇性的 IDistributedCache 實作 API,以避免 byte[] 配置。 這項功能是由 Microsoft.Extensions.Caching.StackExchangeRedis、Microsoft.Extensions.Caching.SqlServer 和 Microsoft.Extensions.Caching.Postgres 套件的預覽版本實作的。 如需詳細資訊,請參閱IBufferDistributedCache。
以下是安裝套件的 .NET CLI 命令:
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis
dotnet add package Microsoft.Extensions.Caching.SqlServer
dotnet add package Microsoft.Extensions.Caching.Postgres
自訂 HybridCache 實作
HybridCache 抽象類別的具體實作包含在共用架構中,並透過相依性插入來提供。 但開發人員歡迎提供或取用 API 的自定義實作,例如 FusionCache。
搭配原生 AOT 使用混合式快取
下列原生 AOT 特定考慮適用於 HybridCache:
串行化
原生 AOT 不支援以運行時間反映為基礎的串行化。 如果您快取自定義類型,則必須使用來源產生器,或明確設定與 AOT 相容的序列化器,例如
System.Text.Json的來源產生器。HybridCache仍在開發中,並簡化與 AOT 搭配使用的方式,是該開發的首要任務。 如需詳細資訊,請參閱提取要求 dotnet/extensions#6475修剪
請確保您快取的所有類型,都已被設定為防止 AOT 編譯器修剪。 使用來源產生器進行串行化有助於符合這項需求。 如需詳細資訊,請參閱 ASP.NET 原生 AOT 的核心支援。
如果您正確設定串行化和修剪, HybridCache 在原生 AOT 中的行為方式與一般 ASP.NET Core 應用程式相同。
相容性
HybridCache 程式庫支援舊版 .NET 執行階段,向下至 .NET Framework 4.7.2 和 .NET Standard 2.0。
其他資源
如需詳細資訊,請參閱HybridCache原始程式碼