简体   繁体   English

缓存单个键与缓存 ASP.NET Web API 中的键字典

[英]Caching individual keys vs caching dictionary of keys in ASP.NET web API

I need to cache information about user roles in ASP.NET Web API.我需要在 ASP.NET Web API 中缓存有关用户角色的信息。 I have decided to use System.Web.Helpers.WebCache class.我决定使用System.Web.Helpers.WebCache类。 Role is plain string, which is about 40 character long.角色是普通字符串,大约有 40 个字符长。 Each user may have between 1-10 roles.每个用户可能有 1-10 个角色。

I am thinking of two ways to do this:我正在考虑两种方法来做到这一点:

  1. Use WebCache.Set(UserID, List<String>).使用WebCache.Set(UserID, List<String>). Use user id as key and store List of roles (string) as value.使用用户 ID 作为键并将角色列表(字符串)存储为值。 Its easy to retrieve.它很容易检索。
  2. Use dictionary, where I will use userId as key and list of roles as value & then cache the dictionary.使用字典,我将使用 userId 作为键,使用角色列表作为值,然后缓存字典。 This way I am caching with only one key.这样我只用一个键缓存。 When I retrieve this information, I first retrieve dictionary and then use user id to get the role information.当我检索此信息时,我首先检索字典,然后使用用户 ID 获取角色信息。

Questions:问题:

  1. Which approach is better?哪种方法更好? I like approach one as its easy to use.我喜欢方法一,因为它易于使用。 Does it have any downside?它有什么缺点吗?
  2. The way I calculated memory use for keeping these keys into cache is by adding same amount of data (stored 10 roles of type string into) into a notepad and then calculated the size of the notepad (used UTF-8 encoding).我计算将这些键保存在缓存中的内存使用的方法是将相同数量的数据(存储 10 个字符串类型的角色)添加到记事本中,然后计算记事本的大小(使用 UTF-8 编码)。 The size was about 500 bytes and size of disk was 4 KB .大小约为500 bytes ,磁盘大小为4 KB Then if I have 200 users, I will multiply 200 * 500 bytes to calculate the memory usage.那么如果我有 200 个用户,我将乘以 200 * 500 字节来计算内存使用量。 Is this right (I am ok if approximately closed) way to calculate?这是正确的(如果大约关闭我可以)计算方式吗?

I prefer the approach of saving individual keys instead of saving the roles of all users as a single cache object.我更喜欢保存单个键的方法,而不是将所有用户的角色保存为单个缓存对象。

Following are the reasons:以下是原因:

1) Creation is simple, when user logs in or at an appropriate moment in time, the cache is checked for and 'if empty' created for that user, no need of iterating through the dictionary object (or LINQ) to get to that key item. 1) 创建很简单,当用户登录时或在适当的时间,检查缓存并为该用户创建“如果为空”,无需遍历字典对象(或 LINQ)以获取该键物品。

2) When user logs off or at an appropriate moment, the cache object is destroyed completely instead of only removing that particular key from cache. 2)当用户注销或在适当的时候,缓存对象被完全销毁,而不是只从缓存中删除该特定键。

3) Also no need of locking the object when multiple users are trying to access the object at the same time and this scenario will happen. 3)当多个用户同时尝试访问对象时,也不需要锁定对象,这种情况就会发生。 Since object is created per user, there is no risk of locking that object or need to use synchronization or mutex.由于对象是按用户创建的,因此没有锁定该对象或需要使用同步或互斥锁的风险。

Thanks, Praveen谢谢,普拉文

1. Solution one is preferrable. 1. 最好是方案一。 It is straightforward and appears to only offer advantages.它很简单,似乎只提供优势。

2. Your calculation makes sense for option 1 but not for option 2. AC# dictionary using hashing takes up more memory, for primitive and short data like this, the data taken by hashes may be a significant increase. 2.你的计算对选项1有意义,但对选项2没有意义。使用散列的AC#字典占用更多内存,对于像这样的原始和短数据,散列所占用的数据可能会显着增加。

The memory storage in individual bytes for this type of application would typically be a secondary concern compared to maintainability and functionality, this is because user roles are often a core functionality with fairly large security concerns and as the project grows it will become very important that the code is maintainable and secure.与可维护性和功能相比,此类应用程序的单个字节内存存储通常是次要问题,这是因为用户角色通常是具有相当大安全问题的核心功能,并且随着项目的发展,将变得非常重要代码是可维护和安全的。

Caching should be used exclusively as an optimization and because this is related to small amounts of data for a relatively small user base(~200 people) it would be much better to make your caching of these roles granular and easy to refetch.缓存应该专门用作优化,因为这与相对较小的用户群(约 200 人)的少量数据有关,最好使您对这些角色的缓存更加细化且易于重新获取。 According to the official documentation on this library根据该库的官方文档

Microsoft system.web.helpers.webcache微软 system.web.helpers.webcache

In general, you should never count on an item that you have cached to be in the cache通常,您永远不应该指望已缓存的项目在缓存中

And because I'll assume that user roles defines some fairly important functionality, it would be better to add queries for these roles to your web API requests instead of storing them locally.并且因为我假设用户角色定义了一些相当重要的功能,所以最好将这些角色的查询添加到您的 Web API 请求中,而不是将它们存储在本地。

