High-Performance Distributed Caching with .NET and Postgres on Azureとは?Azureで使う判断基準と実装ポイント

「High-Performance Distributed Caching with .NET and Postgres on Azure」は、Azure上の.NETアプリで、Postgresを分散キャッシュとして使いながら、HybridCacheでメモリ内キャッシュも組み合わせる実装パターンを整理した公式ウォークスルーです。結論から言うと、これは「Redisを置き換える新標準」というより、すでにAzure Database for PostgreSQLを使っている.NETアプリに、低遅延・負荷削減・運用のシンプルさを足す現実的な選択肢として読むべき更新です。

特に、外部API呼び出し、重い集計処理、マスターデータ取得、複数インスタンス構成のWeb APIを運用している開発者や管理者にとって、今回の内容はそのまま設計レビューに使えます。Microsoftの公式記事は2026年4月28日に公開され、.NET 10のコンソールアプリを題材に、Azure Database for PostgreSQLへ分散キャッシュを保存し、HybridCacheでメモリ内キャッシュと組み合わせる流れを示しています。(Microsoft for Developers)

目次

High-Performance Distributed Caching with .NET and Postgres on Azureで何が変わったか

今回の更新で重要なのは、「Postgresをキャッシュの保存先として使える」という一点だけではありません。ポイントは、.NETアプリのキャッシュ設計を、より実務に近い形で段階的に組み立てていることです。

公式ウォークスルーでは、次の流れが示されています。

観点内容
アプリ構成.NET Generic Hostを使い、構成、DI、ログ、バックグラウンドサービスを整理
キャッシュ保存先Azure Database for PostgreSQLに分散キャッシュ値を保存
キャッシュ方式Microsoft.Extensions.Caching.PostgresとMicrosoft.Extensions.Caching.Hybridを使用
パフォーマンス確認Stopwatchでキャッシュなし、メモリ内ヒット、分散キャッシュヒットの差を確認
運用面appsettings、User Secrets、環境変数、Key Vaultなどを意識した構成

公式記事では、Microsoft.Extensions.Caching.PostgresがPostgresに分散キャッシュを永続化し、Microsoft.Extensions.Caching.Hybridが高速なメモリ内キャッシュと分散キャッシュを組み合わせる役割として紹介されています。(Microsoft for Developers)

つまり、今回の読みどころは「キャッシュを入れると速くなる」という一般論ではなく、Azure上の.NETアプリで、キャッシュ層をどこに置き、どのようにDIへ登録し、どのように期限切れや接続情報を扱うかまで具体化されている点です。

仕組みを簡単に整理する:HybridCacheとPostgresの役割

今回の構成では、HybridCacheがキャッシュ利用の入口になります。アプリケーションコードからはHybridCacheに問い合わせ、裏側ではメモリ内キャッシュとPostgresベースの分散キャッシュが使われます。

処理の流れは次のように考えると理解しやすくなります。

状態何が起きるか期待できる効果
初回アクセスキャッシュに値がないため、外部APIやDBなど本来のデータ取得元を呼び出す通常の処理時間がかかる
メモリ内キャッシュヒットアプリプロセス内のキャッシュから返す最も高速。頻繁なアクセスに向く
メモリ期限切れ、分散キャッシュ有効Postgres上の分散キャッシュから返すアプリ再起動や複数インスタンスでも値を共有しやすい
両方期限切れ再び本来のデータ取得元を呼び出す最新データを再取得できる

公式記事のデモでは、ローカルのメモリ内キャッシュを3秒、Postgres側の分散キャッシュを6秒で期限切れにする設定が使われています。これは挙動を観察しやすくするための短い値であり、本番環境ではデータの更新頻度や業務要件に合わせて設計する必要があります。(Microsoft for Developers)

