springboot整合Hazelcast实现分布式缓存

本文详细介绍了使用Hazelcast实现分布式缓存的过程,包括项目搭建、配置、测试及跨机器部署。通过实例展示了Hazelcast的易用性和高效性。

世上无难事,只要肯放弃

前言

  菜鸡来记录一下学习分布式缓存的过程。


  说起这个缓存我立马就想到了当初学习计算机组成原理的时候学过的什么寄存器,高速缓冲,内存,磁盘,一级缓存,二级缓存,三级缓存之类的东西。我也了解过,一个程序做数据库的缓存也有一级缓存,二级缓存的概念。那么这是不是跟计算机组成原理学习的缓存很相似呢?根据我浅显的认知就大概提一嘴。

  • CPU访问内存比较慢,所以需要高速缓存,让CPU访问高速缓存,而高速缓存与内存进行数据交换。
  • 一个程序要访问数据库,其中与数据库建立连接,查询数据这一过程比较耗时间,所以把第一次查询到的数据进行缓存,下一次查询的时候就直接从缓存中拿到数据,不走数据库,这样能加快程序的速度。

  在搜索如何做缓存的时候,有一篇文章说Ehcache无法实现分布式缓存,就算手动实现分布式缓存,也无法保证数据的强一致性。而Hazelcast是一个很好的分布式缓存解决方案。既然都这么说了,那必须得用一下这个Hazelcast。虽然我是一个连任何缓存都没有用过的菜鸡,但是,世上无难事,只要肯放弃。
  该项目代码存放在码云上:https://gitee.com/siumu/blog_code.git

准备工作

  首先呢,是要先准备数据库。建库、建表、建字段、建数据太麻烦,我就偷个懒,用V部落的sql文件直接导入,用它的user表,该数据库也会和该博客的代码一起上传到码云。这张表长这个样子:
在这里插入图片描述
  接下来就是创建应用了。既然是分布式缓存,那肯定要创建多个应用来测试,所以我就创建一个maven多模块的项目,如何创建一个多模块项目,网上有很多教程,很简单,我就不写一遍了,写起来挺费劲的。如果是第一次创建多模块项目,可能会出现很多问题,慢慢解决就好了,学习就要有耐心。
  我创建的项目目录结构如下:

  • hazelcast_demo是父工程
  • hazelcast-model是子模块,主要是创建实体类
  • hazelcast-web是一个web应用,依赖hazelcast-model
  • hazelcast-web-copy是对hazelcast-web应用的一个复制

  这样就能启动两个web应用了。
在这里插入图片描述
hazelcast_demo作为父工程,没有src,就只有一个pom文件,项目需要的依赖在这里定义,它的pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <packaging>pom</packaging>
    <modules>
        <module>hazelcast-model</module>
        <module>hazelcast-web</module>
        <module>hazelcast-web-copy</module>
    </modules>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.xiumu</groupId>
    <artifactId>hazelcast_demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>hazelcast_demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <mysql.version>5.1.47</mysql.version>
        <lombok.version>1.18.12</lombok.version>
        <springboot.version>2.3.1.RELEASE</springboot.version>
        <hazelcast.version>4.0</hazelcast.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${
   
   mysql.version}</version>
            </dependency>
            <dependency>
   
