在ASP.NET Web API中缓存单个密钥与缓存密钥字典

时间:2018-08-23 14:22:02

标签: c# .net caching asp.net-web-api memory-consumption

我需要在ASP.NET Web API中缓存有关用户角色的信息。我决定使用System.Web.Helpers.WebCache类。角色是纯字符串,大约40个字符长。每个用户可能具有1-10个角色。

我正在考虑两种方法:

  1. 使用WebCache.Set(UserID, List<String>).使用用户ID作为键,并将角色列表(字符串)存储为值。它易于检索。
  2. 使用字典,在这里我将使用userId作为键,并使用角色列表作为值,然后缓存字典。这样,我只用一个键进行缓存。检索此信息时,我首先检索字典,然后使用用户ID获取角色信息。

问题:

  1. 哪种方法更好?我喜欢一种简单易用的方法。它有什么缺点吗?
  2. 我计算将这些键保留在高速缓存中的内存的方式是,将相同数量的数据(存储了10个类型的字符串类型的角色)添加到记事本中,然后计算记事本的大小(使用UTF-8编码)。大小约为500 bytes,磁盘大小为4 KB。然后,如果我有200个用户,我将乘以200 * 500字节来计算内存使用量。是这种计算方法(如果近似封闭,我可以)吗?

5 个答案:

答案 0 :(得分:0)

我更喜欢保存单个密钥的方法,而不是将所有用户的角色保存为单个缓存对象。

以下是原因:

1)创建很简单,当用户登录时或在适当的时候,将检查缓存并为该用户创建“如果为空”,则无需遍历字典对象(或LINQ)即可到那个关键项目。

2)当用户注销或在适当的时候,缓存对象将被完全销毁,而不仅仅是从缓存中删除该特定键。

3)当多个用户试图同时访问对象时,也不需要锁定对象,并且这种情况将发生。由于对象是按用户创建的,因此没有锁定该对象的风险,也无需使用同步或互斥锁。

谢谢Praveen

答案 1 :(得分:0)

1.解决方案之一是可取的。它很简单,似乎只提供优势。

2。您的计算对选项1有意义,但对选项2没有意义。使用散列的C#词典占用更多内存,对于像这样的原始数据和短数据,散列获取的数据可能会大大增加。

与可维护性和功能性相比,用于此类应用程序的单个字节的内存存储通常是次要的问题,这是因为用户角色通常是具有相当大的安全性问题的核心功能,并且随着项目的发展,它将变得非常重要。保证代码的可维护性和安全性很重要。

缓存应专门用于优化,因为这与相对较小的用户群(约200人)的少量数据有关,因此使这些角色的缓存更细粒度且易于重新提取会更好。 根据该库的官方文档

Microsoft system.web.helpers.webcache

  

通常,您永远不要指望已缓存的项目位于缓存中

并且由于我假设用户角色定义了一些相当重要的功能,因此最好将对这些角色的查询添加到您的Web API请求中,而不是将其存储在本地。

但是,如果您对使用此高速缓存一无所知,并且在该高速缓存消失后进行重新获取,则根据您的问题,选项一将是更可取的选择。

这是因为列表占用的内存较少,在这种情况下,它看起来更加简单明了,使用字典对我没有任何好处。

当数据集很大且需要速度时,字典会发光,但是对于这种情况,所有数据已经​​存储在内存中,并且数据集相对较小,因此字典会带来复杂性和更高的内存需求,而其他方面则不多。尽管在大多数现代设备和服务器上,这两种情况下的内存使用情况听起来都是微不足道的。

鉴于您需要用户查找角色,字典可能听起来很引人注目,但WebCache类似乎已经具有这种功能,因此其他字典就失去了吸引力

答案 2 :(得分:0)

Q1:不知道Cache项的实际用法,很难得出结论。尽管如此,我认为所有这些都归结为这些项目的垃圾邮件设计。如果要在一定时期内一次全部淘汰它们,然后查询一组新数据,则将ConcurrentDictionary存储到WebCache中可以容纳用户和角色,这是一个更容易管理的解决方案。

否则,如果您要根据特定事件分别退出每个条目,那么采用一种方法似乎是一个很简单的答案。请注意,如果选择方法二,请使用ConcurrentDictionary而不是Dictionary,因为后者不是线程安全的。

Q2:WebCache基本上是IEnumerable>,因此它存储键字符串和每个值的存储位置,以及对象的元数据。另一方面,ConcurrentDictionary / Dictionary存储键字符串的哈希码和每个值的存储位置。尽管每个键的byte []长度都很小,但其哈希码可能比字符串的大小稍大。否则,HashCodes的大小是非常可预测的,并且相当薄(在我的测试中约为10个字节)。每次添加条目时,整个集合的大小大约增加30个字节。当然,该数字不包括该值的实际大小,因为它与集合无关。

您可以使用以下方法计算字符串的大小:

System.Text.Encoding.UTF8.GetByteCount(key);

您可能还会发现编写代码以达到对象大小很有用:

static long GetSizeOfObject(object obj) 
{
    using (var stream = new MemoryStream())
    {
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Serialize(stream, obj);
        return stream.Length;
    }
}

答案 3 :(得分:0)

首先请确保将有抽象层,并且如果将来可以轻松更改实现。 我看不到这两种方法都使用哈希表进行搜索的任何显着差异。 但是我想第二次使用搜索两次,当它在缓存中搜索字典时以及当它在字典中搜索用户时。 我还要推荐

  1. 如果用户数量巨大,请不要将角色存储为字符串,而是存储角色 ID。如果有1000-10000个没有意义的话
  2. 列表项

    不要忘记 在更新用户角色时清除缓存记录

答案 4 :(得分:0)

您不需要选项2,选项1就足够了,因为您只需要key,list<string>

在使用缓存之前通常需要考虑的几点:-

  • 要缓存的数据量是多少。
  • 您使用的是“内存中/分布式”缓存模式。
  • 您将如何管理缓存。
  • 如果要缓存的数据超过阈值,那么故障转移机制是什么。

缓存有其优点和缺点,在您的场景中,您已经完成了有效负载分析,因此我看不到选项1的任何问题。