重要なのは、メモリ内キャッシュだけに依存しないことです。メモリ内キャッシュは非常に速い一方で、アプリの再起動やスケールアウト時にインスタンス間で共有されません。分散キャッシュは複数アプリサーバーで共有され、クラウドやサーバーファーム環境でパフォーマンスとスケーラビリティを高める用途に向いています。(Microsoft Learn)

どのキャッシュ方式を選ぶべきか

Postgresを分散キャッシュに使えるからといって、すべてのシステムでPostgresキャッシュが最適とは限りません。実務では、速度、運用負荷、既存構成、コスト、可用性を見て選びます。

選択肢向いているケース注意点
メモリ内キャッシュ単一インスタンス、短時間だけ保持したいデータ、極低遅延が必要な処理再起動で消える。複数インスタンス間で共有できない
Postgres分散キャッシュすでにPostgresを使っている.NETアプリ、運用サービス数を増やしたくない構成キャッシュアクセスがPostgresの負荷になるため監視が必要
HybridCache + Postgresメモリの速さと分散キャッシュの共有性を両立したいAPIやバックエンドキー設計、期限設計、シリアル化設計が重要
Azure Cache for Redis高頻度アクセス、低遅延重視、大規模な専用キャッシュ基盤が必要な場合別サービスとしての運用、コスト、接続管理が必要

Microsoft Learnでは、分散キャッシュは複数サーバーで共有されるキャッシュとして説明されており、クラウドやサーバーファームで特に有効とされています。また、実稼働アプリで高性能な分散キャッシュが必要な場合の選択肢としてRedisも示されています。(Microsoft Learn)

そのため、今回のPostgresキャッシュは「Redis不要論」ではなく、Postgresをすでに中核データ基盤として使っているチームが、追加サービスを増やさずに分散キャッシュを導入する選択肢と捉えるのが自然です。

実装の流れ:まず何をすればよいか

公式記事の実装は、コンソールアプリを題材にしていますが、考え方はWeb API、バックグラウンドワーカー、非同期処理基盤にも応用できます。

必要なパッケージを追加する

まず、Postgres分散キャッシュとHybridCacheのパッケージを追加します。

dotnet add package Microsoft.Extensions.Caching.Postgres
dotnet add package Microsoft.Extensions.Caching.Hybrid

Microsoft.Extensions.Caching.PostgresはPostgreSQLを使った.NET向け分散キャッシュ実装として公開されており、READMEでもNuGetパッケージの追加方法と構成例が示されています。(GitHub)

appsettingsでキャッシュ設定を分離する

キャッシュ設定はコードに直書きせず、環境ごとに差し替えられる形にします。

{
  "PostgresCache": {
    "SchemaName": "public",
    "TableName": "cache",
    "CreateIfNotExists": true,
    "UseWAL": false,
    "ExpiredItemsDeletionInterval": "00:30:00",
    "DefaultSlidingExpiration": "00:20:00"
  }
}

Postgresキャッシュの設定項目には、スキーマ名、テーブル名、テーブル作成有無、WAL利用、期限切れアイテムの削除間隔、既定のスライド有効期限などがあります。(GitHub)

本番環境では、CreateIfNotExistsを安易に有効化するより、マイグレーションやIaCでテーブル作成を管理する方が安全です。開発環境では便利ですが、本番でアプリ起動時にスキーマ変更が走る設計は、権限管理やリリース管理の観点で問題になりやすいためです。

接続文字列はソースコードに入れない

公式記事では開発時にUser Secretsを使う例が示されていますが、本番環境では環境変数やAzure Key Vaultなどのシークレット管理を使うことが推奨されています。接続文字列、パスワード、キーをリポジトリへコミットしないことは必須です。(Microsoft for Developers)

開発環境では次のようにUser Secretsへ保存できます。

dotnet user-secrets init
dotnet user-secrets set "ConnectionStrings:PostgresCache" "Host=...;Port=5432;Username=...;Password=...;Database=...;"

運用では、少なくとも次の分離を意識します。

