c# - 多个请求访问数据库 - 等待缓存可用
问题描述
我们正在使用一个简单的Memory Cache
方法来缓存密集查询的响应,否则每秒会被多次命中。缓存非常快,偏移量设置为 2 秒。
public StateService
{
private readonly ObjectCache _cache = MemoryCache.Default;
private const string _queueStatesCacheKey = "_states";
public IList<States> GetStates()
{
var states = _cache.Get(_statesCacheKey);
if (states== null)
{
states = getStatesFromDatabase();
_cache.Set(_statesCacheKey, states, DateTimeOffset.Now.AddSeconds(Settings.AppSettings.QueueStateCacheExpiration));
}
return states as List<States>;
}
}
方法:getStatesFromDatabase()
简单地运行 aSQL-query
来运行一个存储过程并获取这些值。
这都是通过 an 获取的API
,目前我们遇到的情况是缓存被清除并且getStatesFromDatabase()
同时被 4-5 个线程命中。
- 我可以结束
GetStates()
并Task
等到它完成另一个请求开始一个新任务吗? - 还是我必须使它成为一个单例服务才能工作?
- 或者我是否必须创建一种新的提供者来处理返回
List<States>
? - 以不同的方式或其他地方缓存它会更好吗?
解决方案
用于SemaphoreSlim
锁定其他线程,直到缓存准备好:
public StateService
{
private readonly ObjectCache _cache = MemoryCache.Default;
private const string _queueStatesCacheKey = "_states";
private static SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
public IList<States> GetStates()
{
var states = _cache.Get(_statesCacheKey);
if (states== null)
{
try
{
semaphore.Wait();
// we check again from cache, that could have been populated from other thread
states = _cache.Get(_statesCacheKey);
if(states != null) return states as IList<States>;
states = getStatesFromDatabase();
_cache.Set(_statesCacheKey, states, DateTimeOffset.Now.AddSeconds(Settings.AppSettings.QueueStateCacheExpiration));
}
finally
{
semaphore.Release();
}
}
return states as List<States>;
}
}
您可以配置无超时(如示例中所示)或某种超时,可能基于查询的运行时间统计信息。
请注意,这仅适用于单个服务器和单个进程设置。如果您的应用程序打算在多个服务器或多个进程上运行,则此解决方案将允许每个服务器/进程进行一个并发查询。
为避免这种情况,您需要检查一些用于从外部管理锁的包(分布式锁)。例如, Nuget 包DistributedLock就是一个可以完成这项工作的包。
推荐阅读
- clang - 为什么我没有从 LLVM 获得精确的行/列调试信息
- php - 我的中间件返回 Not Found 而不是重定向“离开”
- android - Jetpack Compose 的方向
- python - 如何将列中的值映射到另一个数据框的另外两列并在两列上提取匹配值?
- r - 根据条件和按组计数创建新列
- unit-testing - 在笑话包装器中模拟 beforeMount
- swiftui - 如何在 SwiftUI 中扩展视图?
- android - 使用 Android.mk 从预构建的 apk 文件中提取本机库
- git - git diff master --name-only 不像 git status 那样显示相对路径
- c# - 尝试将 double 类型的变量设置为等于解析的坐标时,输入字符串的格式不正确?