CacheManager

キャッシュライブラリ.NETC#マルチレイヤー分散キャッシュRedisASP.NET

GitHub概要

MichaCo/CacheManager

CacheManager is an open source caching abstraction layer for .NET written in C#. It supports various cache providers and implements many advanced features.

スター2,391
ウォッチ151
フォーク454
作成日:2015年3月22日
言語:C#
ライセンス:Apache License 2.0

トピックス

c-sharpcachecachemanagercachingdotnetdotnet-corememcachedredis

スター履歴

MichaCo/CacheManager Star History
データ取得日時: 2025/7/18 05:46

キャッシュライブラリ

CacheManager

概要

CacheManagerはC#で書かれた.NET向けのオープンソースキャッシュ抽象化レイヤーで、複数のキャッシュプロバイダーをサポートし、高度なキャッシュ機能を実装しています。

詳細

CacheManagerは、.NET開発者の生活を楽にし、複雑なキャッシュシナリオでも数行のコードで実装できることを目標とした包括的なキャッシュソリューションです。マルチレイヤーキャッシュ機能により、インプロセスキャッシュと分散キャッシュの前段に配置することで、読み取りアクセスを高速化できます。スライディング有効期限と絶対有効期限の両方をサポートし、キャッシュハンドル単位またはキャッシュアイテム単位での有効期限設定が可能です。キャッシュリージョン機能により、一部のキャッシュシステムが対応していなくてもライブラリ側で実装し、要素のグループ化と一括削除が可能です。統計カウンタ、イベントシステム、シリアライゼーション設定など豊富な機能を持ち、Redis、Memcached、Couchbaseなど多様なキャッシュプロバイダーと連携できます。.NET Core / ASP.NET Coreとのクロスプラットフォーム対応により、Windows、Linux、macOSで動作します。

メリット・デメリット

メリット

  • 統一インターフェース: 異なるキャッシュ技術を単一のICacheで処理
  • マルチレイヤー: インプロセスと分散キャッシュの組み合わせで最適化
  • 豊富な機能: 有効期限、リージョン、統計、イベントなど充実した機能
  • クロスプラットフォーム: .NET Standard対応でWindows/Linux/macOSで動作
  • 多様なプロバイダー: Redis、Memcached、Couchbaseなど幅広い対応
  • 設定可能: 柔軟なシリアライゼーションとキャッシュポリシー設定
  • パフォーマンス: 最適化されたパフォーマンスとメモリ管理

デメリット

  • .NET専用: 他の言語・プラットフォームからの利用は不可
  • 複雑性: 高機能ゆえの設定と理解の複雑さ
  • オーバーヘッド: シンプルなキャッシュ用途には機能過多
  • 依存関係: 複数の外部ライブラリへの依存
  • 学習コスト: 多機能ゆえの学習コストの高さ
  • デバッグ: 多層構造によるデバッグの複雑さ

主要リンク

書き方の例

基本的なキャッシュ使用

using CacheManager.Core;

// シンプルなインメモリキャッシュの作成
var cache = CacheFactory.New()
    .WithUpdateMode(CacheUpdateMode.Up)
    .WithSerializer(typeof(JsonCacheSerializer))
    .WithMicrosoftMemoryCaching()
    .Build();

// データの保存
cache.Put("user:123", new { Name = "John", Age = 30 });

// データの取得
var user = cache.Get("user:123");
if (user != null)
{
    Console.WriteLine($"キャッシュヒット: {user}");
}
else
{
    Console.WriteLine("キャッシュミス");
}

マルチレイヤーキャッシュ設定

using CacheManager.Core;
using CacheManager.Microsoft.Extensions.Caching.Memory;
using CacheManager.Redis;

// インメモリ + Redis の2層キャッシュ
var cache = CacheFactory.New()
    .WithUpdateMode(CacheUpdateMode.Up)
    .WithMicrosoftMemoryCaching("memory")
    .WithRedisConfiguration("redis", config => {
        config.WithEndpoint("localhost", 6379);
        config.WithDatabase(0);
    })
    .WithRedisCaching("redis")
    .WithJsonSerializer()
    .Build();

// データアクセス(自動的に階層管理)
var result = cache.GetOrAdd("expensive-data", (key) => {
    // 重い処理(DBアクセスなど)
    return ComputeExpensiveData();
});

有効期限とリージョンの使用

// 有効期限とリージョン設定
cache.Put("session:abc123", sessionData, TimeSpan.FromMinutes(30));

// リージョンを使った論理グループ化
cache.Put("user-data", "user:123", userData, "users");
cache.Put("user-prefs", "pref:123", preferences, "users");