However if you are dead set on using this cache and refetching should it ever disappear then according to your question, option one would be a preferrable choice.但是,如果您死心塌地使用此缓存并在它消失时重新获取,那么根据您的问题,选项一将是一个更好的选择。

This is because a list takes less memory and in this case appears to be more straight forward and i see no benefits from using a dictionary.这是因为列表占用更少的内存,在这种情况下似乎更直接,我认为使用字典没有任何好处。

Dictionaries shine when you have large datasets and need speed, but for this scenario where all data is already being stored in memory and the data set is relatively small, a dictionary introduces complexity and higher memory requirements and not much else.当您拥有大型数据集并需要速度时,字典会大放异彩,但对于所有数据已经​​存储在内存中且数据集相对较小的这种情况,字典会引入复杂性和更高的内存要求,除此之外别无他法。 Though the memory usage sounds negligible in either scenario on most modern devices and servers.尽管在大多数现代设备和服务器上的任何一种情况下,内存使用量听起来都可以忽略不计。

While a dictionary may sound compelling given your need to lookup roles by users, the WebCache class appears to already offer that funcitonality and thus an additional dictionary loses its appeal鉴于您需要按用户查找角色,字典可能听起来很有吸引力,但 WebCache 类似乎已经提供了这种功能,因此额外的字典失去了吸引力

Q1: Without knowing the actual usage of Cache items, it is difficult to draw the conclusion. Q1:不知道Cache项的实际使用情况,很难下结论。 Nonetheless, I think it all comes down to the design of the life spam for those items.尽管如此,我认为这一切都归结为这些项目的生活垃圾邮件的设计。 If you want to retire them all in once for certain period and then query a new set of data, storing a ConcurrentDictionary which houses users and roles to WebCache is a easier managing solution to do so.如果您想在一段时间内一次性全部停用它们,然后查询一组新数据,则将容纳用户和角色的 ConcurrentDictionary 存储到 WebCache 是一个更容易管理的解决方案。

Otherwise, if you want to retire each entry according to certain event individually, approach one seems a rather straight forward answer.否则,如果您想根据特定事件单独退出每个条目,方法一个似乎是一个相当直接的答案。 Just be mindful, if you choose approach two, use ConcurrentDictionary instead of Dictionary because the latter is not thread safe.请注意,如果您选择方法二,请使用 ConcurrentDictionary 而不是 Dictionary 因为后者不是线程安全的。

Q2: WebCache is fundamentally a IEnumerable>, thus it stores the key strings and the memory locations of each value, apart from the meta data of the objects. Q2:WebCache 本质上是一个 IEnumerable>,因此除了对象的元数据之外,它还存储关键字符串和每个值的内存位置。 On the other hand, ConcurrentDictionary/Dictionary stores the hash codes of key strings and the memory locations of each value.另一方面,ConcurrentDictionary/Dictionary 存储键字符串的哈希码和每个值的内存位置。 While each key's byte[] length is very small, its hashcode could be slightly bigger than the size of the string.虽然每个键的 byte[] 长度非常小,但它的哈希码可能比字符串的大小略大。 Otherwise, the sizes of HashCodes are very predictable and reasonably slim(around 10 bytes in my test).否则,HashCodes 的大小是非常可预测的并且相当苗条(在我的测试中大约 10 个字节)。 Every time when you add an entry, the size of the whole collection increment about 30 bytes.每次添加条目时,整个集合的大小都会增加大约 30 个字节。 Of course this figure does not include the actual size of the value as it is irrelevant to the collection.当然,这个数字不包括价值的实际大小,因为它与收藏无关。

You can calculate the size of the string by using:您可以使用以下方法计算字符串的大小:

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

You might also find it useful to write code to achieve the size of an object:您可能还会发现编写代码来实现对象的大小很有用:

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

First of all make sure there will be abstract layer and you can easyly change implementation if future.首先确保将有抽象层,如果将来您可以轻松更改实现。 I cant see any significant difference between this two approaches both of them use hashtable for search.我看不出这两种方法之间有任何显着差异,它们都使用哈希表进行搜索。 But second use search two times I suppose, when it serch dictionary in cache and when it search user in dictionary.但是我想第二次使用搜索两次,当它在缓存中搜索字典时,当它在字典中搜索用户时。 I whold recommend in addition我还推荐

  1. if users are huge amount , store not roles as strings but roles Ids.如果用户数量巨大,则不将角色存储为字符串,而是将角色 ID 存储为字符串。 if there are 1000-10000 of no sence to do it如果有1000-10000个无感去做

  2. List item项目清单

    Do not forget to clear cache record when user roles are updated更新用户角色时不要忘记清除缓存记录

You don't need option 2, option 1 should suffice as all you need is key,list<string> .您不需要选项 2,选项 1 就足够了,因为您只需要key,list<string>

Few points to consider in general before using caching:-在使用缓存之前一般需要考虑的几点:-

  • What is amount of data being cached.缓存的数据量是多少。
  • What mode of caching are you using In Memory/Distributed.您使用的是内存中/分布式缓存模式。
  • How are you going to manage the cache.你打算如何管理缓存。
  • If data being cached grows beyond threshold what is the fall over mechanism.如果正在缓存的数据增长超过阈值,则失败机制是什么。

Cache has its pros and cons, In your scenario you have already done the payload analysis so I don't see any issue with option 1.缓存有其优点和缺点,在您的场景中,您已经完成了有效负载分析,因此我认为选项 1 没有任何问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM