ASp .Net Core Web API 中的多个 MemoryCache

Multiple MemoryCache in ASp .Net Core Web API

我有一个 ASP .Net Core 2.2。网页 API。我想通过使用 MemoryCache 来提高性能。但是,我需要缓存 2 种不同的类型,它们都使用整数键。一种是用户列表,另一种是组列表。

现在,我要在 Startup.cs 文件中添加 MemoryCache 服务:

services.AddMemoryCache();

然后我使用依赖注入在两个不同的地方访问这个缓存(在中间件和我写的服务中)。

据我了解,这两个缓存是同一个实例。因此,当我向其中添加我的各种用户和组时,由于它们都有整数键,因此会发生冲突。我该如何处理?我考虑过使用两个缓存 - 每种缓存一个 - 但是(a)我不确定如何做到这一点并且(b)我在某处读到不建议使用多个缓存。有什么想法吗?

是的,我以前遇到过同样的问题,因此我创建了一个扩展版本的 MemoryCache,它允许我插入不同的 "stores".. 只需将要插入缓存的数据包装成 "metadata" 类型 class 即可。我想类似于 ServiceDescriptors 如何在 DI 中包装您的服务注册?

另外,在具体回答"I thought about using two caches - one for each type"点。这就是问题所在,因为我相信 IMemoryCache 默认注册为单例

我自己 运行 解决了这个问题。我想到的一个解决方案是只在包装器 class 中实例化两个单独的内存缓存,并将包装器 class 注册为单例实例。 但是,只有当您对每个内存缓存有不同的要求时才有意义and/or您希望为每个内存缓存存储大量数据(此时,in-memory缓存可能不是你想要的)。

这是我要缓存的一些示例 classes。

    // If using a record, GetHashCode is already implemented through each member already
    public record Person(string Name);

    // If using a class, ensure that Equals/GetHashCode is overridden
    public class Car
    {
        public string Model { get; }
        public Car(string model)
        {
            Model = model;
        }

        public override bool Equals(object? obj)
        {
            return obj is Car car &&
                   Model == car.Model;
        }

        public override int GetHashCode()
        {
            return HashCode.Combine(Model);
        }
    }

这里是双 MemoryCache 实现。

    public class CustomCache : ICustomCache // Expose what you need and register it as singleton instance
    {
        private readonly MemoryCache personCache;
        private readonly MemoryCache carCache;

        public CustomCache(IOptions<MemoryCacheOptions> personCacheOptions, IOptions<MemoryCacheOptions> carCacheOptions)
        {
            personCache = new MemoryCache(personCacheOptions);
            carCache = new MemoryCache(carCacheOptions);
        }

        public void CreatePersonEntry(Person person)
        {
            _ = personCache.Set(person, person, TimeSpan.FromHours(1));
        }

        public void CreateCarEntry(Car car)
        {
            _ = carCache.Set(car, car, TimeSpan.FromHours(12));
        }
    }

如果您没有上述要求,那么您可以按照 juunas 提到的方法创建一个带有复合键的简单包装器。您仍然需要确保为每个要存储的 class 正确实施 GetHashCode。在这里,我的组合键只是一个整数(我用的是质数,没有具体原因)和一个对象配对。我没有为密钥使用结构,因为 MemoryCache 使用 Dictionary<object, CacheEntry>,所以我不想 box/unbox 密钥。

    public class CustomCache : ICustomCache // Expose what you need
    {
        private readonly IMemoryCache cache;

        public CustomCache(IMemoryCache cache)
        {
            this.cache = cache;
        }

        public void CreatePersonEntry(Person person)
        {
            _ = cache.Set(CustomKey.Person(person), person, TimeSpan.FromHours(1));
        }

        public void CreateCarEntry(Car car)
        {
            _ = cache.Set(CustomKey.Car(car), car, TimeSpan.FromHours(12));
        }

        private record CompositeKey(int Key, object Value)
        {
            public static CustomKey Person(Person value) => new(PERSON_KEY, value);
            public static CustomKey Car(Car value) => new(CAR_KEY, value);

            private const int PERSON_KEY = 1123322689;
            private const int CAR_KEY = 262376431;
        }
    }

如果您发现任何错误或有更好的解决方案,请告诉我。