Infinispan篇(一):一个被遗忘了的分布式集群缓存系统

简介: Infinispan 是一个开源内存数据网格,提供灵活的部署选项和强大的数据存储、管理和处理功能。

一、前言

这几天在学习Keycloak,而Keycloak使用的缓存是Infinispan,今天就来排一下它。

二、Infinispan概述

Infinispan 是一个开源内存数据网格,提供灵活的部署选项和强大的数据存储、管理和处理功能。Infinispan提供了一个键/值数据存储,可以保存所有类型的数据,从Java对象到纯文本。Infinispan 将数据分布在弹性可扩展的集群中,以保证高可用性和容错能力,无论您将 Infinispan 用作易失性缓存还是持久性数据存储。

官方文档https://infinispan.org/documentation/

2.1 特点

2.2 部署模型

Infinispan有两种缓存部署模型,远程和嵌入式。与传统数据库系统相比,这两种部署模型都允许应用程序以显著降低的读取操作延迟和更高的写入操作吞吐量访问数据。

远程缓存: Infinispan Server 节点在专用的 Java 虚拟机 (JVM) 中运行。客户端使用 Hot Rod、二进制 TCP 协议或通过 HTTP 访问远程缓存。(Keycloak采用远程部署,通俗点讲就是Infinispan是独立部署的。)

嵌入式缓存: Infinispan 与 Java 应用程序在同一个 JVM 中运行,这意味着数据存储在执行代码的内存空间中。

三、二进制部署

https://downloads.jboss.org/infinispan/14.0.4.Final/infinispan-server-14.0.4.Final.zip

本次测试infinispan的版本为最新稳定版14.0.4.Final。

3.1 准备工作

#将infinispan-server-14.0.4.Final.zip解压
unzip infinispan-server-14.0.4.Final.zip

infinispan 从14版本开始jdk需要11以上,也适用于JDK 17,18和19。

3.2 启动

$ cd /infinispan-server-14.0.4.Final/bin下
$ nohup ./server.sh -b 0.0.0.0 &

3.3 登录infinispan Server Management Console

浏览器中输入http://ip:11222/

必须输入凭据才能访问控制台。创建用户名和密码以继续。

使用以下命令创建用户名和密码,如下

bin/cli.sh user create admin -p admin -g admin

用户名是admin,密码也是admin

四、Infinispan单机部署(容器化单节点)

4.1 镜像拉取

docker pull quay.io/infinispan/server:14.0.4.Final

请拉取官方镜像,https://quay.io/repository/infinispan/server?tab=tags

4.2 准备工作

自定义docker网络

### 预先创建一个自定义的网络pk_net,此处的10.139可以自定义,不冲突即可
$ sudo docker network create --driver bridge --subnet 10.139.0.0/16 --gateway 10.139.0.1 pk_net

编写docker-compose-infinispan.yaml文件,内容如下:

version: '3.7'
services:
  infinispan:
    image: quay.io/infinispan/server:14.0.4.Final
    container_name: infinispan-server
    hostname: infinispan-server
    restart: always
    privileged: true
    environment:
      USER: admin
      PASS: admin
      TZ: Asia/Shanghai
    volumes:
      - /data/infinispan/server/conf/infinispan.xml:/opt/infinispan/server/conf/infinispan.xml
      - /data/infinispan/server/data:/opt/infinispan/server/data
      - /data/infinispan/server/lib:/opt/infinispan/server/lib
      - /data/infinispan/server/log:/opt/infinispan/server/log
    ports:
      - "11222:11222"
    networks:
      - pk_net
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:11222/rest/v2/cache-managers/default/health/status"]
      interval: 30s
      timeout: 20s
      retries: 3
networks:
  pk_net:
    external: true

参数说明:

  • healthcheck表示健康探测。
  • http://localhost:11222/rest/v2/cache-managers/default/health/status是获取缓存管理器健康状态接口。
  • 挂载/data和/log需要在宿主机上更改权限,如:chmod -R 777 /data/infinispan/server/data

infinispan.xml内容如下:

