代码之家  ›  专栏  ›  技术社区  ›  OpenStack

在asp.net web api中缓存单个密钥与缓存密钥字典

  •  -1
  • OpenStack  · 技术社区  · 6 年前

    我需要在asp.net web api中缓存有关用户角色的信息。我决定用 System.Web.Helpers.WebCache 上课。角色是纯字符串,大约40个字符长。每个用户可能有1-10个角色。

    我在想两种方法:

    1. 使用 WebCache.Set(UserID, List<String>). 使用用户id作为键,并将角色列表(字符串)存储为值。很容易找回。
    2. 使用dictionary,在这里我将使用userid作为键,使用角色列表作为值,然后缓存字典。这样我只用一个键来缓存。当我检索这个信息时,我首先检索字典,然后使用用户id来获取角色信息。

    问题:

    1. 哪种方法更好?我喜欢方法一,因为它容易使用。有什么坏处吗?
    2. 我计算将这些键保存在缓存中所用内存的方法是,将相同数量的数据(存储了10个字符串类型的角色)添加到记事本中,然后计算记事本的大小(使用utf-8编码)。大小差不多 500 bytes 磁盘大小是 4 KB . 如果我有200个用户,我将乘以200*500字节来计算内存使用量。这是正确的(我可以,如果大约关闭)计算方法吗?
    5 回复  |  直到 6 年前
        1
  •  0
  •   Praveen Raju    6 年前

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

    原因如下:

    1)创建很简单,当用户登录时或在适当的时间点,检查缓存并为该用户创建“如果为空”,无需遍历dictionary对象(或linq)即可获得该键项。

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

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

    谢谢,普拉文

        2
  •  0
  •   Jody Sowald    6 年前

    1。方案一比较好。它是直截了当的,似乎只提供了优势。

    2。你的计算对选项1有意义,但对选项2没有意义。使用散列的c字典占用更多内存,对于这样的原始数据和短数据,散列所获取的数据可能会有显著的增加。

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

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

    Microsoft system.web.helpers.webcache

    一般来说,您不应该指望已缓存的项在缓存中

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

    但是,如果您已经完全决定使用这个缓存,并且如果它消失了,那么根据您的问题,选项一将是一个更好的选择。

    这是因为列表占用的内存更少,在本例中似乎更直接,我认为使用字典没有任何好处。

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

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

        3
  •  0
  •   Richard Lu    6 年前

    问题1:如果不知道缓存项的实际使用情况,很难得出结论。尽管如此,我认为这一切都归结于生活垃圾对这些项目的设计。如果您想在某一段时间内一次性将它们全部注销,然后查询一组新的数据,那么存储一个ConcurrentDictionary将用户和角色保存到WebCache是一个更容易管理的解决方案。

    否则,如果您想根据某个事件单独取消每个条目,那么接近一个条目似乎是一个相当直截了当的答案。请注意,如果选择方法2,请使用concurrentdictory而不是dictionary,因为后者不是线程安全的。

    问题2:WebCache基本上是一个IEnumerable>,因此它除了存储对象的元数据外,还存储每个值的键字符串和内存位置。另一方面,ConcurrentDictionary/Dictionary存储键字符串的哈希码和每个值的内存位置。虽然每个键的byte[]长度很小,但其hashcode可能略大于字符串的大小。否则,哈希码的大小是非常可预测的,并且相当小(在我的测试中大约为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;
        }
    }
    
        4
  •  0
  •   Serg Shevchenko    6 年前

    首先要确保有抽象层,如果将来需要,可以方便地更改实现。 我看不出这两种方法之间有什么显著的区别,它们都使用哈希表进行搜索。 但第二个使用搜索两次,我想,当它在缓存中搜索字典和当它在字典中搜索用户时。 我还要推荐

    1. 如果用户数量巨大,则不将角色存储为字符串,而将角色存储为 入侵检测系统。如果有1000-10000人没有理由这么做
    2. 列表项

      别忘了 更新用户角色时清除缓存记录

        5
  •  0
  •   Vinay Pandey    6 年前

    你不需要选择2,选择1就足够了 key,list<string> .

    在使用缓存之前,通常需要考虑以下几点:

    • 缓存的数据量是多少。
    • 您在内存/分布式中使用的是哪种缓存模式。
    • 你打算如何管理缓存。
    • 如果被缓存的数据增长超过阈值,那么什么是“溢出”机制。

    cache有它的优点和缺点,在您的场景中,您已经完成了负载分析,所以我认为选项1没有任何问题。

    推荐文章