我们目前在.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客户端还是我必须自己实现这种锁定?
2条答案
按热度按时间tkclm6bt1#
我想知道这是否可能?
一般情况下不会。使用内存缓存相对容易,但分布式缓存则需要分布式锁。然后可以放弃分布式锁,并且在这种情况下必须定义某种恢复语义。
总之,这是一个需要解决的大问题,而使用分布式锁,您将增加更多的性能问题(即,每个请求都必须协调分布式锁,以便在该高速缓存中插入/删除)。具有讽刺意味的是,分布式锁目前通常使用分布式缓存实现。
所以,虽然你可以自己实现它,但我建议你用真实的场景做一些认真的测试,测试分布式锁定缓存的性能是更好还是更差。
无法预测测试会产生什么结果,但我怀疑保留内存中的缓存会更快(你会有
dataFactory
调用 * 每个节点 *,而不是每个请求),或者可能是2级缓存(两个缓存都被检查和更新,但只有内存中的一个被锁定)。pengsaosao2#
我也遇到过同样的问题,我们通过在分布式缓存之上使用内存缓存来解决它,(guava提供了开箱即用的功能)。似乎解决了这个问题。