現代の.NET開発において、アプリケーションには高いスループット、迅速なスケーラビリティ、そして何よりもあらゆる状況下での優れた応答性が求められます。

機能の複雑さが増し、データソースが拡大し、マイクロサービス化が進む中で、この要求を満たすことは容易ではありません。

しかし、2026年4月にリリースされた最新の情報を紐解くと、.NET 10とAzure Database for PostgreSQL、そしてHybridCacheを組み合わせることで、極めて高いパフォーマンスと回復力を備えた分散キャッシュ環境を構築できることがわかります。

本記事では、これらを活用した高度なキャッシュレイヤーの構築手法を具体的に解説します。

分散キャッシュの重要性と現代的な課題

システムの規模が拡大するにつれ、単一のアプリケーションサーバー内だけで完結するメモリ内キャッシュだけでは不十分なケースが増えています。

例えば、サーバーが再起動した際にキャッシュが消失してしまったり、複数のインスタンス間でデータの一貫性が保てなかったりといった課題です。

こうした課題を解決するために、外部のデータベースや専用のキャッシュサーバーを利用する分散キャッシュが一般的に用いられます。

しかし、分散キャッシュはネットワークを介するため、メモリ内キャッシュに比べるとアクセス速度が低下するという側面があります。

「速度」と「永続性・共有性」のトレードオフをいかに解消するかが、現代の.NET開発における大きなテーマとなっています。

.NET 10におけるキャッシュ戦略の新機軸

2026年現在の最新環境である.NET 10では、この課題に対してHybridCacheという強力な解決策を提供しています。

これは、高速なメモリ内キャッシュ (L1) と、永続的な分散キャッシュ (L2) を自動的に組み合わせるライブラリです。

また、分散キャッシュの保存先として、リレーショナルデータベースである Azure Database for PostgreSQL を活用する手法が注目を集めています。

PostgreSQLをキャッシュ基盤として利用することで、既存のデータベース資産を有効活用しながら、信頼性の高いキャッシュ層を構築することが可能になります。

ハイブリッドキャッシュのメリット

HybridCacheを導入することで、開発者は以下のようなメリットを享受できます。

  • L1/L2の自動同期: メモリ内と外部キャッシュの同期をライブラリが管理します。
  • パフォーマンスの最大化: 1ミリ秒未満で応答するメモリキャッシュと、永続的な分散キャッシュの「いいとこ取り」が可能です。
  • スタンプピード現象の防止: キャッシュが切れた瞬間に大量のリクエストがバックエンドへ飛ぶのを防ぐ仕組みが組み込まれています。

実装の準備: プロジェクトの作成とパッケージの導入

それでは、実際にコンソールアプリケーションを作成しながら、構築手順を確認していきましょう。

まずはプロジェクトを作成し、必要なパッケージをインストールします。

ターミナルから以下のコマンドを実行してください。

Shell
mkdir dcache-demo
cd dcache-demo
dotnet new console

次に、ホスティングパッケージを追加します。

これにより、依存関係の注入 (DI) や構成管理、ロギングといったモダンな.NETアプリケーションの基盤を利用できるようになります。

Shell
dotnet add package Microsoft.Extensions.Hosting

さらに、今回の肝となるキャッシュ関連のパッケージを追加します。

Microsoft.Extensions.Caching.Postgres は分散キャッシュの保存先にPostgreSQLを使用するためのものであり、Microsoft.Extensions.Caching.Hybrid はハイブリッドキャッシュ機能を提供します。

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

アプリケーションの基盤構成

インストールしたパッケージを活用するために、Program.cs を書き換えて汎用ホストを構成します。

C#
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Caching.Hybrid;

var builder = Host.CreateDefaultBuilder(args);

// 構成の設定
builder.ConfigureAppConfiguration((hostingContext, config) => {
    config.AddUserSecrets<Program>();
    config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
});

// ロギングの設定
builder.ConfigureLogging(logging => {
    logging.ClearProviders();
    logging.SetMinimumLevel(LogLevel.Information);
    logging.AddSimpleConsole(options => {
        options.TimestampFormat = "[yyyy-MM-dd HH:mm:ss.ffffff] ";
        options.SingleLine = true;
    });
});

var app = builder.Build();

var logger = app.Services.GetRequiredService<ILogger<Program>>();
logger.LogInformation("ホストアプリケーションが起動しました。");

await app.RunAsync();

Azure PostgreSQL分散キャッシュの設定

分散キャッシュの接続情報を安全に管理するため、Secrets Manager を利用します。

接続文字列には、Azure上のPostgreSQLサーバーの情報を指定してください。

Shell
dotnet user-secrets init
dotnet user-secrets set "ConnectionStrings:PostgresCache" "Host=your-server.postgres.database.azure.com;Port=5432;Username=your-user;Password=your-password;Database=your-database;Pooling=true;"

次に、appsettings.json ファイルを作成し、キャッシュの挙動を定義します。

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

これらの設定を反映させるために、サービスの登録コードを修正します。

ここでは分散キャッシュの設定と同時に、services.AddHybridCache() を呼び出すだけで、分散キャッシュとメモリ内キャッシュの連携が有効になります。