<think> 嗯,用户这次的问题很具体,关于Spring Boot+Hazelcast单机模式下缓存丢失一半数据的解决方案。从技术角度看,这属于分布式缓存的异常行为,但在单机模式中出现确实反常。 用户可能已经尝试过基本配置但遇到了棘手问题,语气中带着困惑和急切。ta的引用资料显示对Spring Boot整合Hazelcast有一定了解,引用4提到EntryListener和IMap同步机制,引用2展示了基础配置,但没涉及深层故障处理。 核心排查点应该围绕三个维度:首先是配置陷阱,比如默认分区数或存活检测参数;其次是序列化问题,Hazelcast对复杂对象的序列化支持可能引发静默失败;最后是线程模型,单机模式下的异步写入丢失需要特殊处理。 注意到引用3中关于@EnableAutoConfiguration的说明很重要,如果用户排除了某些自动配置类可能导致缓存管理器失效。另外引用5提到的《Spring Boot实战》书籍第十二章关于消息服务的记载,可能暗示需要检查是否误用了事件驱动机制导致数据覆盖。 解决方案需要分层验证:从最简单的存活时间配置检查,到最复杂的堆外内存泄漏分析。特别要强调备份副本数的设置,Hazelcast默认配置backup-count=1但sync-backup-count=0,这在单机意外终止时必然丢失异步备份数据。 用户没有提及日志信息,这点很关键。应该提醒ta检查Hazelcast的Migration日志,分区表重建记录会明确显示数据丢失原因。如果看到"Partition lost"警告,就能确认为集群状态异常,即便单机模式也存在"伪集群"概念。 </think> 在Spring Boot + Hazelcast单机模式下出现缓存丢失一半数据的问题,通常是由以下几个核心原因及解决方案导致的,请按顺序排查: --- ### 一、核心原因及解决方案 #### 1. **配置错误:分区备份数量(`backup-count`)** Hazelcast默认配置会为每个分区创建1个备份副本(`backup-count=1`),但**单机模式下备份副本无法存储到其他节点**,可能导致数据丢失。 ```yaml {title="hazelcast.yaml"} hazelcast: map: your-cache-name: # 替换为你的缓存名 backup-count: 0 # 关闭备份 async-backup-count: 0 # 关闭异步备份 ``` #### 2. **未正确关闭存活检测(Liveness Probe)** 单机模式下,Hazelcast可能因存活检测失败触发数据迁移(实际无处迁移): ```yaml hazelcast: network: join: multicast: enabled: false # 必须关闭组播 tcp-ip: enabled: false # 关闭TCP-IP集群 liveness-probe: enabled: false # 关闭存活检测 ``` #### 3. **堆外内存溢出(OOM)** 当缓存对象较大时,默认堆外内存(Native Memory)可能不足: ```yaml hazelcast: native-memory: enabled: true size: 512MB # 根据需求调整 ``` #### 4. **未持久化导致进程终止丢失** Hazelcast默认数据存储在内存中,进程重启后丢失: ```java MapConfig mapConfig = new MapConfig("your-cache-name") .getEvictionConfig().setSize(1000) // 限制条目数 .setMapStoreConfig( new MapStoreConfig() .setEnabled(true) .setClassName(DatabaseMapStore.class.getName()) // 自定义存储类 ); ``` --- ### 二、补充排查项 #### 1. **检查序列化一致性** 对象需实现`Serializable`,或改用`IdentifiedDataSerializable`: ```java public class User implements IdentifiedDataSerializable { @Override public int getFactoryId() { return 1; } @Override public int getClassId() { return 100; } // 序列化/反序列化方法... } ``` #### 2. **避免GC导致数据回收** 添加JVM参数限制GC行为: ```bash -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -Xmx4g ``` #### 3. **验证缓存配置生效** 在启动类强制指定配置文件: ```java {title="HazelcastDemoApplication.java"} @Bean public Config hazelcastConfig() { return new ClasspathXmlConfig("hazelcast.xml"); // 或直接代码配置 } ``` --- ### 三、快速验证步骤 1. **日志级别调为DEBUG**: `logging.level.com.hazelcast=DEBUG` 2. **检查分区表状态**: ```java HazelcastInstance instance = ...; PartitionService partitionService = instance.getPartitionService(); partitionService.getPartitions().forEach(p -> System.out.println(p.getOwner() + " | " + p.isMigrating()) ); ``` 输出应为单节点且无迁移状态。 --- ### 根本原因总结 | 现象 | 主要原因 | 解决方案 | |---------------------|-----------------------|--------------------------| | 重启后丢失数据 | 未持久化 | 配置MapStore | | 运行时突然部分丢失 | 堆外内存溢出/GC回收 | 增大Native内存+优化GC | | 日志提示分区迁移失败| 存活检测误判 | 关闭网络探测+存活检测 | > 根据Hazelcast官方文档,单机模式需显式关闭集群相关配置[^2][^4]。若问题仍存在,建议捕获`EntryEvicted`事件监听器分析淘汰逻辑[^4]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值