将MemoryCacheHandle与RedisCacheBackplane一起使用但不使用RedisCacheHandle

时间:2016-11-22 12:34:20

标签: caching redis distributed-caching cachemanager

在文档上说

    /// The cache manager must have at least one cache handle configured with <see cref="CacheHandleConfiguration.IsBackplaneSource"/> set to <c>true</c>.
    /// Usually this is the redis cache handle, if configured. It should be the distributed and bottom most cache handle.

我知道如何使用RedisCacheHandle,因为它在Cachemanager的网站上作为示例提供

var cache = CacheFactory.Build<int>("myCache", settings =>
{
    settings
    .WithSystemRuntimeCacheHandle("inProcessCache")
    .And
    .WithRedisConfiguration("redis", config =>
    {
        config.WithAllowAdmin()
            .WithDatabase(0)
            .WithEndpoint("localhost", 6379);
    })
    .WithMaxRetries(1000)
    .WithRetryTimeout(100)
    .WithRedisBackplane("redis")
    .WithRedisCacheHandle("redis", true);
});

问题是我不想使用Redis作为缓存资源;我只想通过Redis Pub / Sub机制的强大功能来创建分布式缓存。根据我通过代码调试,通过使用Redis Backplane功能,我能够确实向Redis发送消息并从Redis接收消息。那么为什么不使用RedisCacheHandle而是使用SystemRuntimeCacheHandle?

所以,我的期望是使用以下缓存配置成功执行

var cache = CacheFactory.Build<int>("myCache", settings =>
{
    settings
    .WithSystemRuntimeCacheHandle("inProcessCache")
    .And
    .WithRedisConfiguration("redis", config =>
    {
        config.WithAllowAdmin()
            .WithDatabase(0)
            .WithEndpoint("localhost", 6379);
    })
    .WithMaxRetries(1000)
    .WithRetryTimeout(100)
    .WithRedisBackplane("redis")
    .WithSystemRuntimeCacheHandle("inProcessCache", true);
});

但它没有用。你能告诉我一个解决方案吗?我究竟做错了什么?或者,尽管它已在文档中写为

  

...通常这是redis缓存句柄...

有没有办法在没有RedisCacheHandle的情况下使用缓存同步功能?

https://github.com/MichaCo/CacheManager/issues/111

1 个答案:

答案 0 :(得分:0)

我猜你“不工作”你的意思是其他缓存没有被同步,例如如果我从cacheA中删除一个密钥,它不会从cacheB中删除? 是的,这是目前预期的行为。

背板旨在与只有一个状态的进程外缓存一起使用。 使用系统运行时缓存的2个缓存实例,在proc缓存中有两个完全断开连接。

通常,如果您有一个Redis图层并从缓存实例A中删除一个键,则该项将从Redis图层中删除。消息将发送到同一缓存的其他实例,并将从任何其他缓存层中删除密钥,但redis(标记为背板源的密钥)。 这意味着,我们希望背板源已经同步。

现在,如果您将进程内缓存作为背板源,该怎么办?这不起作用,因为两个实例总是不同步。

让我们看看这个例子:

var cacheConfig = ConfigurationBuilder.BuildConfiguration(settings =>
{
    settings
    .WithSystemRuntimeCacheHandle("inProcessCache")
    .And
    .WithRedisConfiguration("redis", config =>
    {
        config.WithAllowAdmin()
            .WithDatabase(0)
            .WithEndpoint("localhost", 6379);
    })
    .WithMaxRetries(1000)
    .WithRetryTimeout(100)
    .WithRedisBackplane("redis")
    .WithSystemRuntimeCacheHandle("inProcessCache", true);
});

var cacheA = new BaseCacheManager<string>(cacheConfig);
var cacheB = new BaseCacheManager<string>(cacheConfig);

cacheB.Backplane.Removed += (obj, args) =>
{
    Console.WriteLine(args.Key + " removed from B.");
};

cacheA.Add("key", "value");

var result = cacheB.Get("key");
Console.WriteLine("Result should be null:" + result);

cacheB.Add("key", "value");
result = cacheB.Get("key");
Console.WriteLine("Result should not be null:" + result);

// triggers backplane remove event
cacheA.Remove("key");

// lets give redis some time send messages
Thread.Sleep(100);

result = cacheB.Get("key");
Console.WriteLine("Result should be null again but isn't:" + result);

Console.ReadKey();

如果运行此操作,您可以看到背板事件实际触发但由于唯一的进程内缓存是背板源,因此密钥不会被删除。 这就是为什么最后,你仍然会把钥匙还给你。

正如我所说,这是目前预期的行为。

您可以通过侦听这些事件来实现自定义逻辑。 (事件将在下一个版本中略有变化,目前存在一些错误和不一致)。

此外,不要指望背板会将缓存值传输到其他实例。这不会发生。 CacheManager只发送键事件,而不是数据,因为数据通常由进程外缓存处理。 这意味着,如果只有背板的进程内缓存,在cacheA中添加项目,则不会将项目复制到cacheB!您可能会在cacheB上获得密钥的change事件。

我希望这是有道理的;)