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

一、介绍

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>
    

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

docker容器安装nexus3以及nexus3备份迁移仓库数据

一、安装步骤 1.搜索nexus3镜像 docker search nexus3 2.拉取镜像 docker pull sonatype/nexus3或者指定版本 docker pull sonatype/nexus3:3.68.0 3.查看拉取的镜像 docker images | grep "nexus3" 4.启动nexus服务 直接启动 docker run -d --name nexus3 -…

优于InstantID!中山大学提出ConsistentID:可以仅使用单个图像根据文本提示生成不同的个性化ID图像

给定一些输入ID的图像&#xff0c;ConsistentID可以仅使用单个图像根据文本提示生成不同的个性化ID图像。效果看起来也是非常不错。 相关链接 Code:https://github.com/JackAILab/ConsistentID Paper&#xff1a;https://ssugarwh.github.io/consistentid.github.io/arXiv.pd…

Sentinel重要的前置知识

文章目录 1、雪崩问题及解决方案1.1、雪崩问题1.2、超时处理1.3、仓壁模式1.4、断路器1.5、限流1.6、总结 2、服务保护技术对比3、Sentinel介绍和安装3.1、初识Sentinel3.2、安装Sentinel 4、微服务整合Sentinel ​&#x1f343;作者介绍&#xff1a;双非本科大三网络工程专业在…

二叉树实战演练

目录 1.二叉树前序遍历---leetcode 思路 画图解析&#xff1a; 2.相同的树的判断 思路&#xff1a; 3.对称二叉树 思路分析&#xff1a; 4.另一棵树的子树 思路&#xff1a; 5.二叉树的便利---牛客网 建立二叉树的逻辑图&#xff1a; 总结&#xff1a; 1.…

Python3 笔记:部分专有名词解释

1、python 英 /ˈpaɪθən/ 这个词在英文中的意思是蟒蛇。但据说Python的创始人Guido van Rossum&#xff08;吉多范罗苏姆&#xff09;选择Python这个名字的原因与蟒蛇毫无关系&#xff0c;只是因为他是“蒙提派森飞行马戏团&#xff08;Monty Python&#xff07;s Flying Ci…

Softing工业将亮相2024年阿赫玛展会——提供过程自动化的连接解决方案

您可于2024年6月10日至14日前往美因河畔法兰克福11.0号馆&#xff0c;Softing将在C25展位展出&#xff0c;欢迎莅临&#xff01; 作为工业应用中数据交换领域公认的专家&#xff0c;Softing工业致力于帮助各行各业的客户部署网络自动化和优化生产流程。 使用Softing产品&…

什么是DNS缓存投毒攻击,有什么防护措施

随着企业组织数字化步伐的加快&#xff0c;域名系统&#xff08;DNS&#xff09;作为互联网基础设施的关键组成部分&#xff0c;其安全性愈发受到重视。然而&#xff0c;近年来频繁发生的针对DNS的攻击事件&#xff0c;已经成为企业组织数字化发展中的一个严重问题。而在目前各…

基于Go实现的分布式主键系统

基于Go实现的分布式主键系统 摘要 随着互联网的发展&#xff0c;微服务得到了快速的发展&#xff0c;在微服务架构下&#xff0c;分布式主键开始变得越来越重要。目前分布式主键的实现方式颇多&#xff0c;有基于数据库自增的、基于UUID的、基于Redis自增的、基于数据库号段的…

Day3: LeedCode 203. 移除链表元素 707. 设计链表 206. 反转链表

详细讲解移步:Day3: LeedCode 203. 移除链表元素 707. 设计链表 206. 反转链表-CSDN博客 203. 移除链表元素 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&a…

Mybatis源码剖析---第一讲

Mybatis源码剖析 基础环境搭建 JDK8 Maven3.6.3&#xff08;别的版本也可以…&#xff09; MySQL 8.0.28 --> MySQL 8 Mybatis 3.4.6 准备jar&#xff0c;准备数据库数据 把依赖导入pom.xml中 <properties><project.build.sourceEncoding>UTF-8</p…

