java - 使用 Spring/EHCache 在负载下刷新缓存

标签 java multithreading spring caching ehcache

我在具有数据库后端和基于 EHCache 的缓存的 Spring 多线程 Web 服务上遇到缓存问题。该服务有许多客户端一次又一次地请求同一个对象,每秒有几十个请求。只有几个对象被频繁请求,大量其他对象被不频繁请求。对象每隔几分钟就会更改一次,因此缓存的 TTL 设置为一分钟。从数据库加载对象很慢,至少需要几秒钟。

起初我使用了一个天真的实现来获取对象:

  1. 检查对象是否在缓存中。
  2. 如果是,从缓存中返回。
  3. 如果没有,从数据库中加载,放入缓存中返回。

最初在本地测试时效果很好。但是在更快的服务器上进行的性能测试显示,每当一个更频繁请求的对象在缓存中过期时,就会出现一些非常糟糕的负载峰值。发生这种情况时,在接下来的 10 秒内,对该对象的所有请求都将导致数据库加载,直到第一个线程完成数据库加载并将新对象放入缓存中。结果是对数据库造成了短暂但非常高的负载,并且有很多用户需要等待请求完成。

我当前的实现通过跟踪当前是否正在加载哪个对象来改善数据库负载:

  1. 检查对象是否被缓存。
  2. 如果是,从缓存中返回。
  3. 如果没有,检查当前是否正在加载对象。
  4. 如果是,等待其他线程加载完成,从缓存中获取新对象并返回。
  5. 如果不是,将该对象放入加载对象列表,完成后放入缓存并返回。

通过这种实现,即使对象过期,也只有一次数据库操作。而且,由于数据库负载较低,它也会更快完成。但这仍然意味着所有在对象加载期间请求该对象的用户都需要等待。

我真正想要的是只有第一个线程等待数据库加载,所有其他线程在加载对象时只返回“过期”对象。对我来说,响应时间比对象过早几秒钟这一事实更重要。

或者,当我注意到某个对象将在几秒钟后过期时,我可以异步刷新缓存。这更接近于 EHCache 的单一 TTL 模型,意味着没有人需要等待数据库加载

我真正的问题是:在我重新发明轮子之前,是否有任何现有框架已经实现了类似的东西(在 Spring/EHCache 环境中)?或者可能在 Spring/EHCache 的某个地方已经存在对此的支持,而我只是找不到正确的选项?

最佳答案

有两个 Ehcache 提供的构造可以帮助您:

  1. Refresh ahead
  2. 定时刷新

两者都需要您更改与缓存交互的方式,因为它们需要配置 CacheLoader

不幸的是,我找不到显示第二个选项示例的在线文档。 它允许使用 Quartz 来刷新缓存条目来安排它。它还可以基于 key 生成器仅刷新 key 的子集。 查看包 net.sf.ehcache.constructs.scheduledrefresh

中的类

关于java - 使用 Spring/EHCache 在负载下刷新缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26296035/

相关文章:

java - 使用 jxl 向 Excel 文件添加数据

c - 如何使用结构在多线程中拥有共享计数器?

Python - 使用 HTTPS 的 urllib2 异步/线程请求示例

Java, Spring : Text comparison sometimes adding null entries.

java - Java Swing Eclipse - JPanel 和组件自动调整大小

java - eclipse java 如何插入构建时间戳

java - PriorityQueue排序问题

c++ - Threadsafe OpenSSL 在单线程中的使用?

java - Spring调度器多次执行任务

java - 防止 JAXB 将字符串转换为数字 (JSON)