Caching 缓存失效算法

Caching 缓存失效算法,caching,invalidation,Caching,Invalidation,我正在考虑在web服务器中缓存动态内容。我的目标是通过返回缓存的HTTP响应来桥接整个处理过程,而不影响DB(或Hibernate)。这个问题不是关于在现有缓存解决方案之间进行选择;我现在关心的是无效判决 我敢肯定,基于时间的失效是毫无意义的:每当用户更改任何内容时,他们都希望立即看到效果,而不是几秒钟甚至几分钟。而缓存几秒钟是没有用的,因为在如此短的时间内不会重复请求相同的数据(因为大多数数据都是特定于用户的) 对于每一次数据更改,我都会得到一个事件,并可以使用它根据更改的数据使所有内容无效。

我正在考虑在web服务器中缓存动态内容。我的目标是通过返回缓存的HTTP响应来桥接整个处理过程,而不影响DB(或Hibernate)。这个问题不是关于在现有缓存解决方案之间进行选择;我现在关心的是无效判决

我敢肯定,基于时间的失效是毫无意义的:每当用户更改任何内容时,他们都希望立即看到效果,而不是几秒钟甚至几分钟。而缓存几秒钟是没有用的,因为在如此短的时间内不会重复请求相同的数据(因为大多数数据都是特定于用户的)

对于每一次数据更改,我都会得到一个事件,并可以使用它根据更改的数据使所有内容无效。由于请求同时发生,因此存在两个与时间相关的问题:

  • 失效可能来得太迟,过时的数据甚至可能被提供给更改数据的客户
  • 失效结束后,长时间运行的请求可能会结束,其过时数据可能会被放入缓存
这两个问题有点相反。我想,通过使用每个客户机的
ReadWriteLock
部分序列化来自同一客户机的请求,可以很容易地解决前者。所以,让我们忘掉它吧

后者更为严重,因为它基本上意味着失效丢失,并永远(或太长时间)服务陈旧数据

我可以想象一个解决方案,比如在更改发生之前,在每个请求启动后重复失效,但这听起来相当复杂和耗时。我想知道是否有任何现有的缓存支持这一点,但我主要感兴趣的是如何实现这一点

澄清 问题在于一个简单的竞争条件:

  • 请求A执行查询并获取结果
  • 请求B做了一些更改
  • 由于B发生失效
  • 请求A(由于任何原因延迟)完成
  • 请求A的过时响应被写入缓存

要解决争用条件,请添加时间戳(或计数器),并在设置新缓存项时检查此时间戳。 这确保了过时的响应不会被缓存

下面是一个伪代码:

//如果未缓存resourceId,则设置新的缓存项
//或者如果现有条目已过时
函数setCache(resourceId、requestTimestamp、responseData){
if(缓存[resourceId]){
if(缓存[resourceId].timestamp>requestTimestamp){
//现有条目较新
返回;
}否则
if(缓存[resourceId].timestamp=requestTimestamp){
//确保无效
responseData=null;
}
}
缓存[resourceId]={
时间戳:请求时间戳,
答复:答复数据
};
}
假设我们收到了两个对同一资源“foo”的请求:

  • 请求A(在00:00:00.000收到)执行查询并获取结果
  • 请求B(在00:00:00.001收到)进行了一些更改
  • 由于B而导致的失效是通过调用
    setCache(“foo”,“00:00:00.001”,null)
  • 请求完成
  • 请求A调用setCache(“foo”、“00:00:00.000”和…)将过时响应写入缓存,但由于现有条目较新而失败
这只是基本的机制,因此还有改进的余地。

我认为您没有意识到(或者不想明确地指出)您正在询问缓存同步策略之间的选择。有几种众所周知的策略:“缓存在一边”、“读通过”、“写通过”和“写在后面”。e、 g.请看这里:。它们提供了不同级别的缓存一致性(您称之为无效)

您的选择应取决于您的需求和要求

到目前为止,您似乎选择了“写在后面”策略(队列或延迟缓存失效)。但从您的顾虑来看,您似乎选择了错误的缓存,因为您担心缓存读取不一致

<>所以,你应该考虑使用“缓存旁”或“读/写”策略,因为它们提供更好的缓存一致性。它们都是同一事物的不同风格-始终保持缓存一致。如果您不关心缓存的一致性,那么可以继续使用“write behind”,但这个问题就变得无关紧要了


在整个体系结构范围内,我永远不会去引发事件来使缓存失效,因为看起来您已经将其作为业务逻辑的一部分,而它只是一个基础架构问题。将缓存失效(或队列失效)作为读/写操作的一部分,而不是在其他地方。这使得缓存只成为基础设施的一个方面,而不是所有其他方面。

缓存系统将与应用程序集成还是单独集成?@Rei它将根据需要紧密集成。我不知道一般情况下是如何实现的,但当我需要集成缓存系统时,我四处寻找现有的解决方案,发现只有基于时间的缓存。我决定写我自己的,结果比我预期的要简单,而且肯定更有效,因为它没有你已经发现的基于时间的问题。数据更改事件是关键。@Rei这就是我要尝试的。我当前的问题是数据更改事件和延迟响应之间的竞争条件;我刚刚补充了一个说明。这听起来很简单,也很简单,我确信,我已经试过了。。。。但我想不起来是什么让我拒绝了(一周对我糟糕的记忆来说可能太多了)。现在,我相信,它应该会起作用。这也发生在我身上,这就是为什么我必须强迫自己评论我的代码。我并不总是成功,因为写代码比写评论有趣得多。:-)同时我已经把它修好了。。。使用失效的起始日期并保留无效的ent