ignit就是一款分布式内存库。日常使用的时候其实就是和其他的内存库功能类似,本质上都是利用内存缩短读取时间。无论数据源是何处来。
一、结构
整体结构
ignite整体分为服务端和客户端。而客户端又分为胖客户端(官方文档中只是叫客户端)和瘦客户端。
服务端存储、计算、处理数据;胖客户端本质和服务端没有区别,但是其不具备服务端的存储功能,最多缓存部分数据(近缓存),其是和服务端一起构成一个集群,集群中一个个服务端/客户端视为一个个节点。
而客户端则是处于集群之外,只能存取集群内部节点数据,仅作为用户跳板来操作集群内部数据,瘦客户端与当前节点连接失败时,客户端可自动切换到可用节点(需要在客户端配置中提供用于故障转移节点的地址列表)。
数据结构
ignite的数据结构可以分为两个维度:逻辑结构和物理存储结构。
在ignite的逻辑中,数据结构分为SQL表和键值对结构,虽然两者是等同的。
这也就给了我们两个方向去获取ignite数据:通过键获取值和sql语句。
在后续也会说明:通过键获取的存储数据对应通过sql语句获取,其中键与表名对等。通过键获取的存储数据也是一个个键值对,与表字段和字段值对等。
但是,当数据作为表存储时,需要指定一个字段作为主键。
从物理存储逻辑上看,这两者是一致的。ignite的物理存储单元是数据条目(或表数据行),以二进制对象存储,数据条目的集合被分为:分区。分区均匀地分布在所有节点上。数据和分区之间以及分区和节点之间的映射方式都由关联函数控制。关联函数控制数据条目和分区以及分区和节点之间的映射。
ignite也提供了不同的分区模式:PARTITIONED和REPLICATED模式。
- PARTITIONED模式将节点均匀的分布在每一个节点上,每个节点只存在部分分区,所有分区共同组成一个至多个完整缓存。
- REPLICATED模式则是在一个节点中只有一个主分区,其余为分区副本。但是分区数和节点数并不一定要一致。在该分区模式下,一个节点即可提供完整缓存。
二、基本使用
以ignite的2.12.0版本为例。服务端往往按需定制ignite的bean配置文件即可,而客户端则需要根据代码手动配置。
2.0.服务端
以使用服务端最基本的配置为例。ignite的bean实现格式是固定的,所有的配置都是放在唯一的一个bean配置中:
<bean id="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
</bean>
开启的方式就是启动脚本ignite.cmd/bat 加上指定的配置类就可以,成功创建服务端节点会打节点信息。
下面说明一些服务端基本的配置:
-
日志配置 把日志提到最开始说是因为ignite的配置采用
插件的方式。在ignite-core包中并不包含其他的功能,例如log4j的配置。其默认的是java.util.logging框架。以配置log4j为例,首先需要将ignite官方包libs目录下的optional目录中的ignite-log4j文件夹整体放入lib下即可。然后再配置:<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration"> <!-- 日志ignite-log4j2 模块,(部分低版本需要ignite-cust)--> <property name="gridLogger"> <bean class="org.apache.ignite.logger.log4j2.Log4J2Logger"> <constructor-arg type="java.lang.String" value="apache-ignite-2.12.0-bin/node-1-log4j2.xml"/> </bean> </property> </bean> </beans> -
集群间节点发现方式配置 节点发现方式常用的有两种:zookeeper和tcp,其中以zookeeper使用最多。
- zk发现配置
<property name="discoverySpi"> <bean class="org.apache.ignite.spi.discovery.zk.ZookeeperDiscoverySpi"> <property name="zkConnectionString" value="127.0.0.1:2181,127.0.0.1:2191,127.0.0.1:2201"/> <property name="sessionTimeout" value="60000"/> <property name="zkRootPath" value="/ignite_cache"/> <property name="joinTimeout" value="30000"/> </bean> </property>- 其中
zkConnectionString配置为zk的地址:端口。这个是必须配置的。 sessionTimeout表示与zk会话超时时间,注意该值配置最好要大于zk的tickTime * syncLimit时间,因为当zk超过该时间时会发起zk集群间节点会发起同步,如果ignite节的超时时间恰好到该时刻,很有可能导致某一zk节点(向其他zk节点发起同步状态)下的ignite节点误认为该zk以掉线,从而触发ignite的断尾保全机制:直接丢弃该部分igite节点。zkRootPath则指定了ignite节点信息在zk的根路径名字。
- 其中
- tcp发现配置,基本是采用组播的方式
其中,TcpDiscoveryMulticastIpFinder类是tcp发现方式的核心类,其最低配置要求是<property name="discoverySpi"> <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi"> <property name="ipFinder"> <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder"> <property name="addresses"> <list> <value>127.0.0.1:47500..47599</value> </list> </property> </bean> </property> </bean>addresses内的地址:端口范围,同一集群的节点配置必须一致。如果不一致,则会造成无意的集群隔离现象,使得原本的一个集群被分为多个互不干扰的集群。
- zk发现配置
-
针对瘦客户端连接的配置
<property name="clientConnectorConfiguration"> <bean class="org.apache.ignite.configuration.ClientConnectorConfiguration"> <property name="port" value="23333"/> <property name="portRange" value="50"/> <property name="socketSendBufferSize" value="32768"/> <property name="socketReceiveBufferSize" value="32768"/> </bean> </property>客户端是处于集群外的,和服务端的通信需要另外配置。ClientConnectorConfiguration 就是管理瘦客户端的配置类。
配置的最低要求是
port,其指定该服务端与胖客户端的端口。此外,还可以配置portRange设置端口开启范围,当配置的端口被占用时,ignite会依次向后开启端口,直到有一个找到一个能用的端口或者全部不行后报错。此外,
ocketSendBufferSize和socketReceiveBufferSize可以配置每次客户端查询时服务端收发的缓存大小。如果不配置,ignite的默认值都是0。 -
对等类配置,默认是不开启的 对于对等类的配置我也不是很懂,只知道官方是建议配置开启的。欢迎大佬来补充。
个人认为开启后可以使得Java客户端可以互相通信。
<property name="peerClassLoadingEnabled" value="true"/>
2.1.胖客户端
-
开启客户端
胖客户端可以认为是无法存储数据的服务端,但是其可以开启近缓存,缓存少量(相较于服务端的存储而言)热点数据,其配置也只需要设置ignite的节点模式为client即可:
IgniteConfiguration cfg = new IgniteConfiguration(); //客戶端方式启动 cfg.setClientMode(true);同样,其也可以配置节点发现方式,以下是zk和tcp的发现方式配置:
//设置节点发现 //需要引入ignite-zookeeper包 ZookeeperDiscoverySpi zkSpi = new ZookeeperDiscoverySpi(); zkSpi.setZkConnectionString("127.0.0.1:2181"); zkSpi.setSessionTimeout(30000); zkSpi.setZkRootPath("/ignite"); zkSpi.setJoinTimeout(15000); cfg.setDiscoverySpi(zkSpi); /*------------------------*/ //ip finder 找到本机上的节点 TcpDiscoveryMulticastIpFinder ipFinder = new TcpDiscoveryMulticastIpFinder(); ipFinder.setAddresses(Collections.singletonList("127.0.0.1:47500..47509")); cfg.setDiscoverySpi(new TcpDiscoverySpi().setIpFinder(ipFinder));需要额外注意的是,客户端的zk配置的zk地址和节点路径需要和服务端一致,而tcp的地址也是如此。
开启客户端也很简单,只需调用 Ignition 类的 start(IgniteConfiguration cfg) 方法即可。
下面附上完整代码:
package org.client import org.apache.ignite.Ignite; import org.apache.ignite.Ignition; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; import org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder; import org.apache.ignite.spi.discovery.zk.ZookeeperDiscoverySpi; import java.util.Collections; /** * 胖客户端演示 */ public class RichClient { private Ignite ignite; public Ignite getIgniteByTcpIp() { IgniteConfiguration cfg = new IgniteConfiguration(); //客戶端方式启动 cfg.setClientMode(true); //可以通过该类进行网络传输 cfg.setPeerClassLoadingEnabled(true); //ip finder 找到本机上的节点 TcpDiscoveryMulticastIpFinder ipFinder = new TcpDiscoveryMulticastIpFinder(); ipFinder.setAddresses(Collections.singletonList("127.0.0.1:47500..47509")); cfg.setDiscoverySpi(new TcpDiscoverySpi().setIpFinder(ipFinder)); // Starting the node ignite = Ignition.start(cfg); return ignite; } public Ignite getIgniteByZk() { IgniteConfiguration cfg = new IgniteConfiguration(); cfg.setClientMode(true); cfg.setPeerClassLoadingEnabled(true); //设置节点发现 //需要引入ignite-zookeeper包 ZookeeperDiscoverySpi zkSpi = new ZookeeperDiscoverySpi(); zkSpi.setZkConnectionString("127.0.0.1:2181"); zkSpi.setSessionTimeout(30000); zkSpi.setZkRootPath("/ignite"); zkSpi.setJoinTimeout(15000); cfg.setDiscoverySpi(zkSpi); return Ignition.start(cfg); } } -
常用的方法
胖客户端常见创建和获取缓存的方法很简单:
public void getIgniteByTcpIpTest() { final Ignite ignite = new RichClient().getIgniteByTcpIp(); //如果缓存存在就销毁 if (ignite.cacheNames().contains("cache1")) { ignite.destroyCache("cache1"); } //创建缓存 IgniteCache<String, String> firstCache = ignite.createCache("cache1"); firstCache.put("1","演示1"); //获取缓存,不存在就报错 IgniteCache<String, String> cache = ignite.cache("cache1"); String example = cache.get("1"); System.out.println("第一次演示" + example); /*上述创建的方法在缓存存在时会报错,可以用下面的方法*/ IgniteCache<String, String> sedCache = ignite.getOrCreateCache("cache2"); sedCache.put("2","演示2"); System.out.println("第二次演示" + sedCache.get("2")); }ignite缓存每次创建都是独立的,每个缓存都可以配置缓存策略等等。这就要用到CacheConfiguration,事实上如果将数据库加载至ignite中时,常常会用该类来制定每张表的缓存策略(每张表都归为独立的缓存)。
public void igniteCreateCacheByConfig() { final Ignite ignite = new RichClient().getIgniteByTcpIp(); /*通过缓存配置来设置改缓存策略,同时,该方式适用于sql存储 * Person类也就三个String字段:name,age,number。这里就不详细列出了。 */ CacheConfiguration<String, Person> peopleCacheConfig = new CacheConfiguration<>("people"); /*设置分区策略和该缓存备份*/ peopleCacheConfig.setCacheMode(CacheMode.PARTITIONED).setBackups(1); /*创建缓存*/ IgniteCache<String, Person> orCreateCache = ignite.getOrCreateCache(peopleCacheConfig); Person p1 = new Person("紬壮壮", "17", "17372121082"); orCreateCache.put(p1.getNumber(),p1); /*-------------------------*/ IgniteCache<String, Person> peopleCache = ignite.cache("people"); /*通过索引来找到对应的记录*/ System.out.println(peopleCache.get("17372121082").toString()); peopleCache.remove("17372121082"); }
2.2.瘦客户端
瘦客户端的使用和胖客户端类似,但是类完全不同。
-
开启瘦客户端
虽然官方建议用try-with-resources的方式来开启瘦客户端,但是通常客户端创建后再使用ignite期间是不关闭的,用单例或者连接池的方式管理都可以。
public class ThinClient { /*这里用的是IgniteClient*/ private IgniteClient thinClient; public IgniteClient initClient() { if (thinClient != null) { return thinClient; } synchronized (this) { if (thinClient != null) { return thinClient; } //瘦客户端为轻量客户端,不支持配置zk搜寻节点 ClientConfiguration clientConfig = new ClientConfiguration(); //这里的配置是集群中指定的节点和通信端口 clientConfig.setAddresses("127.0.0.1:23333"); thinClient = Ignition.startClient(clientConfig); } return thinClient; } }注意到,瘦客户端用的是IgniteClient类,而对应的对应的客户端配置用的是ClientConfiguration,而非胖客户端的IgniteConfiguration。因为
瘦客户端是独立于ignite集群,所以瘦客户端不能像胖客户端那样配置集群发现。但是,可以使用curator去读约定的ignite集群在zk里的配置,然后传入该配置类中。此外,需注意的是,瘦客户端配置的地址只是集群中的节点和端口,该端口要在服务端中额外配置,这一点在开始的服务端配置第三点已经示例的了。
而开启客户端的方法也变为了startClient方法。
-
常见方法
瘦客户端的缓存类是ClientCache。其存储缓存则和胖客户端一致。
public void AddressTest(){ IgniteClient thinClient = new ThinClient().initClient(); ClientCache<Object, Object> cache1 = thinClient.getOrCreateCache("thinClientCache1"); //瘦客户端能够操作胖客户端大多数的操作,比如存入/读取缓存 cache1.put("1","瘦客户端通过地址首次配置"); //没有就报错 cache1 = thinClient.cache("thinClientCache1"); System.out.println(cache1.get("1")); /*-------------------------------*/ /*采用缓存配置创建缓存,但是无法再配置阶段就指定键和缓存类型*/ ClientCacheConfiguration peopleClientConfig = new ClientCacheConfiguration(); peopleClientConfig.setName("Person") .setCacheMode(CacheMode.PARTITIONED) .setBackups(1); ClientCache<String, Person> cache = thinClient.getOrCreateCache(peopleClientConfig); Person daiwei = new Person("呆唯", "17", "16526771092"); cache.put(daiwei.getNumber(),daiwei); //另一种获取缓存方式 ClientCache<String, Person> peopleCache = thinClient.cache("Person"); System.out.println(peopleCache.get("16526771092").toString()); peopleCache.remove("16526771092"); }瘦客户端的缓存配置类是ClientCacheConfiguration,其无法像胖客户端那样创建时就制定键和缓存类型,需要在创建缓存时单独指定。其余缓存策略和胖客户端一致。