【问题标题】:Entries disappearing from ConcurrentDictionary条目从 ConcurrentDictionary 中消失
【发布时间】:2020-03-31 16:02:42
【问题描述】:

我托管了一个跟踪帐户权限的 API。权限存储在 API 数据库中。为了能够在数据库极慢或不可用的情况下准确响应,我选择尝试在内存中反映数据库权限。

为此,我选择了ConcurrentDictionary<string, Permission>。键是帐户 ID,值是它的权限。这包含在服务InMemoryStorageService 中,该服务在我们的 DI 框架中注册为单例。

为了能够在内存中反映数据库,采取以下步骤:

  1. 在应用程序启动时,整个数据库表被预加载到内存中(大约 100k 条目)
  2. 对帐户权限进行更改时,它们会在数据库和内存存储中更新

我遇到的问题是,对于 api 调用的几个百分比,内存中的权限无法找到,而它们存在于数据库中。我添加了日志记录,因此我知道特定帐户的权限是在启动时从数据库加载的。在 API 启动后,这种情况经常发生。所以事件的顺序是这样的:

  1. API 启动
  2. 帐户(123、144、168)的权限被加载到 ConcurrentDictionary
  3. 帐户 144 尝试获取其权限
  4. 在内存中找不到帐户 144 的权限但在数据库中存在的日志条目

有什么建议吗?

public class InMemoryStorageService : IInMemoryStorageService
{
    private readonly ILogFactory _logFactory;
    private readonly IPermissionRepository _permissionRepository;
    private readonly ConcurrentDictionary<string, Permission> _inMemoryStore;

    private ILog _log;
    protected ILog Log => _log ?? (_log = _logFactory.GetLogger(GetType()));

    public InMemoryStorageService(ILogFactory logFactory, IPermissionRepository permissionRepository)
    {
        _logFactory = logFactory;
        _permissionRepository = permissionRepository;
        _inMemoryStore = new ConcurrentDictionary<string, Permission>();
    }

    public Permission GetPermission(string accountId)
    {
        Permission value;
        if (_inMemoryStore.TryGetValue(accountId, out value)) return value;

        return null;
    }

    public void AddOrUpdatePermission(Permission permissions)
    {
        if (permissions == null) throw new ArgumentNullException(nameof(permissions));

        _inMemoryStore.AddOrUpdate(permissions.AccountId, permissions,
            (accId, currentPermissions) =>
                permissions.Updated > currentPermissions?.Updated ? permissions : currentPermissions);
    }

    public void PreloadStorageFromDb()
    {
        try
        {
            var stopWatch = new Stopwatch();
            stopWatch.Start();

            int addedPermissions = 0;
            var permissions = _permissionRepository.GetAll();
            foreach (var accountPermission in permissions)
            {
                AddOrUpdatePermission(accountPermission);
                addedPermissions++;
            }

            stopWatch.Stop();
            Log.InfoAsJson($"{nameof(PreloadStorageFromDb)}", new
            {
                addedPermissions,
                timeToLoadCacheInMilliseconds = stopWatch.ElapsedMilliseconds
            });
        }
        catch (Exception e)
        {
            Log.ErrorAsJson($"{nameof(PreloadStorageFromDb)}", null, e);
        }
    }
}

DI 框架是 SimpleInjector

container.RegisterInstance<IInMemoryStorageService>(new InMemoryStorageService(logFactory, new PermissionRepository(appSettings, logFactory)));

API 是通过 Owin 自托管的。它通过 .NET Framework 4.7.1 WindowsService 启动。

【问题讨论】:

    标签: .net caching singleton concurrentdictionary


    【解决方案1】:

    没关系。我真蠢。我曾假设记录的条目来自 api。但它们源自引擎,它不会预加载内存存储。

    道歉!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-12-11
      • 1970-01-01
      • 2013-01-07
      • 1970-01-01
      • 1970-01-01
      • 2016-03-21
      • 2016-04-23
      相关资源
      最近更新 更多