<infinispan
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="urn:infinispan:config:14.0 https://infinispan.org/schemas/infinispan-config-14.0.xsd
                            urn:infinispan:server:14.0 https://infinispan.org/schemas/infinispan-server-14.0.xsd"
      xmlns="urn:infinispan:config:14.0"
      xmlns:server="urn:infinispan:server:14.0">
   <cache-container name="default" statistics="true">
      <transport cluster="${infinispan.cluster.name:cluster}" stack="${infinispan.cluster.stack:tcp}" node-name="${infinispan.node.name:}"/>
      <security>
         <authorization/>
      </security>
   </cache-container>
   <server xmlns="urn:infinispan:server:14.0">
      <interfaces>
         <interface name="public">
            <inet-address value="${infinispan.bind.address:127.0.0.1}"/>
         </interface>
      </interfaces>
      <socket-bindings default-interface="public" port-offset="${infinispan.socket.binding.port-offset:0}">
         <socket-binding name="default" port="${infinispan.bind.port:11222}"/>
         <socket-binding name="memcached" port="11221"/>
      </socket-bindings>
      <security>
         <credential-stores>
            <credential-store name="credentials" path="credentials.pfx">
               <clear-text-credential clear-text="secret"/>
            </credential-store>
         </credential-stores>
         <security-realms>
            <security-realm name="default">
               <!-- Uncomment to enable TLS on the realm -->
               <!-- server-identities>
                  <ssl>
                     <keystore path="application.keystore"
                               password="password" alias="server"
                               generate-self-signed-certificate-host="localhost"/>
                  </ssl>
               </server-identities-->
               <properties-realm groups-attribute="Roles">
                  <user-properties path="users.properties"/>
                  <group-properties path="groups.properties"/>
               </properties-realm>
            </security-realm>
         </security-realms>
      </security>
      <endpoints socket-binding="default" security-realm="default" />
   </server>
</infinispan>

这是从容器中拷贝出来的。

或者采用docker run命令,如下:

docker run --name infinispan -d -p 11222:11222 -e USER="admin" -e PASS="password" quay.io/infinispan/server:14.0.4.Final

注意有些最小化镜像版本是没有管理界面,请选择合适的镜像版本。

五、infinispan集群部署(二进制部署)

infinispan的集群部署相对简单,在多个主机上部署Infinispan Server,Infinispan会自动发现(多播功能)整个网络上找到所有Infinispan Server实例加入到集群里面。

若是主机上存在多个网卡时,启动时需要通过-k指定集群ip,如下启动命令:

nohup ./bin/server.sh -b 192.168.0.201 -k 192.168.0.201 &
或者
nohup ./bin/server.sh -b 0.0.0.0 -k 192.168.0.201 &

如下:

通过7800来进行集群交互。

六、infinispan集群部署(容器化部署)

前面我们收到infinispan会自动发现(多播功能)整个网络上找到所有Infinispan Server实例加入到集群里面,但是容器化的方式,其默认的集群ip是容器ip,若是不改变集群ip,其它主机节点上的infinispan服务是无法加入集群。

编写docker-compose-infinispan.yaml文件,内容如下:

version: '3.7'
services:
  infinispan:
    image: quay.io/infinispan/server:14.0.4.Final
    container_name: infinispan-server
    hostname: infinispan-server
    restart: always
    privileged: true
    #改变集群ip
    command: ["-k 192.168.0.201"]
    environment:
      USER: admin
      PASS: admin
      TZ: Asia/Shanghai
    volumes:
      - /mnt/data/infinispan-docker/server/conf/infinispan.xml:/opt/infinispan/server/conf/infinispan.xml
      - /mnt/data/infinispan-docker/server/data:/opt/infinispan/server/data
      - /mnt/data/infinispan-docker/server/lib:/opt/infinispan/server/lib
      - /mnt/data/infinispan-docker/server/log:/opt/infinispan/server/log
    ports:
      - "11222:11222"
      - "7800:7800"
    #使用宿主机网络
    network_mode: host
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:11222/rest/v2/cache-managers/default/health/status"]
      interval: 30s
      timeout: 20s
      retries: 3

需要通过-k 192.168.0.201去改变集群ip,通过查看infinispan的源码发现其实-k 等同于--cluster-address,所以可以写command: ["--cluster-address=192.168.0.201"]。

源码Bootstrap中handleArgumentCommand方法:

@Override
   protected void handleArgumentCommand(String command, String parameter, Iterator<String> args) {
      switch (command) {
         case "-c":
            parameter = args.next();
            // Fall through
         case "--server-config":
            configurationFiles.add(Paths.get(parameter));
            break;
         case "-l":
            parameter = args.next();
            // Fall through
         case "--logging-config":
            loggingFile = Paths.get(parameter);
            break;
         case "-s":
            parameter = args.next();
            // Fall through
         case "--server-root":
            serverRoot = new File(parameter);
            break;
         case "-b":
            parameter = args.next();
            // Fall through
         case "--bind-address":
            properties.setProperty(Server.INFINISPAN_BIND_ADDRESS, parameter);
            break;
         case "-p":
            parameter = args.next();
            // Fall through
         case "--bind-port":
            properties.setProperty(Server.INFINISPAN_BIND_PORT, parameter);
            break;
         case "-n":
            parameter = args.next();
         case "--node-name":
            properties.setProperty(Server.INFINISPAN_NODE_NAME, parameter);
            break;
         case "-g":
            parameter = args.next();
         case "--cluster-name":
            properties.setProperty(Server.INFINISPAN_CLUSTER_NAME, parameter);
            break;
         case "-j":
            parameter = args.next();
         case "--cluster-stack":
            properties.setProperty(Server.INFINISPAN_CLUSTER_STACK, parameter);
            break;
         case "-k":
            parameter = args.next();
         case "--cluster-address":
            properties.setProperty(Server.JGROUPS_BIND_ADDRESS, parameter);
            break;
         case "-o":
            parameter = args.next();
            // Fall through
         case "--port-offset":
            properties.setProperty(Server.INFINISPAN_PORT_OFFSET, parameter);
            int offset = Integer.parseInt(parameter);
            if (!properties.containsKey(Server.JGROUPS_BIND_PORT)) {
               properties.setProperty(Server.JGROUPS_BIND_PORT, Integer.toString(Server.DEFAULT_JGROUPS_BIND_PORT + offset));
            }
            break;
         case "-P":
            parameter = args.next();
         case "--properties":
            try (Reader r = Files.newBufferedReader(Paths.get(parameter))) {
               Properties loaded = new Properties();
               loaded.load(r);
               loaded.forEach(properties::putIfAbsent);
            } catch (IOException e) {
               throw new IllegalArgumentException(e);
            }
            break;
         default:
            throw new IllegalArgumentException(command);
      }
   }