关于阳光雨露外派联想的面试感想

最近在找工作&#xff0c;接到了一个阳光雨露外派联想的面试邀请。说实在的一开始就有不对劲的感觉。想必这就是大厂的自信吧&#xff0c;上就问能不能现场面试&#xff0c;然后直接发面试邀请。这时候我倒是没觉得有啥问题。 然后今天就去面试去了&#xff0c;住的比较偏&…

CSS demo演示 20240524

说明&#xff1a;不修改父盒子的样式&#xff0c;只在子盒子上设置定位&#xff0c;让子盒子定位在父盒子右侧。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Document</title><style>…

Docker快速部署Seata的TC服务以及微服务引入Seata教程

目录 一、使用docker部署Seata的TC服务 1、拉取TC服务镜像 2、创建并运行容器 ​3、修改配置文件 4、在Nacos中添加TC服务的配置 5、重启TC服务 二、微服务集成Seata 1、引入依赖 2、修改配置文件 Seata是阿里的一个开源的分布式事务解决方案&#xff0c;能够为分布…

2024 电工杯高校数学建模竞赛(B题)数学建模完整思路+完整代码全解全析

你是否在寻找数学建模比赛的突破点&#xff1f;数学建模进阶思路&#xff01; 作为经验丰富的数学建模团队&#xff0c;我们将为你带来2024电工杯数学建模竞赛&#xff08;B题&#xff09;的全面解析。这个解决方案包不仅包括完整的代码实现&#xff0c;还有详尽的建模过程和解…

设置 sticky 不生效?会不会是你还是没懂 sticky?

官方描述 基本上可以看懂的就会知道。sticky 是相对于存在滚动条的内容的&#xff0c;啥意思&#xff1f; 就是不论你被谁包着&#xff0c;你只会往上找有 overflow 属性的盒子进行定位&#xff0c;包括&#xff1a;overflow:hidden; overflow:scroll; overflow:auto; overflo…

PMP 学习笔记(增量更新中)

PMP 作为最流行的项目管理方法论&#xff0c;是项目管理领域的对话基础&#xff0c;了解它能帮助我理解术语和规范的管理过程&#xff0c;也许后面会考一个认证。感谢 B 站视频《 PMP 认证考试课程最新完整免费课程零基础一次通过项目管理 PMP 考试》的作者&#xff0c;我通过它…

山脉数组的峰顶索引 ---- 二分查找

题目链接 题目: 分析: 我们很明显, 可以从峰值位置将数组分成两段, 具有"二段性", 所以可以用二分查找因为arr是山峰数组, 不存在相等的情况如果arr[mid] > arr[mid 1], 说明mid的位置可能是峰值, 移动right mid如果arr[mid] < arr[mid 1], 说明mid的位置…

【ZYNQ】GPIO 与 AXI GPIO

在嵌入式开发中&#xff0c;GPIO 是最常见的外设。GPIO 是 General Purpose I/O 的缩写&#xff0c;译为通用输入/输出。GPIO 用于连接外部设备&#xff0c;例如按键、传感器等&#xff0c;实现数字信号的输入或输出功能。本文主要介绍 Zynq GPIO 的基本概念&#xff0c;并对比…

物理服务器介绍

物理服务器介绍 概述分类按服务器应用分类按服务器结构分类塔式服务器机架式服务器刀片式服务器机架式服务器与刀片式服务器的对比按处理器个数分类按处理器架构分类 主板概述工作原理物理结构技术参数 CPU概述工作原理指令集相关技术技术参数主流产品 内存概述类型相关技术技术…

Python中文件操作和异常处理

文章目录 一、文件操作1.概念2.文件3.二进制 二、基本文件操作三、乱码产生四、with open() as f五、代码实现文件复制粘贴六、try ... except ...七、代码比较 一、文件操作 1.概念 帮助我们把爬虫抓下来的数据&#xff0c;进行保存。 2.文件 在计算机中&#xff0c;没有p…