从零开始:Spring Boot项目中如何集成并使用Infinispan

news2024/12/25 9:32:50

一、介绍

Infinispan 其实就是一个分布式缓存数据网格平台,提供了高度可扩展和高性能数据缓存解决方案。Infinispan可以作为本地缓存分布式缓存使用,支持事务、查询、处理大数据等功能。简单地说,Infinispan 可以理解为是 MySQL 的内存版本。

与 Redis 对比

Infinispan 与 Redis 都是一种缓存解决方案或工具,但两者之间存在着许多不同的地方。

  • 设计目标:Infinispan 是一种数据网格和分布式计算平台,提供丰富的数据管理功能;而 Redis 主要设计为高性能的键值存储。
  • 数据模型:Infinispan 主要提供键值存储模型,支持复杂的查询和事务,支持 JAVA 数据类型存储;Redis支持丰富的数据结构,如列表、集合等。
  • 分布式特性:Infinispan 天生设计为分布式数据网格,提供数据分片、负载均衡等分布式特性;Redis 虽然也支持分布式部署,但需要通过 Redis 集群、哨兵模式等方式实现。
  • 事务和查询:Infinispan 支持事务和基于 Lucene 的全文搜索、基于 SQL 的查询;Redis 的事务支持较为基础,查询能力主要限于基本的数据结构操作。
  • 使用场景:Infinispan 适合需要复杂数据处理、分布式计算的场景,如大数据处理、实时分析等;Redis 适用于需要快速读写、高效缓存、简单消息队列的场景。

二、缓存模式

在 Infinispan 中,有一个缓存管理器叫做 CacheManager,能够用于创建和控制使用不同的缓存模式,比如本地缓存、分布式缓存、失效缓存等。

缓存模式分类
  • Local(本地)
    • Infinispan 作为单一节点运行
    • 适用场景:不需要跨多个节点共享数据
  • Replicated(复制)
    • Infinispan 在集群中的所有节点上复制所有的缓存数据,并且只执行本地读取操作,即集群中每个节点的数据都是一致的,从任何一个节点都能读取到所需要的数据
    • 适用场景:读密集型
  • Distributed(分布式)
    • Infinispan 在集群中的部分节点上复制缓存数据,并将数据分配给固定的大多数节点,即集群中的任意节点都不会有全部的数据,但读取的时候会请求拥有该数据的节点进行读取
    • 适用场景:读/写操作均衡,并且需要数据在部分节点之间共享的场景
  • Invalidation(失效)
    • 每当有操作修改缓存数据时,Infinispan 会从所有节点中清理过期的数据,只进行本地读取操作(不会跨节点操作数据)
    • 适用场景:一致性需求较高,但不需要分布式读取
  • Scattered(分散)
    • Infinispan 将缓存数据存储在集群中的部分节点上。默认情况下,Infinispan 为分散缓存分配一个主要拥有节点和一个备份拥有节点,主要拥有节点的分配方式与分布式缓存相同,而备份拥有节点始终是发起写入操作的节点。Infinispan 从至少一个拥有节点请求读取操作以确保返回正确的值。
    • 适用场景:高并发读写,并且数据能够在多个节点之间进行备份和恢复。
缓存模式比较

缓存模式比较

三、Spring Boot 集成

项目demo地址:https://gitee.com/regexpei/infinispan-demo

1. 创建项目,添加依赖
<dependency>
  <groupId>org.infinispan</groupId>
  <artifactId>infinispan-spring-boot-starter-embedded</artifactId>
</dependency>
<dependency>
    <groupId>org.infinispan</groupId>
    <artifactId>infinispan-query</artifactId>
</dependency>
2.缓存配置
@Configuration
public class InfinispanCacheConfig {
    @Bean
    public InfinispanGlobalConfigurationCustomizer globalCustomizer() {
        return builder -> builder.clusteredDefault().transport()
                .clusterName("MyCluster")
                .machineId("myMachine")
                .rackId("Rack").siteId("China").build();
    }


