ASP.NET Core の分散キャッシュ
作成者: Mohsin Nasir、smandia
メモ
これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。
警告
このバージョンの ASP.NET Core はサポート対象から除外されました。 詳細については、「.NET および .NET Core サポート ポリシー」を参照してください。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。
重要
この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。
現在のリリースについては、この記事の .NET 8 バージョンを参照してください。
分散キャッシュは、複数のアプリ サーバーによって共有されるキャッシュであり、通常、それにアクセスするアプリサーバーに対する外部サービスとして保持されます。 分散キャッシュを使用すると、ASP.NET Core アプリのパフォーマンスとスケーラビリティを向上させることができ、アプリがクラウド サービスまたはサーバー ファームでホストされていると特に効果的です。
キャッシュされたデータが個々のアプリ サーバーに格納される他のキャッシュ シナリオと比べて、分散キャッシュにはいくつかの利点があります。
キャッシュされたデータが分散されると、データは次のようになります。
- 複数のサーバーに対する要求の間で "コヒーレント" (一貫したもの) になります。
- サーバーが再起動されたり、アプリがデプロイされたりしても維持されます。
- ローカル メモリを使用しません。
分散キャッシュの構成は実装に固有です。 この記事では、SQL Server と Redis 分散キャッシュを構成する方法について説明します。 NCache (GitHub の NCache) など、サードパーティの実装も利用できます。 どの実装を選んでも、アプリとキャッシュの対話には IDistributedCache インターフェイスを使用します。
サンプル コードを表示またはダウンロードします (ダウンロード方法)。
警告
この記事では、ユーザーの認証を必要としないローカル データベースを使用します。 運用アプリでは、使用可能な最も安全な認証フローを使用する必要があります。 デプロイされたテスト アプリと運用アプリの認証の詳細については、「セキュリティで保護された認証フロー」をご覧ください。
前提条件
次のように、使用する分散キャッシュ プロバイダーのパッケージ参照を追加します。
- Redis の分散キャッシュの場合は、Microsoft.Extensions.Caching.StackExchangeRedis です。
- SQL Server の場合は、Microsoft.Extensions.Caching.SqlServer です。
- NCache の分散キャッシュの場合は、NCache.Microsoft.Extensions.Caching.OpenSource です。
IDistributedCache インターフェイス
IDistributedCache インターフェイスから、分散キャッシュの実装内の項目を操作するための次のメソッドが提供されます。
- Get、GetAsync: 文字列キーを受け取り、キャッシュされた項目がキャッシュ内で見つかった場合は、
byte[]
配列としてそれを取得します。 - Set、SetAsync: 文字列キーを使用して、項目を (
byte[]
配列として) キャッシュに追加します。 - Refresh、RefreshAsync: キャッシュ内の項目をそのキーに基づいて更新し、そのスライド式有効期限のタイムアウトをリセットします (ある場合)。
- Remove、RemoveAsync: キャッシュ項目をその文字列キーに基づいて削除します。
分散キャッシュ サービスを確立する
IDistributedCache の実装を Program.cs
に登録します。 このトピックで説明するフレームワーク提供の実装には、次のものが含まれます。
分散 Redis キャッシュ
実稼働アプリでは、最もパフォーマンスが高い分散 Redis Cache を使用することをお勧めします。 詳細については、「推奨事項」を参照してください。
Redis は、オープンソースのメモリ内データ ストアであり、多くの場合、分散キャッシュとして使用されます。 Azure でホストされる ASP.NET Core アプリ用に Azure Cache for Redis を構成し、ローカル開発に Azure Cache for Redis を使用することができます。
アプリでは、AddStackExchangeRedisCache を呼び出して RedisCache のインスタンスを使用してキャッシュの実装を構成します。 出力キャッシュの場合、AddStackExchangeRedisOutputCache
を使用します。
- Azure Cache for Redis を作成します。
- プライマリ接続文字列 (StackExchange.Redis) を構成にコピーします。
- ローカル開発: シークレット マネージャーで接続文字列を保存します。
- Azure: Azure Key Vault などのセキュリティで保護されたストアに接続文字列を保存する
次のコードにより、Azure Cache for Redis が有効になります。
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = builder.Configuration.GetConnectionString("MyRedisConStr");
options.InstanceName = "SampleInstance";
});
上のコードでは、プライマリ接続文字列 (StackExchange.Redis) は MyRedisConStr
というキー名で構成に保存されていたものと想定されています。
詳細については、「Azure Cache for Redis」を参照してください。
ローカル Redis キャッシュに対する別のアプローチについては、こちらの GitHub イシューをご覧ください。
分散メモリ キャッシュ
分散メモリ キャッシュ (AddDistributedMemoryCache) は、フレームワークによって提供される IDistributedCache の実装であり、項目がメモリに格納されます。 分散メモリ キャッシュは実際の分散キャッシュではありません。 キャッシュされる項目は、アプリが実行されているサーバー上のアプリ インスタンスによって格納されます。
分散メモリ キャッシュは、次のような場合に役に立つ実装です。
- 開発とテストのシナリオ。
- 運用環境で 1 台のサーバーが使用されていて、メモリの消費量が問題ではない場合。 分散メモリ キャッシュを実装すると、キャッシュされたデータ ストレージが抽象化されます。 これにより、後で複数のノードまたはフォールト トレランスが必要になった場合に、真の分散キャッシュ ソリューションを実装できます。
このサンプル アプリでは、Program.cs
の開発環境でアプリが実行されているときに、分散メモリ キャッシュが使用されます。
builder.Services.AddDistributedMemoryCache();
分散 SQL Server キャッシュ
分散 SQL Server キャッシュの実装 (AddDistributedSqlServerCache) では、分散キャッシュで SQL Server データベースをバッキング ストアとして使用できます。 SQL Server のインスタンスに SQL Server のキャッシュ項目テーブルを作成するには、sql-cache
ツールを使用できます。 このツールにより、指定した名前とスキーマでテーブルが作成されます。
sql-cache create
コマンドを実行して、SQL Server にテーブルを作成します。 SQL Server のインスタンス (Data Source
)、データベース (Initial Catalog
)、スキーマ (dbo
など)、テーブル名 (TestCache
など) を指定します。
dotnet sql-cache create "Data Source=(localdb)/MSSQLLocalDB;Initial Catalog=DistCache;Integrated Security=True;" dbo TestCache
ツールが正常に実行されたことを示すメッセージがログに記録されます。
Table and index were created successfully.
sql-cache
ツールによって作成されるテーブルのスキーマは、次のようになります。
Note
アプリでは、SqlServerCache ではなく、IDistributedCache のインスタンスを使用してキャッシュの値を操作する必要があります。
このサンプル アプリでは、Program.cs
の開発以外の環境に SqlServerCache が実装されます。
builder.Services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = builder.Configuration.GetConnectionString(
"DistCache_ConnectionString");
options.SchemaName = "dbo";
options.TableName = "TestCache";
});
メモ
通常、ConnectionString (および必要に応じ SchemaName と TableName) は、ソース管理の外部に格納されます (たとえば、シークレット マネージャーによって、または appsettings.json
/appsettings.{Environment}.json
ファイルに格納されます)。 接続文字列には、ソース管理システムの外部に保持する必要がある資格情報を含めることができます。
分散 NCache キャッシュ
Ncache はオープンソースのメモリ内分散キャッシュであり、.NET および .NET Core でネイティブに開発されました。 NCache は、ローカル環境でも、Azure または他のホスティング プラットフォームで実行される ASP.NET Core アプリ用の分散キャッシュ クラスターとしての構成でも動作します。
ローカル コンピューターに NCache をインストールして構成する方法については、「Windows (.NET および .NET Core) 向け使用開始ガイド」をご覧ください。
NCache を構成するには:
- Ncache オープンソース NuGet をインストールします。
- client.ncconf でキャッシュ クラスターを構成します。
Program.cs
に次のコードを追加します。
builder.Services.AddNCacheDistributedCache(configuration =>
{
configuration.CacheName = "democache";
configuration.EnableLogs = true;
configuration.ExceptionsEnabled = true;
});
分散 Azure CosmosDB キャッシュ
Azure Cosmos DB は、IDistributedCache
インターフェイスを使用することで、ASP.NET Core 内のセッション状態プロバイダーとして使用できます。 Azure Cosmos DB は、フル マネージドの NoSQL およびリレーショナル データベースであり、最新のアプリ開発用に、ミッション クリティカルなアプリケーションの高可用性、スケーラビリティ、データへの低遅延アクセスを提供します。
Microsoft.Extensions.Caching.Cosmos NuGet パッケージをインストールした後、次のように Azure Cosmos DB 分散キャッシュを構成します。
既存のクライアントの再利用
分散キャッシュを構成する最も簡単な方法は、既存の Azure Cosmos DB クライアントを再利用することです。 この場合、プロバイダーが破棄される際も、CosmosClient
インスタンスは破棄されません。
services.AddCosmosCache((CosmosCacheOptions cacheOptions) =>
{
cacheOptions.ContainerName = Configuration["CosmosCacheContainer"];
cacheOptions.DatabaseName = Configuration["CosmosCacheDatabase"];
cacheOptions.CosmosClient = existingCosmosClient;
cacheOptions.CreateIfNotExists = true;
});
新しいクライアントの作成
別の方法としては、新しいクライアントのインスタンスを作成します。 この場合、プロバイダーが破棄されると、CosmosClient
インスタンスも破棄されます。
services.AddCosmosCache((CosmosCacheOptions cacheOptions) =>
{
cacheOptions.ContainerName = Configuration["CosmosCacheContainer"];
cacheOptions.DatabaseName = Configuration["CosmosCacheDatabase"];
cacheOptions.ClientBuilder = new CosmosClientBuilder(Configuration["CosmosConnectionString"]);
cacheOptions.CreateIfNotExists = true;
});
分散キャッシュを使用する
IDistributedCache インターフェイスを使用するには、アプリで IDistributedCache のインスタンスを要求します。 インスタンスは、依存関係の挿入 (DI) によって提供されます。
サンプル アプリが開始すると、IDistributedCache が Program.cs
に挿入されます。 IHostApplicationLifetime を使用して現在の時刻がキャッシュされます (詳しくは、汎用ホストの IHostApplicationLifetime に関するページをご覧ください)。
app.Lifetime.ApplicationStarted.Register(() =>
{
var currentTimeUTC = DateTime.UtcNow.ToString();
byte[] encodedCurrentTimeUTC = System.Text.Encoding.UTF8.GetBytes(currentTimeUTC);
var options = new DistributedCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(20));
app.Services.GetService<IDistributedCache>()
.Set("cachedTimeUTC", encodedCurrentTimeUTC, options);
});
インデックス ページで使用するため、サンプル アプリによって IDistributedCache が IndexModel
に挿入されます。
インデックス ページが読み込まれるたびに、OnGetAsync
でキャッシュのキャッシュ時刻がチェックされます。 キャッシュ時刻が期限切れになっていない場合は、時刻が表示されます。 キャッシュ時刻が最後にアクセスされたとき (このページが最後に読み込まれたとき) から 20 秒経過した場合、ページには "キャッシュ時刻が期限切れになった" ことが表示されます。
[Reset Cached Time]\(キャッシュ時刻のリセット\) ボタンを選んで、キャッシュ時刻を現在の時刻に直ちに更新します。 このボタンにより、OnPostResetCachedTime
ハンドラー メソッドがトリガーされます。
public class IndexModel : PageModel
{
private readonly IDistributedCache _cache;
public IndexModel(IDistributedCache cache)
{
_cache = cache;
}
public string? CachedTimeUTC { get; set; }
public string? ASP_Environment { get; set; }
public async Task OnGetAsync()
{
CachedTimeUTC = "Cached Time Expired";
var encodedCachedTimeUTC = await _cache.GetAsync("cachedTimeUTC");
if (encodedCachedTimeUTC != null)
{
CachedTimeUTC = Encoding.UTF8.GetString(encodedCachedTimeUTC);
}
ASP_Environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
if (String.IsNullOrEmpty(ASP_Environment))
{
ASP_Environment = "Null, so Production";
}
}
public async Task<IActionResult> OnPostResetCachedTime()
{
var currentTimeUTC = DateTime.UtcNow.ToString();
byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC);
var options = new DistributedCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(20));
await _cache.SetAsync("cachedTimeUTC", encodedCurrentTimeUTC, options);
return RedirectToPage();
}
}
組み込み実装の IDistributedCache のインスタンスに対して、シングルトンまたはスコープ設定された有効期間を使用する必要はありません。
また、DI を使用する代わりに、IDistributedCache のインスタンスが必要な場所でそれを作成することもできますが、コードでインスタンスを作成すると、コードのテストが難しくなり、明示的な依存関係の原則に違反する可能性があります。
推奨事項
アプリに最適な IDistributedCache の実装を決定するときは、次の点を考慮してください。
- 既存のインフラストラクチャ
- パフォーマンス要件
- コスト
- チームのエクスペリエンス
通常、キャッシュ ソリューションではキャッシュされたデータの高速取得を実現するためにメモリ内ストレージが利用されますが、メモリは限られたリソースであり、拡張にはコストがかかります。 キャッシュにはよく使用されるデータのみを格納してください。
ほとんどのアプリでは、SQL Server キャッシュより Redis キャッシュの方が、スループットは高く、待機時間は短くなります。 ただし、キャッシュ戦略のパフォーマンス特性を判断するため、ベンチマークが推奨されます。
SQL Server が分散キャッシュのバッキング ストアとして使用されている場合、キャッシュと、アプリの通常のデータ ストレージおよび取得に、同じデータベースを使用すると、パフォーマンスに悪影響を与える可能性があります。 分散キャッシュのバッキング ストアには、専用の SQL Server インスタンスを使用することをお勧めします。
その他の技術情報
- Azure での Redis Cache
- Azure での SQL Database
- Web ファームでの NCache 用 ASP.NET Core IDistributedCache プロバイダー (GitHub での NCache)
- Microsoft.Extensions.Caching.Cosmos のリポジトリ README ファイル
- ASP.NET Core のメモリ内キャッシュ
- ASP.NET Core で変更トークンを使用して変更を検出する
- ASP.NET Core の応答キャッシュ
- ASP.NET Core での応答キャッシュ ミドルウェア
- ASP.NET Core MVC のキャッシュ タグ ヘルパー
- ASP.NET Core の分散キャッシュ タグ ヘルパー
- Web ファームでの ASP.NET Core のホスト
分散キャッシュは、複数のアプリ サーバーによって共有されるキャッシュであり、通常、それにアクセスするアプリサーバーに対する外部サービスとして保持されます。 分散キャッシュを使用すると、ASP.NET Core アプリのパフォーマンスとスケーラビリティを向上させることができ、アプリがクラウド サービスまたはサーバー ファームでホストされていると特に効果的です。
キャッシュされたデータが個々のアプリ サーバーに格納される他のキャッシュ シナリオと比べて、分散キャッシュにはいくつかの利点があります。
キャッシュされたデータが分散されると、データは次のようになります。
- 複数のサーバーに対する要求の間で "コヒーレント" (一貫したもの) になります。
- サーバーが再起動されたり、アプリがデプロイされたりしても維持されます。
- ローカル メモリを使用しません。
分散キャッシュの構成は実装に固有です。 この記事では、SQL Server と Redis 分散キャッシュを構成する方法について説明します。 NCache (GitHub の NCache) など、サードパーティの実装も利用できます。 どの実装を選んでも、アプリとキャッシュの対話には IDistributedCache インターフェイスを使用します。
サンプル コードを表示またはダウンロードします (ダウンロード方法)。
必須コンポーネント
次のように、使用する分散キャッシュ プロバイダーのパッケージ参照を追加します。
Redis の分散キャッシュの場合は、Microsoft.Extensions.Caching.StackExchangeRedis です。
SQL Server の場合は、Microsoft.Extensions.Caching.SqlServer です。
NCache の分散キャッシュの場合は、NCache.Microsoft.Extensions.Caching.OpenSource です。
-
警告
この記事では、ユーザーの認証を必要としないローカル データベースを使用します。 運用アプリでは、使用可能な最も安全な認証フローを使用する必要があります。 デプロイされたテスト アプリと運用アプリの認証の詳細については、「セキュリティで保護された認証フロー」をご覧ください。
IDistributedCache インターフェイス
IDistributedCache インターフェイスから、分散キャッシュの実装内の項目を操作するための次のメソッドが提供されます。
- Get、GetAsync: 文字列キーを受け取り、キャッシュされた項目がキャッシュ内で見つかった場合は、
byte[]
配列としてそれを取得します。 - Set、SetAsync: 文字列キーを使用して、項目を (
byte[]
配列として) キャッシュに追加します。 - Refresh、RefreshAsync: キャッシュ内の項目をそのキーに基づいて更新し、そのスライド式有効期限のタイムアウトをリセットします (ある場合)。
- Remove、RemoveAsync: キャッシュ項目をその文字列キーに基づいて削除します。
分散キャッシュ サービスを確立する
IDistributedCache の実装を Program.cs
に登録します。 このトピックで説明するフレームワーク提供の実装には、次のものが含まれます。
分散 Redis キャッシュ
実稼働アプリでは、最もパフォーマンスが高い分散 Redis Cache を使用することをお勧めします。 詳細については、「推奨事項」を参照してください。
Redis は、オープンソースのメモリ内データ ストアであり、多くの場合、分散キャッシュとして使用されます。 Azure でホストされる ASP.NET Core アプリ用に Azure Redis Cache を構成し、ローカル開発に Azure Redis Cache を使用することができます。
アプリでは、RedisCache のインスタンス (AddStackExchangeRedisCache) を使用してキャッシュの実装を構成します。
- Azure Cache for Redis を作成します。
- プライマリ接続文字列 (StackExchange.Redis) を構成にコピーします。
- ローカル開発: シークレット マネージャーで接続文字列を保存します。
- Azure: Azure Key Vault などのセキュリティで保護されたストアに接続文字列を保存する
次のコードにより、Azure Cache for Redis が有効になります。
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = builder.Configuration.GetConnectionString("MyRedisConStr");
options.InstanceName = "SampleInstance";
});
上のコードでは、プライマリ接続文字列 (StackExchange.Redis) は MyRedisConStr
というキー名で構成に保存されていたものと想定されています。
詳細については、「Azure Cache for Redis」を参照してください。
ローカル Redis キャッシュに対する別のアプローチについては、こちらの GitHub イシューをご覧ください。
分散メモリ キャッシュ
分散メモリ キャッシュ (AddDistributedMemoryCache) は、フレームワークによって提供される IDistributedCache の実装であり、項目がメモリに格納されます。 分散メモリ キャッシュは実際の分散キャッシュではありません。 キャッシュされる項目は、アプリが実行されているサーバー上のアプリ インスタンスによって格納されます。
分散メモリ キャッシュは、次のような場合に役に立つ実装です。
- 開発とテストのシナリオ。
- 運用環境で 1 台のサーバーが使用されていて、メモリの消費量が問題ではない場合。 分散メモリ キャッシュを実装すると、キャッシュされたデータ ストレージが抽象化されます。 これにより、後で複数のノードまたはフォールト トレランスが必要になった場合に、真の分散キャッシュ ソリューションを実装できます。
このサンプル アプリでは、Program.cs
の開発環境でアプリが実行されているときに、分散メモリ キャッシュが使用されます。
builder.Services.AddDistributedMemoryCache();
分散 SQL Server キャッシュ
分散 SQL Server キャッシュの実装 (AddDistributedSqlServerCache) では、分散キャッシュで SQL Server データベースをバッキング ストアとして使用できます。 SQL Server のインスタンスに SQL Server のキャッシュ項目テーブルを作成するには、sql-cache
ツールを使用できます。 このツールにより、指定した名前とスキーマでテーブルが作成されます。
sql-cache create
コマンドを実行して、SQL Server にテーブルを作成します。 SQL Server のインスタンス (Data Source
)、データベース (Initial Catalog
)、スキーマ (dbo
など)、テーブル名 (TestCache
など) を指定します。
dotnet sql-cache create "Data Source=(localdb)/MSSQLLocalDB;Initial Catalog=DistCache;Integrated Security=True;" dbo TestCache
ツールが正常に実行されたことを示すメッセージがログに記録されます。
Table and index were created successfully.
sql-cache
ツールによって作成されるテーブルのスキーマは、次のようになります。
Note
アプリでは、SqlServerCache ではなく、IDistributedCache のインスタンスを使用してキャッシュの値を操作する必要があります。
このサンプル アプリでは、Program.cs
の開発以外の環境に SqlServerCache が実装されます。
builder.Services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = builder.Configuration.GetConnectionString(
"DistCache_ConnectionString");
options.SchemaName = "dbo";
options.TableName = "TestCache";
});
メモ
通常、ConnectionString (および必要に応じ SchemaName と TableName) は、ソース管理の外部に格納されます (たとえば、シークレット マネージャーによって、または appsettings.json
/appsettings.{Environment}.json
ファイルに格納されます)。 接続文字列には、ソース管理システムの外部に保持する必要がある資格情報を含めることができます。
分散 NCache キャッシュ
Ncache はオープンソースのメモリ内分散キャッシュであり、.NET および .NET Core でネイティブに開発されました。 NCache は、ローカル環境でも、Azure または他のホスティング プラットフォームで実行される ASP.NET Core アプリ用の分散キャッシュ クラスターとしての構成でも動作します。
ローカル コンピューターに NCache をインストールして構成する方法については、「Windows (.NET および .NET Core) 向け使用開始ガイド」をご覧ください。
NCache を構成するには:
- Ncache オープンソース NuGet をインストールします。
- client.ncconf でキャッシュ クラスターを構成します。
Program.cs
に次のコードを追加します。
builder.Services.AddNCacheDistributedCache(configuration =>
{
configuration.CacheName = "democache";
configuration.EnableLogs = true;
configuration.ExceptionsEnabled = true;
});
分散キャッシュを使用する
IDistributedCache インターフェイスを使用するには、アプリで IDistributedCache のインスタンスを要求します。 インスタンスは、依存関係の挿入 (DI) によって提供されます。
サンプル アプリが開始すると、IDistributedCache が Program.cs
に挿入されます。 IHostApplicationLifetime を使用して現在の時刻がキャッシュされます (詳しくは、汎用ホストの IHostApplicationLifetime に関するページをご覧ください)。
app.Lifetime.ApplicationStarted.Register(() =>
{
var currentTimeUTC = DateTime.UtcNow.ToString();
byte[] encodedCurrentTimeUTC = System.Text.Encoding.UTF8.GetBytes(currentTimeUTC);
var options = new DistributedCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(20));
app.Services.GetService<IDistributedCache>()
.Set("cachedTimeUTC", encodedCurrentTimeUTC, options);
});
インデックス ページで使用するため、サンプル アプリによって IDistributedCache が IndexModel
に挿入されます。
インデックス ページが読み込まれるたびに、OnGetAsync
でキャッシュのキャッシュ時刻がチェックされます。 キャッシュ時刻が期限切れになっていない場合は、時刻が表示されます。 キャッシュ時刻が最後にアクセスされたとき (このページが最後に読み込まれたとき) から 20 秒経過した場合、ページには "キャッシュ時刻が期限切れになった" ことが表示されます。
[Reset Cached Time]\(キャッシュ時刻のリセット\) ボタンを選んで、キャッシュ時刻を現在の時刻に直ちに更新します。 このボタンにより、OnPostResetCachedTime
ハンドラー メソッドがトリガーされます。
public class IndexModel : PageModel
{
private readonly IDistributedCache _cache;
public IndexModel(IDistributedCache cache)
{
_cache = cache;
}
public string? CachedTimeUTC { get; set; }
public string? ASP_Environment { get; set; }
public async Task OnGetAsync()
{
CachedTimeUTC = "Cached Time Expired";
var encodedCachedTimeUTC = await _cache.GetAsync("cachedTimeUTC");
if (encodedCachedTimeUTC != null)
{
CachedTimeUTC = Encoding.UTF8.GetString(encodedCachedTimeUTC);
}
ASP_Environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
if (String.IsNullOrEmpty(ASP_Environment))
{
ASP_Environment = "Null, so Production";
}
}
public async Task<IActionResult> OnPostResetCachedTime()
{
var currentTimeUTC = DateTime.UtcNow.ToString();
byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC);
var options = new DistributedCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(20));
await _cache.SetAsync("cachedTimeUTC", encodedCurrentTimeUTC, options);
return RedirectToPage();
}
}
組み込み実装の IDistributedCache のインスタンスに対して、シングルトンまたはスコープ設定された有効期間を使用する必要はありません。
また、DI を使用する代わりに、IDistributedCache のインスタンスが必要な場所でそれを作成することもできますが、コードでインスタンスを作成すると、コードのテストが難しくなり、明示的な依存関係の原則に違反する可能性があります。
推奨事項
アプリに最適な IDistributedCache の実装を決定するときは、次の点を考慮してください。
- 既存のインフラストラクチャ
- パフォーマンス要件
- コスト
- チームのエクスペリエンス
通常、キャッシュ ソリューションではキャッシュされたデータの高速取得を実現するためにメモリ内ストレージが利用されますが、メモリは限られたリソースであり、拡張にはコストがかかります。 キャッシュにはよく使用されるデータのみを格納してください。
ほとんどのアプリでは、SQL Server キャッシュより Redis キャッシュの方が、スループットは高く、待機時間は短くなります。 ただし、キャッシュ戦略のパフォーマンス特性を判断するため、ベンチマークが推奨されます。
SQL Server が分散キャッシュのバッキング ストアとして使用されている場合、キャッシュと、アプリの通常のデータ ストレージおよび取得に、同じデータベースを使用すると、パフォーマンスに悪影響を与える可能性があります。 分散キャッシュのバッキング ストアには、専用の SQL Server インスタンスを使用することをお勧めします。
その他の技術情報
- Azure での Redis Cache
- Azure での SQL Database
- Web ファームでの NCache 用 ASP.NET Core IDistributedCache プロバイダー (GitHub での NCache)
- ASP.NET Core のメモリ内キャッシュ
- ASP.NET Core で変更トークンを使用して変更を検出する
- ASP.NET Core の応答キャッシュ
- ASP.NET Core での応答キャッシュ ミドルウェア
- ASP.NET Core MVC のキャッシュ タグ ヘルパー
- ASP.NET Core の分散キャッシュ タグ ヘルパー
- Web ファームでの ASP.NET Core のホスト
分散キャッシュは、複数のアプリ サーバーによって共有されるキャッシュであり、通常、それにアクセスするアプリサーバーに対する外部サービスとして保持されます。 分散キャッシュを使用すると、ASP.NET Core アプリのパフォーマンスとスケーラビリティを向上させることができ、アプリがクラウド サービスまたはサーバー ファームでホストされていると特に効果的です。
キャッシュされたデータが個々のアプリ サーバーに格納される他のキャッシュ シナリオと比べて、分散キャッシュにはいくつかの利点があります。
キャッシュされたデータが分散されると、データは次のようになります。
- 複数のサーバーに対する要求の間で "コヒーレント" (一貫したもの) になります。
- サーバーが再起動されたり、アプリがデプロイされたりしても維持されます。
- ローカル メモリを使用しません。
分散キャッシュの構成は実装に固有です。 この記事では、SQL Server と Redis 分散キャッシュを構成する方法について説明します。 NCache (GitHub の NCache) など、サードパーティの実装も利用できます。 どの実装を選んでも、アプリとキャッシュの対話には IDistributedCache インターフェイスを使用します。
サンプル コードを表示またはダウンロードします (ダウンロード方法)。
必須コンポーネント
SQL Server の分散キャッシュを使用するには、Microsoft.Extensions.Caching.SqlServer パッケージへのパッケージ参照を追加します。
Redis の分散キャッシュを使用するには、Microsoft.Extensions.Caching.StackExchangeRedis パッケージへのパッケージ参照を追加します。
NCache の分散キャッシュを使用するには、NCache.Microsoft.Extensions.Caching.OpenSource パッケージへのパッケージ参照を追加します。
IDistributedCache インターフェイス
IDistributedCache インターフェイスから、分散キャッシュの実装内の項目を操作するための次のメソッドが提供されます。
- Get、GetAsync: 文字列キーを受け取り、キャッシュされた項目がキャッシュ内で見つかった場合は、
byte[]
配列としてそれを取得します。 - Set、SetAsync: 文字列キーを使用して、項目を (
byte[]
配列として) キャッシュに追加します。 - Refresh、RefreshAsync: キャッシュ内の項目をそのキーに基づいて更新し、そのスライド式有効期限のタイムアウトをリセットします (ある場合)。
- Remove、RemoveAsync: キャッシュ項目をその文字列キーに基づいて削除します。
分散キャッシュ サービスを確立する
IDistributedCache の実装を Startup.ConfigureServices
に登録します。 このトピックで説明するフレームワーク提供の実装には、次のものが含まれます。
分散メモリ キャッシュ
分散メモリ キャッシュ (AddDistributedMemoryCache) は、フレームワークによって提供される IDistributedCache の実装であり、項目がメモリに格納されます。 分散メモリ キャッシュは実際の分散キャッシュではありません。 キャッシュされる項目は、アプリが実行されているサーバー上のアプリ インスタンスによって格納されます。
分散メモリ キャッシュは、次のような場合に役に立つ実装です。
- 開発とテストのシナリオ。
- 運用環境で 1 台のサーバーが使用されていて、メモリの消費量が問題ではない場合。 分散メモリ キャッシュを実装すると、キャッシュされたデータ ストレージが抽象化されます。 これにより、後で複数のノードまたはフォールト トレランスが必要になった場合に、真の分散キャッシュ ソリューションを実装できます。
このサンプル アプリでは、Startup.ConfigureServices
の開発環境でアプリが実行されているときに、分散メモリ キャッシュが使用されます。
services.AddDistributedMemoryCache();
分散 SQL Server キャッシュ
分散 SQL Server キャッシュの実装 (AddDistributedSqlServerCache) では、分散キャッシュで SQL Server データベースをバッキング ストアとして使用できます。 SQL Server のインスタンスに SQL Server のキャッシュ項目テーブルを作成するには、sql-cache
ツールを使用できます。 このツールにより、指定した名前とスキーマでテーブルが作成されます。
sql-cache create
コマンドを実行して、SQL Server にテーブルを作成します。 SQL Server のインスタンス (Data Source
)、データベース (Initial Catalog
)、スキーマ (dbo
など)、テーブル名 (TestCache
など) を指定します。
dotnet sql-cache create "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=DistCache;Integrated Security=True;" dbo TestCache
ツールが正常に実行されたことを示すメッセージがログに記録されます。
Table and index were created successfully.
sql-cache
ツールによって作成されるテーブルのスキーマは、次のようになります。
Note
アプリでは、SqlServerCache ではなく、IDistributedCache のインスタンスを使用してキャッシュの値を操作する必要があります。
このサンプル アプリでは、Startup.ConfigureServices
の開発以外の環境に SqlServerCache が実装されます。
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString =
_config["DistCache_ConnectionString"];
options.SchemaName = "dbo";
options.TableName = "TestCache";
});
メモ
通常、ConnectionString (および必要に応じ SchemaName と TableName) は、ソース管理の外部に格納されます (たとえば、シークレット マネージャーによって、または appsettings.json
/appsettings.{Environment}.json
ファイルに格納されます)。 接続文字列には、ソース管理システムの外部に保持する必要がある資格情報を含めることができます。
分散 Redis キャッシュ
Redis は、オープンソースのメモリ内データ ストアであり、多くの場合、分散キャッシュとして使用されます。 Azure でホストされる ASP.NET Core アプリ用に Azure Redis Cache を構成し、ローカル開発に Azure Redis Cache を使用することができます。
アプリでは、RedisCache のインスタンス (AddStackExchangeRedisCache) を使用してキャッシュの実装を構成します。
- Azure Cache for Redis を作成します。
- プライマリ接続文字列 (StackExchange.Redis) を構成にコピーします。
- ローカル開発: シークレット マネージャーで接続文字列を保存します。
- Azure: Azure Key Vault などのセキュリティで保護されたストアに接続文字列を保存する
次のコードにより、Azure Cache for Redis が有効になります。
public void ConfigureServices(IServiceCollection services)
{
if (_hostContext.IsDevelopment())
{
services.AddDistributedMemoryCache();
}
else
{
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = _config["MyRedisConStr"];
options.InstanceName = "SampleInstance";
});
}
services.AddRazorPages();
}
上のコードでは、プライマリ接続文字列 (StackExchange.Redis) は MyRedisConStr
というキー名で構成に保存されていたものと想定されています。
詳細については、「Azure Cache for Redis」を参照してください。
ローカル Redis キャッシュに対する別のアプローチについては、こちらの GitHub イシューをご覧ください。
分散 NCache キャッシュ
Ncache はオープンソースのメモリ内分散キャッシュであり、.NET および .NET Core でネイティブに開発されました。 NCache は、ローカル環境でも、Azure または他のホスティング プラットフォームで実行される ASP.NET Core アプリ用の分散キャッシュ クラスターとしての構成でも動作します。
ローカル コンピューターに NCache をインストールして構成する方法については、「Windows (.NET および .NET Core) 向け使用開始ガイド」をご覧ください。
NCache を構成するには:
Ncache オープンソース NuGet をインストールします。
client.ncconf でキャッシュ クラスターを構成します。
Startup.ConfigureServices
に次のコードを追加します。services.AddNCacheDistributedCache(configuration => { configuration.CacheName = "demoClusteredCache"; configuration.EnableLogs = true; configuration.ExceptionsEnabled = true; });
分散キャッシュを使用する
IDistributedCache インターフェイスを使用するには、アプリの任意のコンストラクターから IDistributedCache のインスタンスを要求します。 インスタンスは、依存関係の挿入 (DI) によって提供されます。
サンプル アプリが開始すると、IDistributedCache が Startup.Configure
に挿入されます。 IHostApplicationLifetime を使用して現在の時刻がキャッシュされます (詳しくは、汎用ホストの IHostApplicationLifetime に関するページをご覧ください)。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env,
IHostApplicationLifetime lifetime, IDistributedCache cache)
{
lifetime.ApplicationStarted.Register(() =>
{
var currentTimeUTC = DateTime.UtcNow.ToString();
byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC);
var options = new DistributedCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(20));
cache.Set("cachedTimeUTC", encodedCurrentTimeUTC, options);
});
インデックス ページで使用するため、サンプル アプリによって IDistributedCache が IndexModel
に挿入されます。
インデックス ページが読み込まれるたびに、OnGetAsync
でキャッシュのキャッシュ時刻がチェックされます。 キャッシュ時刻が期限切れになっていない場合は、時刻が表示されます。 キャッシュ時刻が最後にアクセスされたとき (このページが最後に読み込まれたとき) から 20 秒経過した場合、ページには "キャッシュ時刻が期限切れになった" ことが表示されます。
[Reset Cached Time]\(キャッシュ時刻のリセット\) ボタンを選んで、キャッシュ時刻を現在の時刻に直ちに更新します。 このボタンにより、OnPostResetCachedTime
ハンドラー メソッドがトリガーされます。
public class IndexModel : PageModel
{
private readonly IDistributedCache _cache;
public IndexModel(IDistributedCache cache)
{
_cache = cache;
}
public string CachedTimeUTC { get; set; }
public async Task OnGetAsync()
{
CachedTimeUTC = "Cached Time Expired";
var encodedCachedTimeUTC = await _cache.GetAsync("cachedTimeUTC");
if (encodedCachedTimeUTC != null)
{
CachedTimeUTC = Encoding.UTF8.GetString(encodedCachedTimeUTC);
}
}
public async Task<IActionResult> OnPostResetCachedTime()
{
var currentTimeUTC = DateTime.UtcNow.ToString();
byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC);
var options = new DistributedCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(20));
await _cache.SetAsync("cachedTimeUTC", encodedCurrentTimeUTC, options);
return RedirectToPage();
}
}
メモ
IDistributedCache のインスタンスに対して、シングルトンまたはスコープ設定された有効期間を使用する必要はありません (少なくとも組み込み実装の場合)。
また、DI を使用する代わりに、IDistributedCache のインスタンスが必要な場所でそれを作成することもできますが、コードでインスタンスを作成すると、コードのテストが難しくなり、明示的な依存関係の原則に違反する可能性があります。
推奨事項
アプリに最適な IDistributedCache の実装を決定するときは、次の点を考慮してください。
- 既存のインフラストラクチャ
- パフォーマンス要件
- コスト
- チームのエクスペリエンス
通常、キャッシュ ソリューションではキャッシュされたデータの高速取得を実現するためにメモリ内ストレージが利用されますが、メモリは限られたリソースであり、拡張にはコストがかかります。 キャッシュにはよく使用されるデータのみを格納してください。
一般に、SQL Server キャッシュより Redis キャッシュの方が、スループットは高く、待機時間は短くなります。 ただし、通常は、キャッシュ戦略のパフォーマンス特性を判断するためにベンチマークが必要です。
SQL Server が分散キャッシュのバッキング ストアとして使用されている場合、キャッシュと、アプリの通常のデータ ストレージおよび取得に、同じデータベースを使用すると、パフォーマンスに悪影響を与える可能性があります。 分散キャッシュのバッキング ストアには、専用の SQL Server インスタンスを使用することをお勧めします。
その他の技術情報
- Azure での Redis Cache
- Azure での SQL Database
- Web ファームでの NCache 用 ASP.NET Core IDistributedCache プロバイダー (GitHub での NCache)
- ASP.NET Core のメモリ内キャッシュ
- ASP.NET Core で変更トークンを使用して変更を検出する
- ASP.NET Core の応答キャッシュ
- ASP.NET Core での応答キャッシュ ミドルウェア
- ASP.NET Core MVC のキャッシュ タグ ヘルパー
- ASP.NET Core の分散キャッシュ タグ ヘルパー
- Web ファームでの ASP.NET Core のホスト
ASP.NET Core