環境推奨される扱い
ローカル開発User Secrets、ローカル用の限定権限ユーザー
検証環境環境変数、Key Vault、検証用Postgres
本番環境Key Vault、マネージドID、最小権限、監査ログ

DIにPostgres分散キャッシュとHybridCacheを登録する

サービス登録では、Postgresの分散キャッシュを登録したうえで、HybridCacheを追加します。

builder.Services.AddDistributedPostgresCache(options =>
{
    options.ConnectionString = builder.Configuration.GetConnectionString("PostgresCache");
    options.SchemaName = builder.Configuration.GetValue<string>("PostgresCache:SchemaName", "public");
    options.TableName = builder.Configuration.GetValue<string>("PostgresCache:TableName", "cache");
    options.CreateIfNotExists = builder.Configuration.GetValue<bool>("PostgresCache:CreateIfNotExists", false);
});

builder.Services.AddHybridCache();

公式記事では、services.AddHybridCache()を追加することで、メモリ内キャッシュと分散キャッシュを組み合わせる構成が紹介されています。(Microsoft for Developers)

GetOrCreateAsyncでキャッシュミス時の処理を書く

実際の利用では、GetOrCreateAsyncを使うと「キャッシュにあれば返す。なければ取得して保存する」という流れを簡潔に書けます。

var result = await cache.GetOrCreateAsync(
    $"weather:forecast:{region}",
    async token => await weatherService.GetForecastAsync(region, token),
    cancellationToken: cancellationToken
);

HybridCacheのドキュメントでも、GetOrCreateAsyncの主なオーバーロードが一般的なシナリオで推奨されており、キャッシュキーは対象データを一意に識別できる必要があると説明されています。(Microsoft Learn)

キャッシュキー設計で失敗しやすいポイント

キャッシュ導入で最も多い失敗は、「保存するかどうか」ではなく「何をキーにするか」です。キーが曖昧だと、別ユーザーのデータを返す、古い条件の検索結果を返す、キャッシュが増えすぎるといった問題が起きます。

避けるべきキーの例は次の通りです。

// 悪い例:条件が曖昧
"search-result"

// 悪い例:外部入力をそのまま使う
$"search:{rawQuery}"

改善例は次のようになります。

$"search:v1:tenant:{tenantId}:locale:{locale}:hash:{queryHash}"

キーには、少なくとも次の要素を検討します。

要素例理由
データ種別product, user-profile, weather異なるデータの衝突を防ぐ
バージョンv1, v2仕様変更時に古いキャッシュを自然に切り離す
テナントtenant:{tenantId}マルチテナントでの混在を防ぐ
ユーザー・権限user:{userId}個人化データの誤配信を防ぐ
条件region:{region}, lang:{locale}検索条件や表示条件の違いを反映する

Microsoft Learnでも、キャッシュキーには一意性が必要であり、外部ユーザー入力を直接キーに使うと、無意味なキーの氾濫やセキュリティリスクにつながる可能性があると説明されています。(Microsoft Learn)

有効期限は「短ければ安全」ではない

キャッシュの有効期限は、短すぎても長すぎても問題になります。短すぎるとキャッシュヒット率が上がらず、長すぎると古いデータを返し続けます。

実務では、データの性質ごとに考えるのが効果的です。

データの種類期限設計の目安補足
変更頻度の低いマスターデータ数分〜数十分更新時に明示削除できると安定する
外部APIの取得結果API制限やSLAに合わせるレート制限対策として有効
商品価格・在庫短め、またはイベントで無効化古い情報の影響が大きい
ユーザー設定数十秒〜数分更新後にRemoveAsyncで削除する
権限・認可情報慎重に短く設計誤った権限判定を避ける

HybridCacheでは、グローバルな既定値をAddHybridCacheで設定でき、個別のGetOrCreateAsync呼び出しでHybridCacheEntryOptionsを渡して上書きすることもできます。ドキュメントでは、ExpirationとLocalCacheExpirationを使った設定例も示されています。(Microsoft Learn)