    @Bean
    public InfinispanCacheConfigurer cacheConfigurer() {
        return manager -> {
            final org.infinispan.configuration.cache.Configuration ispnConfig = new ConfigurationBuilder()
                    .clustering()
                    .cacheMode(CacheMode.LOCAL)     // 设置缓存模式
                    .persistence()                  // 开启持久化
                    .passivation(false)          // 缓存数据时持久化数据
                    .addSoftIndexFileStore()        // 使用软索引文件存储方式 
                    .dataLocation("cache-data")     // 持久化数据存储位置
                    .indexLocation("cache-index")   // 持久化索引存储位置
                    .shared(false)               // 不共享持久化存储 
                    .memory().maxCount(1000000L)    // 设置缓存最大数量, 1000000L 表示存储一百万条数据
                    .build();

            manager.defineConfiguration("local-sync-config", ispnConfig);
        };
    }
    @Bean(name = "large-cache")
    public org.infinispan.configuration.cache.Configuration largeCache() {
        return new ConfigurationBuilder()
                .clustering().cacheMode(CacheMode.LOCAL)
                .indexing().enable().storage(IndexStorage.FILESYSTEM).path("my-fs-cache-inf")
                .addIndexedEntities(UserInfoEntity.class)
                .memory().maxCount(1000000L)
                .build();
    }
}
3.实体类
@Data
@Table(value = "user_info")
@Indexed
public class UserInfoEntity implements Serializable {
    @Id(keyType = KeyType.Auto)
    private Long id;
    @KeywordField
    private String name;
    private String idCard;
    private String phoneNumber;
    @FullTextField
    private String desc;
    private String email;
    private String bankCard;
    @GenericField
    private LocalDateTime updateTime;
    private LocalDateTime createTime;
}
  1. 实体类需要实现序列化
  2. 实体类需要添加@Indexed注解
  3. 字段注解
    • @KeywordField:关键词索引,建议用于内容只有数字和字母的字段上,比如id、taskNo,数据类型只能是String
    • @FullTextField:全文索引,建议用在需要模糊匹配、文本检索的字段上,比如taskName,对于纯数字字母内容的字段,只能全匹配,模糊匹配会失效,数据类型只能是String
    • @GenericField:普通索引,建议除了添加@KeywordField和@FullTextField注解之外的字段都加上这个索引,因为SQL中出现使用@FullTextField注解的字段不能和没有添加注解的字段起使用
4. Controller
@Slf4j
@RestController
@RequestMapping("users")
public class UserController {
    @Autowired
    UserInfoMapper userInfoMapper;
    @Autowired
    UserInfoService userInfoService;
    @Autowired
    EmbeddedCacheManager cacheManager;
    @GetMapping("{id}")
    public UserInfoEntity getOne(@PathVariable Long id){
        return userInfoMapper.selectOneByCondition(USER_INFO_ENTITY.ID.eq(id));
    }
    @GetMapping("add-cache")
    public String addCache(@RequestParam long page, @RequestParam(defaultValue = "10000") long pageSize){
        long count = userInfoMapper.selectCountByCondition(QueryCondition.createEmpty());
        long total = count / pageSize + 1;
        log.info("分页总数:{}", total);
        int coreSize = Runtime.getRuntime().availableProcessors() * 2 + 1;
        ThreadPoolExecutor executor = ThreadUtil.newExecutor(coreSize, coreSize + 5);
        for (long i = 1; i <= total; i++) {
            long finalI = i;
            executor.execute(() -> userInfoService.addToCache(finalI, pageSize));
        }
        log.info("缓存完成!");
        return "ok";
    }

    @PostMapping("search")
    public List<UserInfoEntity> query(@RequestBody Map<String, Object> parameters){
        String sql = (String) parameters.get("sql");
        Integer page = (Integer) parameters.get("page");
        Integer pageSize = (Integer) parameters.get("pageSize");
        return userInfoService.search(sql, page, pageSize);
    }
    @DeleteMapping("{id}")
    public int del(@PathVariable Long id){
        return userInfoMapper.deleteByCondition(USER_INFO_ENTITY.ID.eq(id));
    }
    @GetMapping("count")
    public long count() {
        Cache<String, UserInfoEntity> cache = cacheManager.getCache("large-cache");
        OptionalLong optionalLong = Search.getQueryFactory(cache)
                .create("from cn.regexp.infinispan.entity.UserInfoEntity")
                .execute().hitCount();
        return optionalLong.orElse(0L);
    }
    @GetMapping("clear")
    public String clear() {
        Cache<String, UserInfoEntity> cache = cacheManager.getCache("large-cache");
        cache.clear();
        return "ok";
    }
}

