微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 Redis 缓存未命中时,获取数据仅执行一次

如何解决在 Redis 缓存未命中时,获取数据仅执行一次

我们目前在 .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 客户端可以做到这一点,还是我必须自己实现这种锁定?

解决方法

我想知道这是否可能?

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

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

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。