【问题标题】:On Redis cache miss, get data only executes once在 Redis 缓存未命中时,获取数据只执行一次
【发布时间】:2021-04-02 18:50:03
【问题描述】:

我们目前在 .NET Core 微服务中使用 LazyCache,但想利用分布式缓存,因此我们正在寻找 Redis 的解决方案。

我正在研究缓存未命中情况。假设我们有 100 个请求(在同一台服务器上)进来,都需要获取相同的数据。我们有一个对数据库的后台调用,但它是一个复杂的查询,所以我们使用 LazyCache 缓存了结果。如果数据不在缓存中,则 LazyCache 会调用数据库以获取数据并锁定所有其他请求者,直到有响应为止。所以数据库调用只进行一次。

这是 LazyCache 相对于 Microsoft 的传统 MemoryCache 的优势。这篇文章很好地解释了这个问题: https://blog.novanet.no/asp-net-core-memory-cache-is-get-or-create-thread-safe/

现在我们想对 Redis 做同样的事情,但我想知道这是否可能?我们使用 StackExchange.Redis 客户端。

实际上我们想要这样做:

public async Task<string> GetOrAddAsync(string key, Func<Task<string>> dataFactory)
{
    var result = await cache.GetStringAsync(key);

    if(result != null)
    {
        return result;
    }

    result = await dataFactory();

    await cache.SetStringAsync(key, result);

    return result;
}

假设我们同时有 100 个请求。在一个线程调用 SetStringAsync 之前,所有其他线程都将调用 dataFactory();也可以获取数据。这可能是一个巨大的性能问题。我想看到的是,只有该键的第一个线程调用 dataFactory,但所有其他线程都被锁定在那里并等待第一个请求完成并设置 SetStringAsync。这与 LazyCache 中的行为相同。

这对我来说似乎是一个很明显的场景,所以我很惊讶我在网上找不到任何关于这个的信息?有谁知道 StackExchange.Redis 客户端可以做到这一点,还是我必须自己实现这个锁定?

【问题讨论】:

    标签: multithreading redis stackexchange.redis memorycache lazycache


    【解决方案1】:

    我想知道这是否可能?

    一般不会。这对于内存缓存来说相对容易,但是分布式缓存需要分布式锁。然后可以放弃它,在这种情况下您必须定义某种恢复语义。

    总而言之,这是一个需要解决的大问题,而且使用分布式锁会增加更多性能问题(即,每个请求都必须协调分布式锁才能在缓存中插入/删除)。具有讽刺意味的是,如今分布式锁通常使用分布式缓存来实现。

    因此,虽然您可以自己实现它,但我建议在实际场景中进行一些认真的测试,以测试分布式锁定缓存的性能是更好还是更差。

    无法预测测试会产生的结果,但我怀疑保留内存缓存会更快(您将有 dataFactory 调用 每个节点,而不是每个请求),或者可能是 2 级缓存(其中两个缓存都被检查和更新,但只有内存中的一个被锁定)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-03
      • 2018-03-23
      • 2021-04-12
      • 1970-01-01
      • 2015-11-04
      • 2023-03-12
      • 1970-01-01
      • 2019-03-27
      相关资源
      最近更新 更多