四、问题记录

  1. ISPN000343: Must have a transport set in the global configuration in order to define a clustered cache

    infinispan.xml配置文件添加以下内容:

    <infinispan xmlns="urn:infinispan:config:13.0">
        <cache-container>
            <transport cluster="MyCluster"
                       machine="LinuxServer01"
                       rack="Rack01"
                       site="US-WestCoast"/>
        </cache-container>
    </infinispan>
    
  2. ISPN000403: No indexable classes were defined for this indexed cache. The configuration must contain classes or protobuf message types annotated with ‘@Indexed’

    infinispan.xml配置文件添加以下内容:

    <infinispan xmlns="urn:infinispan:config:13.0">
        <cache-container>
            <replicated-cache segments="256"
                              mode="SYNC"
                              statistics="true" name="replicatedCache">
                
                <indexing enabled="true"
                          storage="local-heap">
                    <index-reader refresh-interval="1000"/>
                    <indexed-entities>
                        <indexed-entity>cn.regexp.infinispan.entity.UserInfoEntity</indexed-entity>
                    </indexed-entities>
                </indexing>
            </replicated-cache>
        </cache-container>
    </infinispan>
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1688620.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

玩转OpenHarmony智能家居:如何实现开发版“碰一碰”设备控制

一、简介 “碰一碰”设备控制&#xff0c;依托NFC短距通信协议&#xff0c;通过碰一碰的交互方式&#xff0c;将OpenAtom OpenHarmony&#xff08;简称“OpenHarmony”&#xff09;标准系统设备和全场景设备连接起来&#xff0c;解决了应用与设备之间接续慢、传输难的问题&…

浅析智能体开发(第二部分):智能体设计模式和软件架构

大语言模型&#xff08;LLM&#xff09;驱动的智能体&#xff08;AI Agent&#xff09;展现出许多传统软件所不具备的特征。不仅与传统软件的设计理念、方法、工具和技术栈有显著的差异&#xff0c;AI原生&#xff08;AI Native&#xff09;的智能体还融入了多种新概念和技术。…

springboot-阿里羚羊 服务端埋点

官方文档 集成Java SDK 手动引入jar包「quickaplus-log-collector-java-sdk-1.0.1-SNAPSHOT.jar」 <dependency><groupId>com.alibaba.lingyang</groupId><artifactId>quickaplus-log-collector-java-sdk</artifactId><version>1.0.1&l…

心识宇宙 x TapData:如何加速落地实时数仓,助力 AI 企业智慧决策

使用 TapData&#xff0c;化繁为简&#xff0c;摆脱手动搭建、维护数据管道的诸多烦扰&#xff0c;轻量代替 OGG、DSG 等同步工具&#xff0c;「CDC 流处理 数据集成」组合拳&#xff0c;加速仓内数据流转&#xff0c;帮助企业将真正具有业务价值的数据作用到实处&#xff0c…

Java(十)---抽象类和接口

文章目录 前言知识回顾1.抽象类1.1.抽象类语法1.2 抽象类特性 2.接口2.1.接口的概念2.2 语法规则2.3 接口使用2.4 接口特性2.5 实现多个接口 3.Object类3.1 获取对象信息3.2.对象比较equals方法 4.接口使用实例4.1.Comparable4.2.Comparator4.3.Cloneable深拷贝和浅拷贝 前言 …

CCF-GESP 等级考试 2023年9月认证C++四级真题

2023年9月 一、单选题&#xff08;每题2分&#xff0c;共30分&#xff09; 第 1 题 ⼈们所使⽤的⼿机上安装的App通常指的是&#xff08; &#xff09;。 A. ⼀款操作系统B. ⼀款应⽤软件C. ⼀种通话设备D. 以上都不对 第 2 题 下列流程图的输出结果是&#xff1f;( ) A. 9B.…

2024/5/22 学习杂记

为什么功率放大电路在模电中经常提到&#xff1f; 模拟信号&#xff1a;它是连续变化的电信号&#xff0c;它在时间上和幅度上都是连续的&#xff0c;能够代表信息的连续变化。大多数物理量为模拟信号&#xff0c;如&#xff1a;温度、压力、流量… 非电物理量通过传感器变换成…

RabbitMQ 消息队列安装及入门

市面常见消息队列中间件对比 技术名称吞吐量 /IO/并发时效性&#xff08;类似延迟&#xff09;消息到达时间可用性可靠性优势应用场景activemq万级高高高简单易学中小型企业、项目rabbitmq万级极高&#xff08;微秒&#xff09;高极高生态好&#xff08;基本什么语言都支持&am…

告别付费!这款开源软件让你免费看高清电视直播!

文章目录 📖 介绍 📖🏡 演示环境 🏡📝 开源详情 📝🎯 软件介绍🚀 软件特点🎈 获取方式 🎈⚓️ 相关链接 ⚓️📖 介绍 📖 🔮 揭秘一款神奇的软件,让你轻松畅游电视直播的海洋,无需付费,无需繁琐设置,即可畅享海量高清节目!想要知道它是什么吗?跟…

如何改变echo在Linux下的输出颜色

文章目录 问题回答常规输出字体加粗斜体字带下划线闪烁效果 参考 问题 我正在尝试使用 echo 命令在终端中打印文本。 我想把文本打印成红色。我该怎么做&#xff1f; 回答 你可以使用 ANSI escape codes 定义控制输出颜色的变量。 ANSI escape codes是一种用于在文本中设置…

Gitee在已有项目基础上创建仓库中遇到的问题和解决

问题一&#xff1a;fatal: remote origin already exists 解释&#xff1a;当前仓库添加了一个名为"origin"的远程仓库配置&#xff0c;此时输入 git remote add origin https://xxx就会提示上面的内容。 解决方案1:移除旧的origin git remote remove origin 解决方案…

pyqt6入门案例

效果预览 hello.ui <?xml version"1.0" encoding"UTF-8"?> <ui version"4.0"><class>Dialog</class><widget class"QDialog" name"Dialog"><property name"geometry"><…

2024年5月份最新独角数卡使用USDT详细小白教程

直观配套视频教程 2024年5月份最新独角数卡安装及USDT使用详细小白教程 1、创建服务器 Centos或者Ubuntu2、宝塔面板开心版安装寶塔 Linux 面版 8.0.5 開心版 - 2024年1月12日 - 开心专区 - 异次元 - Powered by Discuz!Centos安装命令&#xff08;默认安装是 8.0.1 直接在线升…

PyMySQL:连接Python与MySQL的桥梁

系列文章目录 更新ing... MySQL操作全攻略&#xff1a;库、表、数据、事务全面指南深入探索MySQL SELECT查询&#xff1a;从基础到高级&#xff0c;解锁数据宝藏的密钥MySQL SELECT查询实战&#xff1a;练习题精选&#xff0c;提升你的数据库查询技能PyMySQL&#xff1a;连接P…

代码随想录算法训练营第三十四天 | 理论基础、455.分发饼干、376、摆动序列、53.最大子序和

目录 理论基础 455.分发饼干 思路 代码 376.摆动序列 思路 代码 53.最大子序和 思路 代码 理论基础 代码随想录 455.分发饼干 代码随想录 思路 可以是大饼干优先满足大胃口&#xff0c;也可以是小饼干优先满足小胃口。 代码 class Solution:def findContentChildre…

【深度学习】与【PyTorch实战】

目录 一、深度学习基础 1.1 神经网络简介 1.2 激活函数 1.3 损失函数 1.4 优化算法 二、PyTorch基础 2.1 PyTorch简介 2.2 张量操作 2.3 构建神经网络 2.4训练模型 2.5 模型评估 三、PyTorch实战 3.1 数据加载与预处理 3.2 模型定义与训练 3.3 模型评估与调优 3…

与WAF的“相爱相杀”的RASP

用什么来保护Web应用的安全&#xff1f; 猜想大部分安全从业者都会回答&#xff1a;“WAF&#xff08;Web Application Firewall,应用程序防火墙&#xff09;。”不过RASP&#xff08;Runtime Application Self-Protection&#xff0c;应用运行时自我保护&#xff09;横空出世…

java操作Redis缓存设置过期时间

如何用java操作Redis缓存设置过期时间&#xff1f;很多新手对此不是很清楚&#xff0c;为了帮助大家解决这个难题&#xff0c;下面小编将为大家详细讲解&#xff0c;有这方面需求的人可以来学习下&#xff0c;希望你能有所收获。 在应用中我们会需要使用redis设置过期时间&…

android studio接入facebook踩坑1

今天在接入facebook第三方登录的时候&#xff0c;点击登录按钮&#xff0c;APP闪退&#xff0c;并报错 java.lang.RuntimeException Failure delivering result ResultInfo{whonull,request64206,result-1} 新文章链接https://lengmo714.top/facebook1.html 如下图&#xff1a;…

网络传输层

叠甲&#xff1a;以下文章主要是依靠我的实际编码学习中总结出来的经验之谈&#xff0c;求逻辑自洽&#xff0c;不能百分百保证正确&#xff0c;有错误、未定义、不合适的内容请尽情指出&#xff01; 文章目录 1.端口号的基础2.传输层两协议2.1.UDP 协议2.1.1.协议结构2.1.2.封…