C#
builder.ConfigureServices((hostingContext, services) => {
    // PostgreSQL分散キャッシュの登録
    services.AddDistributedPostgresCache(options => {
        options.ConnectionString = hostingContext.Configuration.GetConnectionString("PostgresCache");
        options.SchemaName = hostingContext.Configuration.GetValue<string>("PostgresCache:SchemaName", "public");
        options.TableName = hostingContext.Configuration.GetValue<string>("PostgresCache:TableName", "cache");
        options.CreateIfNotExists = hostingContext.Configuration.GetValue<bool>("PostgresCache:CreateIfNotExists", true);
    });

    // HybridCacheの登録
    services.AddHybridCache();
    
    // バックグラウンドサービスの登録
    services.AddHostedService<ConsoleService>();
});

HybridCacheを利用したデータ取得の実装

それでは、実際にキャッシュを利用するビジネスロジックを実装します。

ここでは、時間のかかるデータ取得をシミュレートし、HybridCacheがどのように機能するかを確認します。

HybridCacheの最大の特徴は、GetOrCreateAsync メソッドによる直感的な記述です。

C#
public class ConsoleService : BackgroundService {
    private readonly ILogger<ConsoleService> _logger;
    private readonly HybridCache _cache;

    // デモ用に短い有効期限を設定
    private readonly HybridCacheEntryOptions _entryOptions = new HybridCacheEntryOptions {
        LocalCacheExpiration = TimeSpan.FromSeconds(3), // L1: メモリ内 (3秒)
        Expiration = TimeSpan.FromSeconds(6),          // L2: 分散キャッシュ (6秒)
    };

    public ConsoleService(ILogger<ConsoleService> logger, HybridCache cache) {
        _logger = logger;
        _cache = cache;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
        while (!stoppingToken.IsCancellationRequested) {
            var timer = System.Diagnostics.Stopwatch.StartNew();

            // キャッシュがあれば取得、なければファクトリを実行して保存
            var response = await _cache.GetOrCreateAsync(
                "weather:forecast:next-day",
                async cancel => {
                    _logger.LogInformation("キャッシュミス! ソースからデータを取得します。");
                    return await GetDataFromTheSource(cancel);
                },
                options: _entryOptions,
                cancellationToken: stoppingToken
            );

            timer.Stop();
            _logger.LogInformation("データ取得完了: {ElapsedMs} ms", timer.Elapsed.TotalMilliseconds);

            await Task.Delay(500, stoppingToken);
        }
    }

    async Task<IEnumerable<WeatherForecast>> GetDataFromTheSource(CancellationToken token) {
        await Task.Delay(2000, token); // 2秒の遅延をシミュレート
        return new List<WeatherForecast> { new WeatherForecast { Summary = "Sunny" } };
    }
}

パフォーマンスの測定と結果の分析

このアプリケーションを実行すると、キャッシュの効果が劇的に現れることがわかります。

text
[2026-04-28 10:00:00.000000] info: キャッシュミス! ソースからデータを取得します。
[2026-04-28 10:00:02.050000] info: データ取得完了: 2050.12 ms (初回取得)
[2026-04-28 10:00:02.550000] info: データ取得完了: 0.15 ms (L1: メモリ内ヒット)
[2026-04-28 10:00:03.050000] info: データ取得完了: 0.12 ms (L1: メモリ内ヒット)
[2026-04-28 10:00:05.550000] info: データ取得完了: 25.40 ms (L2: 分散キャッシュヒット)
キャッシュの状態応答速度の目安解説
初回 / キャッシュ切れ2000ms +外部ソースへのアクセスが発生するため、非常に低速です。
L1 ヒット< 1ms最速の状態です。 同一サーバーのメモリから直接取得します。
L2 ヒット10 – 50msメモリよりは遅いですが、Azure Postgresから高速に取得されます。

この結果からわかる通り、L1キャッシュ (メモリ内) が有効な間はミリ秒未満の超高速応答が実現され、それが期限切れになった後もL2キャッシュ (Postgres) が存在することで、再度2秒待つことなくデータを取得できています。

さらに、アプリケーションサーバーが再起動してメモリがクリアされたとしても、データはPostgresに永続化されているため、システム全体の回復力が大幅に向上します。

まとめ

.NET 10とAzure Database for PostgreSQL、そしてHybridCacheを組み合わせた戦略は、単なるパフォーマンス向上に留まりません。

それは、アプリケーションに極めて高いスケーラビリティと、障害に対する強靭さをもたらす設計パターンです。

今回紹介した手法を導入することで、データベースへの負荷を最小限に抑えつつ、ユーザーに対して常に一貫した高速な体験を提供できるようになります。

特に、クラウドネイティブなマイクロサービス環境においては、こうした「階層型キャッシュ」の構築は必須のスキルと言えるでしょう。

2026年以降の.NET開発において、Azure Postgresを分散キャッシュとして活用する手法は、そのシンプルさと信頼性から、多くのプロダクション環境で標準的な選択肢となっていくはずです。

ぜひ、皆様のプロジェクトでもこの強力なキャッシュ戦略を取り入れてみてください。