何时以及如何更新缓存

时间:2017-09-01 03:29:54

标签: rest caching architecture

我有服务 A 和服务 B

服务 A 是一个REST API,用于在数据库中存储服务 B 所需的一些相关信息。

服务 B 处理大量流量,并且不断消耗来自Kafka主题的消息。每条消息都需要来自服务 A 的一些信息。但是这些信息很少改变,最多只会改变每天的时间。

因此,为了避免经常访问REST API以获取很少更改的信息,我将实现缓存。 (不使用缓存也会给出始终查询数据库的问题)。服务 B 将首先点击缓存,如果它没有所需的数据,它只会点击 A 一次。

问题就在这里。

如果服务 A 更新其信息,我需要立即更新缓存

这样做的最佳方式是什么?

1)我可以在REST API中实现一些东西,让 B 注意到它需要更新他的chache,但是在关注点和封装方面的分离方面,不好< strong> A 知道 B 处理内部缓存? (我认为是)

2)我可以在 B 中实现一个池(并且在每X次更新信息时进行B检查)或者每隔X次更新一次缓存。但是这样我就有可能无法立即更新信息

3)此信息可能是 A 中的缓存?至少我避免查询数据库,但没有点击API:/

有没有更好的方法来解决这个问题?

谢谢!

3 个答案:

答案 0 :(得分:1)

这是一致性保证的问题,它是分布式系统中的核心问题。

您的方案包含三项服务:A,B和数据库。 如果B在任何情况下都不得使用陈旧数据,那么您有两种选择:

  1. 所有读取都将到达数据库(A或B没有缓存)。数据库内置的机制,如数据库的内部缓存,磁盘缓存和RAID镜像,可能会缓解一些磁盘I / O瓶颈。
  2. 在A(或B)处缓存数据并强制缓存和数据库之间的强一致性,这意味着每次写入都将在数据库和缓存之间的分布式事务中完成(或者使用其他一些共识协议,提供强大的一致性保证)
  3. 第一个选项不需要付出任何努力,并且对于某个工作负载可以正常工作,但如果B处的数据入口需要更多的数据库可以保留的吞吐量,它将成为一个严重的瓶颈。

    第二个选项实现起来非常复杂,会减慢数据更改使系统复杂化并损害其整体可用性:如果A发生故障,则数据无法在数据库中更改;它在事务中发生故障,然后数据将无法从数据库中读取(!)

    好消息是,大多数系统不需要如此强大的一致性保证,并且在特定情况下偶尔使用陈旧数据也可以。

    如果您的系统属于这种情况,则有几种方法可以使缓存失效。我个人认为Jose Martinez的建议是使用消息排队系统,结合发布/订阅模式:服务B会向pub / sub发布“数据已更改”消息(该消息将包含有关哪些数据项的信息)确切地改变了),服务A将是订阅者处理“数据已更改”的消息并在其到达时使其缓存无效。

    补充要点:

    B内部的缓存看起来似乎可以提供强大的一致性,但事实是您可能需要扩展B,因此您将拥有多个B实例,每个实例都有自己的缓存,需要进行无效和同步。

    您可以使用整个其他服务来保存缓存数据(Redis,Memcached等),这样您就可以将其职责分配给缓存数据(B可以使其无效,A可以直接从中读取),但它不会改变一致性困境的本质。

答案 1 :(得分:0)

基于此声明:&#34;如果服务A更新其信息,我将需要立即更新缓存&#34;,那么根据我的经验,您的两种选择将是某种形式的分布式缓存:

  1. 让服务A提供服务B可以订阅的侦听器机制,以便在数据更改时使其自己的内部缓存无效;
  2. 实现服务A和B都知道的分布式缓存层,如ehcache或memcache;当服务A更新时,它会将新值写入缓存并且所有订户都会自动更新
  3. 希望有所帮助!

答案 2 :(得分:0)

在@ CapnSchwenk的回答中添加第三个要点...

  1. 让A提交对消息队列的所有更改,例如Rabbit MQ。消息队列可以处理持久性(在B关闭的情况下)和发布者设计模型实现。队列还可以包含新数据,这样B就不必为新数据查询A.