首页 文章

设计问题:使缓存实体变得可变的好坏?

提问于
浏览
0

在这里,我需要缓存一些内容,例如内容管理系统(CMS)中的页面树 . 该系统允许开发人员编写插件,在插件中他们可以访问缓存的页面树 . 使缓存的页面树可变是好的还是坏的(即,树节点对象有setter,和/或我们在ChildPages集合中公开Add,Remove方法 . 因此客户端代码可以设置页面树的属性节点,并自由添加/删除树节点)?

Here's my opinions:

(1)如果页面树是不可变的,则插件开发人员无法修改树意外 . 这样我们就可以避免一些微妙的错误 .

(2)但有时我们需要更改页面的名称 . 如果页面树是不可变的,我们应该调用一些方法,如“Refresh()”来刷新缓存 . 这将导致数据库命中(因此完全有两个数据库命中,但我们应该避免2个数据库命中中的一个) . 在这种情况下,如果页面树是可变的,我们可以直接更改页面树中的名称以使树更新(因此只需要1个数据库命中) .

你怎么看待这件事?如果遇到这种情况,你会怎么做?

提前致谢! :)

UPDATE: 页面树类似于:

public class PageCacheItem {
    public string Name { get; set; }
    public string PageTitle { get; set; }
    public PageCacheItemCollection Children { get; private set; }
}

我的问题不在于哈希码,因为PageCacheItem不会作为键放在哈希集或字典上 .

My prolbem is:

如果PageCacheItem(树节点)是可变的,也就是说,有属性的setter(例如,具有Name,PageTitle属性的setter) . 如果某些插件作者错误地更改了PageCacheItem的属性, the system will be in a incorrect state (缓存数据与数据库中的数据不一致), and this bug is hard to debug ,因为它是由某个插件引起的,而不是系统本身引起的 .

但是如果PageCacheItem是只读的,那么可能很难实现有效的“缓存刷新”功能,因为没有属性的设置器,我们不能简单地通过将属性设置为最新值来更新属性 .

UPDATE2

多谢你们 . 但我有一点需要注意,那就是,我不打算开发一个通用的缓存框架,而是在一个现有的缓存框架之上开发一些API . 所以我的API是底层缓存框架和插件作者之间的中间层 . 插件作者不需要了解底层缓存框架 . 他只需要知道从缓存中检索到这个页面树 . 并且他获得了强类型的PageCacheItem API,而不是从底层缓存框架中检索到的弱类型“对象” .

So my questions is about designing APIs for plugin authors ,也就是说,使API类PageCacheItem可变是好还是坏(这里mutable ==属性可以在PageCacheItem类之外设置)?

2 回答

  • 3

    首先,我假设您的意思是缓存的值可能是可变的,也可能不是可变的,而不是它所标识的标识符 . 如果你的意思是标识符,那么我会非常强调在这方面是不可改变的(强调足以让我的帖子标记为淫秽语言) .

    至于可变值,这里没有一个正确的答案 . 无论哪种方式,您都会遇到主要的pro和con,并且您描述的两个选项中的每一个都有多个变体 . 高速缓存失效通常是一个众所周知的难题(如Phil Karlton的众所周知的引用,“计算机科学中只有两个难题:高速缓存失效和命名事物 . ”*)

    有些事情需要考虑:

    • 更改的频率 . 如果更改很少,刷新变得容易 - 转储现有缓存并让它重建 .

    • CMS将在多个服务器上,或将来是否可以,因为这意味着必须共享任何无效信息 .

    • 陈旧数据的糟糕程度,以及它有多快坏(你能否乐意在接下来的一个小时左右服务器过时的 Value ,或者这会与新的 Value 发生冲突) .

    • 重新验证方法是否对您有意义,在一定时间后检查缓存值以确保它仍然有效,并更新下一次检查的时间(或者,定期转储旧值并让它们成为再次从新鲜的来源中获取) .

    • 首先检测陈旧性有多容易?如果它很难,这可以排除一些方法 .

    • 缓存实际保存了多少 . 你能摆脱它吗?

    我没有't mentioned threading issues, because the threading issues are difficult with any sort of cache unless you'单线程(如果它是一个CMS我'm guessing it'的网络,因此本质上是多线程的) . 有一件事我一般都是缓存失败并不严重的情况(根据定义,缓存失败有一个后备 - 获得新值)因此,采用一种方法而不是无限期地在监视器上阻塞(这是 lock 的做法)是富有成效的在内部)你使用带有超时的 Montior.TryEnter ,如果达到超时,则缓存操作会失败 . 使用 ReaderWriterLockSlim 并允许稍长的写入超时可能是一个很好的方法 . 这样,如果你得到一个重锁争用点,那么缓存将停止为某些线程工作,但这些线程仍然可以获得可用数据 . 这会破坏这些线程的性能,但不会像锁争用会导致所有受影响的线程一样多,而缓存是一个很容易将锁争用引入Web项目的地方,只有在你上线后才能点击 .

    *(当然还有众所周知的变体,“计算机科学中只有两个难题:缓存失效,命名事物和逐个错误”) .

  • 1

    以这种方式看待它,如果条目是可变的,那么当对象发生变异时,哈希码可能会发生变化 .

    根据缓存的字典实现,它可以:

    • 是'lost'

    • 在最坏的情况下,需要重新整个缓存

    可能有正当理由为什么你想要'可变的哈希码',但我在这里看不到理由 . (在过去的9年里,我只需要做一次) .

    只删除并替换您希望“变异”的条目会容易得多 .

相关问题