注意したいのは、メモリ内キャッシュと分散キャッシュの期限を同じにする必要はないことです。たとえば、メモリ内キャッシュは短く、分散キャッシュは少し長くすることで、プロセス内では高速に返しつつ、再起動やスケールアウト時にもPostgres側のキャッシュを活用できます。

更新・削除の設計を先に決めておく

キャッシュは「保存する」より「消す」方が難しい仕組みです。データが変わったときにキャッシュをどう扱うかを決めずに導入すると、障害対応時に原因追跡が難しくなります。

HybridCacheでは、期限切れ前に元データが変わった場合、キーを指定してRemoveAsyncを呼ぶことでキャッシュエントリを明示的に削除できます。削除時にはプライマリとセカンダリの両方のキャッシュから削除されます。(Microsoft Learn)

たとえば、商品情報を更新した直後に次のような削除処理を入れます。

await cache.RemoveAsync($"product:v1:{productId}", cancellationToken);

また、HybridCacheにはタグによる無効化もあります。ただし、タグベースの無効化は論理的な操作であり、値そのものが即座に物理削除されるとは限りません。大量のタグを付けるとパフォーマンスに影響する可能性もあります。(Microsoft Learn)

Postgresをキャッシュに使うときの運用注意点

Azure Database for PostgreSQLを分散キャッシュとして使う場合、運用はシンプルになりますが、無条件に負荷が消えるわけではありません。キャッシュの読み書きはPostgresへのアクセスになるため、通常のアプリデータと同じPostgresを使う場合は、負荷の分離と監視が重要です。

特に次の項目は導入前に確認してください。

確認項目見るべきポイント
接続数アプリのスケールアウト時にPostgres接続数が増えすぎないか
テーブル肥大化期限切れキャッシュが適切に削除されているか
I/O負荷キャッシュの高頻度アクセスで通常クエリが遅くならないか
可用性Postgres障害時にアプリがどう振る舞うか
リージョンアプリとPostgresの距離が遅延を増やしていないか
コストキャッシュ用途の読み書きでDBコストが増えないか

ExpiredItemsDeletionIntervalは期限切れアイテムの削除間隔に関わります。短くすれば掃除は早くなりますが、削除処理の頻度が増えます。長くすれば掃除の負荷は下がりますが、不要なデータが残りやすくなります。サービスのアクセス量や保存件数を見ながら調整する項目です。

UseWALについても、単にオン・オフで決めるのではなく、耐久性、レプリケーション、障害復旧、キャッシュデータの扱いを踏まえて検証する必要があります。キャッシュは「失われても再取得できるデータ」であるべきですが、障害時の動作はアプリ側で確認しておくべきです。

キャッシュすべきデータ、してはいけないデータ

キャッシュは万能ではありません。むしろ、向かないデータをキャッシュすると、障害や情報漏えいの原因になります。

キャッシュに向いているデータ

次のようなデータは、キャッシュ効果が出やすい対象です。

データ理由
外部APIの応答レイテンシ削減とレート制限対策になる
変更頻度の低いマスターデータ古い値のリスクが低く、ヒット率が高い
重い集計結果DB負荷を下げやすい
設定値・Feature Flagの一部短いTTLなら反映遅延を制御しやすい
同一条件で繰り返される検索結果条件をキー化しやすい

キャッシュに慎重になるべきデータ

一方で、次のデータは慎重に扱います。

データ注意点
認可・権限情報古い権限を返すと重大な問題になる
個人情報を含むレスポンスキー設計ミスで別ユーザーへ返るリスクがある
在庫・決済・残高正確性が最優先。TTLだけに頼らない
巨大なオブジェクトシリアル化コストやサイズ制限に注意
一度しか読まれないデータキャッシュしても効果が薄い

HybridCacheにはサイズやキー長の制限もあります。ドキュメントでは、既定の最大ペイロードが1MB、最大キー長が1,024文字と説明されています。制限を超える値はキャッシュに保存されないため、大きなレスポンスをそのまま保存する設計は避けるべきです。(Microsoft Learn)

実務で導入する前のチェックリスト

Postgres分散キャッシュとHybridCacheを導入する前に、次の質問に答えられる状態にしておくと、設計の失敗を避けやすくなります。

チェック項目判断基準
何を高速化したいか外部API、DB集計、検索、マスターデータなど対象を明確にする
キャッシュミス時の処理時間はどれくらいか遅い処理ほど効果が出やすい
同じキーで何回読まれるか再利用されないデータはキャッシュ効果が薄い
どれくらい古くても許容できるかTTL設計の根拠になる
更新時に削除できるかRemoveAsyncやタグ無効化の設計が必要
キーにテナント・ユーザー・条件を含めたかデータ混在を防ぐ
Postgresへの負荷を監視できるかCPU、I/O、接続数、テーブルサイズを見る
障害時の動作を決めたかキャッシュなしで本来の取得元へ戻れるか
シークレット管理は安全かKey Vaultや環境変数を使う
Redisとの比較をしたか超低遅延や大規模用途では専用キャッシュも検討する

このチェックリストで半分以上が曖昧なら、まず小さな対象から始めるのが安全です。たとえば「天気情報」「商品カテゴリ」「外部APIの参照結果」のように、更新頻度が低く、キャッシュミス時の処理が重く、誤配信リスクが低いデータを選びます。

Microsoft ecosystem readersが注目すべき意味

今回の公式更新は、Azure、.NET、Postgres、HybridCacheが実務的に接続された点で重要です。Microsoft ecosystemの開発者や管理者にとっては、単なるサンプルではなく、次のような判断材料になります。

まず、.NETの標準的なDI、構成、ログの流れに沿ってキャッシュを組み込めます。特別な独自フレームワークを覚えるのではなく、Generic HostやMicrosoft.Extensions.*の流儀で実装できます。

次に、Azure Database for PostgreSQLをすでに使っている環境では、キャッシュ用に新しい専用サービスを増やす前に、Postgres分散キャッシュを検証する余地があります。もちろん、アクセス頻度が非常に高い場合や専用キャッシュ基盤が必要な場合はRedisなどの比較が必要ですが、運用のシンプルさを重視するチームには有力な選択肢です。

さらに、HybridCacheにより、アプリ内の高速なメモリキャッシュと、複数インスタンスで共有しやすい分散キャッシュを同じ入口から扱えるようになります。これは、Web API、バックグラウンドジョブ、マイクロサービス、非同期処理のいずれにも応用しやすい考え方です。

まずは小さく試し、数値で判断する

High-Performance Distributed Caching with .NET and Postgres on Azureを読むときは、「Postgresキャッシュを入れるべきか」ではなく、自分のアプリのどの処理に、どの期限で、どのキー設計で入れると効果が出るかを考えることが大切です。

最初の一歩としては、次の順番がおすすめです。

  1. 遅い処理をログやAPMで特定する
  2. 同じ条件で繰り返し読まれるデータを選ぶ
  3. キャッシュキーとTTLを設計する
  4. HybridCacheでGetOrCreateAsyncを使う
  5. Stopwatchやメトリクスでヒット時・ミス時の差を測る
  6. Postgres側の接続数、I/O、テーブルサイズを監視する
  7. 効果が確認できたら対象範囲を広げる

キャッシュは、入れるだけで自動的に速くなる魔法ではありません。しかし、対象データ、キー、期限、削除、監視を正しく設計すれば、レイテンシ削減、下流システムの負荷軽減、スケール時の安定性向上に直結します。今回の公式更新は、Azure上の.NETアプリでその設計を始めるための、実用的な出発点として活用できます。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次