依次对应如下集群设置:

public static final String INFINISPAN_BIND_ADDRESS = "infinispan.bind.address";
   public static final String INFINISPAN_BIND_PORT = "infinispan.bind.port";
   public static final String INFINISPAN_CLUSTER_NAME = "infinispan.cluster.name";
   public static final String INFINISPAN_CLUSTER_STACK = "infinispan.cluster.stack";
   public static final String INFINISPAN_NODE_NAME = "infinispan.node.name";
   public static final String INFINISPAN_PORT_OFFSET = "infinispan.socket.binding.port-offset";
   public static final String JGROUPS_BIND_ADDRESS = "jgroups.bind.address";
   public static final String JGROUPS_BIND_PORT = "jgroups.bind.port";

或者采用docker run命令,如下:

docker run --name infinispan -d -p 11222:11222 -p 7800:7800 --net=host  -e USER="admin" -e PASS="admin" quay.io/infinispan/server:14.0.4.Final -k 192.168.0.201

-k 192.168.0.201 等同于--cluster-address=192.168.0.201

如下:

通过7800来进行集群交互,通过-k去指定集群ip,若是不指定,拿到的就是本地ip,即容器ip, 这样infinispan自动发现是没办法发现其他主机上的infinispan节点的。

相关文章
|
6天前
|
缓存 Linux
linux系统缓存机制
linux系统缓存机制
|
10天前
|
分布式计算 Ubuntu 调度
如何本地搭建开源分布式任务调度系统DolphinScheduler并远程访问
如何本地搭建开源分布式任务调度系统DolphinScheduler并远程访问
|
1月前
|
缓存 应用服务中间件 数据库
【分布式技术专题】「缓存解决方案」一文带领你好好认识一下企业级别的缓存技术解决方案的运作原理和开发实战(多级缓存设计分析)
【分布式技术专题】「缓存解决方案」一文带领你好好认识一下企业级别的缓存技术解决方案的运作原理和开发实战(多级缓存设计分析)
37 1
|
1月前
|
缓存 NoSQL Java
手撸的 SpringBoot缓存系统,性能杠杠的
手撸的 SpringBoot缓存系统,性能杠杠的
28 0
|
1月前
|
存储 分布式计算 大数据
现代化数据库技术——面向大数据的分布式存储系统
传统的关系型数据库在面对大规模数据处理时遇到了诸多挑战,而面向大数据的分布式存储系统应运而生。本文将深入探讨现代化数据库技术中的分布式存储系统,包括其优势、工作原理以及在大数据领域的应用。
|
1月前
|
消息中间件 存储 NoSQL
【Redis项目实战】使用Springcloud整合Redis分布式锁+RabbitMQ技术实现高并发预约管理处理系统
【Redis项目实战】使用Springcloud整合Redis分布式锁+RabbitMQ技术实现高并发预约管理处理系统
|
1月前
|
缓存
LRU 缓存置换策略:提升系统效率的秘密武器(下)
LRU 缓存置换策略:提升系统效率的秘密武器(下)
|
1月前
|
存储 缓存 算法
LRU 缓存置换策略:提升系统效率的秘密武器(上)
LRU 缓存置换策略:提升系统效率的秘密武器(上)
|
1月前
|
存储 缓存 算法
说说什么是本地缓存、分布式缓存以及多级缓存,它们各自的优缺点?
说说什么是本地缓存、分布式缓存以及多级缓存,它们各自的优缺点?
|
1月前
|
存储 Web App开发 运维
原来10张图就可以搞懂分布式链路追踪系统原理
原来10张图就可以搞懂分布式链路追踪系统原理