在本篇博客中,我们将首先探讨分布式环境(同一应用服务器的多个节点)中缓存的一些问题,随后我们将探讨如何使用Hazelcast缓存在Spring Boot应用中实现分布式缓存。
1.0 为什么分布式环境中的缓存是困难的
假设你有一个如下的环境--同一Spring Boot应用程序的多个节点运行着嵌入式缓存(例如Caffeine缓存)。
现在每个应用服务器都有自己的缓存副本,但会共享一个共同的数据库。
如果有任何更新数据库中记录的请求,那么只有处理该请求的应用服务器的缓存会在操作后更新。所有其他应用服务器节点上的缓冲区仍将继续提供陈旧的数据。
让我们来看看一个有2个应用服务器节点的示例场景。
正如你在上面的例子中看到的,App Node 1
,即使在数据库被更新之后,仍然继续提供陈旧的/旧的人的记录。
2.0 如何解决分布式缓存的问题
2.1 分布式嵌入式缓存的缓存复制。
如果缓存服务器被嵌入到应用程序中,那么解决方案就是在这些缓存服务器中启用REPLICATION
。
这意味着任何应用服务器缓存的变化都会自动传播到所有其他应用服务器缓存。
要做到这一点,必须有一个DISCOVERY
机制,让每个缓存服务器知道其他缓存服务器的位置。
你能想到在什么情况下使用上述缓存架构会导致问题吗?
当有大量的复制节点时,例如50-100个,那么在所有这些节点上发现和复制数据的时间就会变得越来越困难,越来越耗时。
基本上,随着节点数量的增加,复制的时间也会增加,因此在某个阶段,在所有节点上实时复制是不可行的。
2.2 远程缓存服务器
另一个避免缓存复制开销的方案是使用远程缓存服务器,如下图所示
这将解决我们复制延迟的问题。
然而,这并不像嵌入式缓存那样快--因为会有一个网络调用来到达缓存服务器。
3.0 使用HazelCast实现分布式缓存
在本节中,我们将看到如何使用Hazelcast缓存实现分布式缓存。我们将实现一个复制的嵌入式缓存,而不是一个远程缓存服务器。
这个项目的Spring Boot应用样本和整个项目可以在以下网站找到- https://github.com/chatterjeesunit/spring-boot-app/tree/v8.0
要检查这个发布标签,请运行以下命令
*git clone [https://github.com/chatterjeesunit/spring-boot-app.git](https://github.com/chatterjeesunit/spring-boot-app.git)* *cd spring-boot-app* *git checkout tags/v8.0 -b v8.0-hazelcast-caching*
3.1 添加依赖项和配置
将以下依赖项添加到你的build.gradle
implementation 'org.springframework.boot:spring-boot-starter-cache'
implementation group: 'com.hazelcast', name: 'hazelcast-all', version: '4.0.2'
接下来,我们将使用Configuration
类在Spring Boot中启用缓存。
@Configuration
@EnableCaching
public class CacheConfig {
}
最后但并非最不重要的是,为Multicast
Discovery
添加配置--通过这种方式,每个嵌入式缓存服务器可以与网络中所有其他嵌入式缓存服务器通信。
在src/main/resources
文件夹中添加一个文件 "hazelcast.yaml
" ,内容如下。
hazelcast:
network:
join:
multicast:
enabled: true
这就是使用Hazelcast在Spring Boot中配置分布式缓存所需的全部配置。现在你可以在你的方法中添加@Cacheable
注释,并开始缓存你的数据。
3.2 缓存发现的网络配置
现在,在任何分布式复制架构中,所有的组节点都需要一种方法来发现并与同组的其他节点进行通信。
我们在上一节中看到,我们在hazelcast.yaml
,启用了Multicast
发现。
那么问题来了--什么是组播?
3.3 测试这一切
在我们的项目中,我们已经设置了Docker Compose,使用它我们可以很容易地产生超过1个应用服务器的实例。
因此,让我们启动3个节点的应用服务器(带嵌入式hazecast缓存)。
如果你看一下你的应用程序的日志,你可以看到像这样的东西
这表明所有三个节点现在都通过组播连接,并且连接在端口5701
。
你现在可以测试分布式缓存,但要调用应用程序的读/写API。你会注意到,只要你调用任何写API,所有节点的缓存都会自动更新。每个应用节点都会返回相同的更新数据。