// リージョン単位での削除
cache.ClearRegion("users");

// スライディング有効期限
cache.Put("activity", activityData, ExpirationMode.Sliding, TimeSpan.FromMinutes(15));

ASP.NET Core での依存性注入

// Startup.cs または Program.cs
using CacheManager.Core;
using CacheManager.Microsoft.Extensions.DependencyInjection;

public void ConfigureServices(IServiceCollection services)
{
    // CacheManagerの設定
    services.AddCacheManager(builder =>
        builder.WithUpdateMode(CacheUpdateMode.Up)
               .WithMicrosoftMemoryCaching()
               .WithRedisConfiguration("redis", config => {
                   config.WithEndpoint("localhost", 6379);
               })
               .WithRedisCaching("redis")
               .WithJsonSerializer()
    );
}

// コントローラーでの使用
[ApiController]
public class UserController : ControllerBase
{
    private readonly ICacheManager _cache;
    
    public UserController(ICacheManager cache)
    {
        _cache = cache;
    }
    
    [HttpGet("{id}")]
    public async Task<User> GetUser(int id)
    {
        return await _cache.GetOrAddAsync($"user:{id}", async (key) => {
            return await _userRepository.GetByIdAsync(id);
        }, TimeSpan.FromMinutes(10));
    }
}

統計とイベント処理

// 統計の有効化
var cache = CacheFactory.New()
    .WithMicrosoftMemoryCaching()
    .EnableStatistics()
    .Build();

// イベントハンドラーの登録
cache.OnAdd += (sender, args) => {
    Console.WriteLine($"アイテム追加: {args.Key}");
};

cache.OnGet += (sender, args) => {
    Console.WriteLine($"アイテム取得: {args.Key}");
};

cache.OnRemove += (sender, args) => {
    Console.WriteLine($"アイテム削除: {args.Key}, 理由: {args.Reason}");
};

// 複数回のアクセス後に統計情報を確認
for (int i = 0; i < 100; i++)
{
    cache.GetOrAdd($"item:{i}", i);
}

var stats = cache.Statistics;
Console.WriteLine($"ヒット率: {stats.Ratio:P2}");
Console.WriteLine($"アイテム数: {stats.Items}");
Console.WriteLine($"ヒット数: {stats.Hits}");
Console.WriteLine($"ミス数: {stats.Misses}");

カスタムシリアライゼーション

using CacheManager.Serialization.Json;
using Newtonsoft.Json;

// カスタムJSON設定
var cache = CacheFactory.New()
    .WithMicrosoftMemoryCaching()
    .WithSerializer(typeof(JsonCacheSerializer), new JsonSerializerSettings
    {
        DateTimeZoneHandling = DateTimeZoneHandling.Utc,
        NullValueHandling = NullValueHandling.Ignore
    })
    .Build();

// 複雑なオブジェクトのキャッシュ
public class ComplexData
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime CreatedAt { get; set; }
    public List<string> Tags { get; set; }
}

var complexData = new ComplexData
{
    Id = 1,
    Name = "サンプルデータ",
    CreatedAt = DateTime.UtcNow,
    Tags = new List<string> { "tag1", "tag2", "tag3" }
};

cache.Put("complex:1", complexData, TimeSpan.FromHours(1));

条件付きキャッシュ更新

// データのバージョン管理付きキャッシュ
public class CacheService
{
    private readonly ICacheManager _cache;
    
    public CacheService(ICacheManager cache)
    {
        _cache = cache;
    }
    
    public async Task<T> GetWithVersionCheck<T>(string key, Func<Task<(T Data, string Version)>> factory)
    {
        var cacheKey = $"data:{key}";
        var versionKey = $"version:{key}";
        
        var cachedData = _cache.Get<T>(cacheKey);
        var cachedVersion = _cache.Get<string>(versionKey);
        
        // 最新バージョンを確認
        var (currentData, currentVersion) = await factory();
        
        if (cachedData != null && cachedVersion == currentVersion)
        {
            return cachedData;
        }
        
        // キャッシュを更新
        _cache.Put(cacheKey, currentData, TimeSpan.FromMinutes(30));
        _cache.Put(versionKey, currentVersion, TimeSpan.FromMinutes(30));
        
        return currentData;
    }
}

// 使用例
var data = await cacheService.GetWithVersionCheck("user-settings", async () => {
    var settings = await _database.GetUserSettingsAsync(userId);
    var version = settings.LastModified.ToString("O");
    return (settings, version);
});