【问题标题】:Distributed Cache Warmup分布式缓存预热
【发布时间】:2016-08-30 18:49:52
【问题描述】:

我有一个部署在 Tomcat 网络服务器中的网络应用程序(基于 spring 的战争)。此 Web 应用程序由多个服务器实例提供服务,每个服务器实例都运行一个 Tomcat 实例。我打算在 Redis 数据存储上缓存一些数据,并且所有应用程序实例都联系该数据存储以读取数据。作为一个准备步骤,我希望在应用程序启动时将一些数据缓存在 Redis 中。

如果我通过网络应用程序执行此操作,所有节点都会尝试初始化缓存。让实例领导者之一是一种选择,有没有更好的解决方案?

  • Restarting:表示:停止tomcat,然后重新启动。可以出于以下几个原因完成:部署新版本的 Web 应用程序/服务器(机器)重新启动/将新服务器添加到池中。不太可能同时启动所有 tomcat 实例,但其中一些可能几乎同时启动。
  • 缓存服务器独立于网络应用程序,但以防万一它也崩溃并且数据丢失。我也会在缓存中维护“最后读取”的 TS。

【问题讨论】:

  • 关于缓存预热“最佳实践”的文本并不多(有吗?),所以 +1 敢于提出这个问题。但是,你能把它更详细一点吗?重启对于多个节点上的应用程序意味着什么?为什么要重启?为什么应用节点外部的缓存内容在重启后无法存活?
  • @cruftex 感谢 cmets。我添加了更多上下文。
  • 你怎么知道哪些按键需要预热?
  • 一个粗略的想法:Leader 选举意味着额外的复杂性,而且您希望所有节点都进行预热。给定一个需要预热的关键空间,定义一个顺序。在有序键空间内,使每个应用程序节点从一个随机偏移量开始,并在找到已填充的键后停止。

标签: java spring caching redis init


【解决方案1】:

您至少有两个选择:

  1. 要么从应用程序内部预热缓存
  2. 或者你在外面做

这两种方法都有自己的属性,从这里您可以得出解决方案。

应用程序内部升温

您的应用程序内部拥有执行缓存预热的所有基础架构。如果缓存预热是幂等的,那么由所有实例完成它可能会很好。如果您不想让所有应用程序都使用缓存预热,那么您需要做出决定:

缓存升温时其他实例会做什么?

我对这个问题有两个答案:

  1. 忽略并继续启动
  2. 等到缓存预热

在这两种情况下,您都可以使用具有超时功能的 Redis CAS(比较和交换)来创建一个即将过期的分布式锁,这样最快的启动实例就会进行预热并在完成后释放锁。

您还可以通过将第一个实例部署到执行缓存预热的服务器的过程来应对这一挑战。您等到该应用程序完成其工作,然后您就可以开始处理其他实例了。

在应用程序外加温

通过应用程序外部的缓存预热,您不会遇到并发问题,但这需要在操作和开发方面付出一些努力。您需要有人(或某些进程)在应用程序启动/部署之前运行缓存预热。您还需要构建一段代码来访问您的数据并将其放入缓存中。

构建领导者模式也可以,但需要额外的代码/组件。如果可以,请保持简单。

HTH,马克

【讨论】: