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

问题描述 投票:-1回答:5

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

我正在考虑两种方法:

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

问题:

  1. 哪种方法更好?我喜欢接近一个因为它易于使用。它有任何缺点吗?
  2. 我计算内存用于保持这些密钥进入缓存的方式是将相同数量的数据(存储10个类型字符串的角色)添加到记事本中,然后计算记事本的大小(使用UTF-8编码)。大小约为500 bytes,磁盘大小为4 KB。然后,如果我有200个用户,我将乘以200 * 500字节来计算内存使用量。这是正确的(我很好,如果近似关闭)计算方法?
c# .net caching asp.net-web-api memory-consumption
5个回答
0
投票

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

以下是原因:

1)创建很简单,当用户登录或在适当的时刻,检查缓存并为该用户创建“如果为空”,无需迭代字典对象(或LINQ)来获取该密钥项目。

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

3)当多个用户同时尝试访问对象时也不需要锁定对象,并且会发生这种情况。由于每个用户都创建了对象,因此不存在锁定该对象或需要使用同步或互斥的风险。

谢谢,Praveen


0
投票

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

2.您的计算对选项1有意义,但对选项2没有意义。使用散列的C#字典占用更多内存,对于这样的原始和短数据,散列所采用的数据可能会显着增加。

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

缓存应该专门用作优化,因为这与相对较小的用户群(约200人)的少量数据相关,所以将这些角色的缓存细化并且易于重新提取会更好。根据这个图书馆的官方文件

Microsoft system.web.helpers.webcache

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

而且因为我假设用户角色定义了一些相当重要的功能,所以最好将这些角色的查询添加到Web API请求中,而不是在本地存储它们。

但是,如果您已经设置使用此缓存并且重新获取它应该消失,那么根据您的问题,选项一将是一个可取的选择。

这是因为列表占用的内存较少,在这种情况下似乎更直接,我认为使用字典没有任何好处。

当您拥有大型数据集并且需要速度时,字典会闪耀,但是对于所有数据已经​​存储在内存中且数据集相对较小的情况,字典会引入复杂性和更高的内存要求而不是其他内容。虽然在大多数现代设备和服务器上的任何一种情况下,内存使用量都可以忽略不计

虽然字典可能听起来引人注目,因为您需要用户查找角色,但WebCache类似乎已经提供了这种功能,因此额外的字典失去了它的吸引力


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;
    }
}

0
投票

首先确保将有抽象层,如果将来你可以轻松地改变实现。我看不出这两种方法之间有任何显着差异,它们都使用哈希表进行搜索。但是我认为第二次使用搜索,当它在缓存中搜索字典时以及在字典中搜索用户时。我还推荐了

  1. 如果用户数量巨大,则不将角色存储为字符串,而是存储角色ID。如果有1000-10000没有做到这一点
  2. 项目清单 更新用户角色时,请不要忘记清除缓存记录

0
投票

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

在使用缓存之前,一般要考虑的几点: -

  • 什么是缓存的数据量。
  • 您在内存/分布式中使用什么模式的缓存。
  • 你打算如何管理缓存?
  • 如果缓存的数据超出阈值,那么什么是跌倒机制。

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

© www.soinside.com 2019 - 2024. All rights reserved.