在Redis缓存未命中时,get data只执行一次

vdzxcuhz  于 12个月前  发布在  Redis
关注(0)|答案(2)|浏览(176)

我们目前在.NET Core微服务中使用LazyCache,但希望利用分布式缓存,因此我们正在寻找Redis的解决方案。
我正在研究该高速缓存未命中的情况。(在同一台服务器上)进来的都需要获取相同的数据。我们有一个对数据库的后台调用,但它是一个复杂的查询,所以我们用LazyCache缓存了结果。如果数据不在该高速缓存中,LazyCache会调用数据库来获取数据,并锁定所有其他请求者,直到有响应为止。因此,数据库调用只执行一次。
这是LazyCache相对于微软传统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客户端还是我必须自己实现这种锁定?

tkclm6bt

tkclm6bt1#

我想知道这是否可能?
一般情况下不会。使用内存缓存相对容易,但分布式缓存则需要分布式锁。然后可以放弃分布式锁,并且在这种情况下必须定义某种恢复语义。
总之,这是一个需要解决的大问题,而使用分布式锁,您将增加更多的性能问题(即,每个请求都必须协调分布式锁,以便在该高速缓存中插入/删除)。具有讽刺意味的是,分布式锁目前通常使用分布式缓存实现。
所以,虽然你可以自己实现它,但我建议你用真实的场景做一些认真的测试,测试分布式锁定缓存的性能是更好还是更差。
无法预测测试会产生什么结果,但我怀疑保留内存中的缓存会更快(你会有dataFactory调用 * 每个节点 *,而不是每个请求),或者可能是2级缓存(两个缓存都被检查和更新,但只有内存中的一个被锁定)。

pengsaosao

pengsaosao2#

我也遇到过同样的问题,我们通过在分布式缓存之上使用内存缓存来解决它,(guava提供了开箱即用的功能)。似乎解决了这个问题。

相关问题