Apache Ignite 学习笔记(二): Ignite Java Thin Client
前一篇文章,我们介绍了如何安装部署Ignite集群,并且尝试了用REST和SQL客户端连接集群进行了缓存和数据库的操作。现在我们就来写点代码,用Ignite的Java thin client来连接集群。 在开始介绍具体代码之前,让我们先简单的了解一下Ignite的thin client,以及背后的binary client protocol(原本打算把thin client翻译为精简客户端,bianry client protocol翻译为二进制客户端协议,但总读的不顺口,就索性就不翻译了吧-_-|||)。
Ignite Thin Client和Binary Client Protocol介绍
为了缓存数据的高性能读写,Ignite是节点内部需要维护一套高效的数据结构来记录一些元数据,所以如果在自己的应用程序中启动一个Ignite的server/client节点是要占用一些应用程序的CPU/内存资源的。另外,Ignite是一个分布式系统,单个节点需要和集群里的其他节点通讯,又要消耗一些的网络资源。 因此不同于server/client节点,thin client是一个Ignite轻量化的客户端。为什么说它是轻量化的呢,因为thin client并不会加入到Ignite集群的拓扑中(即thin client的连接,断开不会导致Ignite集群拓扑发生变化,也不会触发相应的事件通知),不会存储任何集群的数据或是被做为计算节点接收计算任务。Thin client就是一个纯粹的客户端,它纯粹到通过最原始的socket连接到Ignite集群中的某一个节点进行所有的操作。
在Ignite集群成功启动后,我们会在日志看到“Topology snapshot [ver=1, servers=1, clients=0, CPUs=2, offheap=1.6GB, heap=1.0GB]”信息。这条日志里的clients和thin client不是一回事。按照之前介绍,thin client是不会加入Ignite集群的拓扑中去,理应不会出现在和拓扑相关的日志中,所以这里不要把thin client和集群中的client节点搞混了。
这个链接详细的介绍了Binary Client Protocol的数据格式(比如采用的是litter-endian,Ignite的二进制对象描述用户数据),消息格式(定义了消息头格式,响应消息的格式,以及连接时如何进行握手保证版本兼容等)和各种缓存操作所需的操作编码和格式。 所以只要你按照Binary Client Protocol的要求,你可以用任何一种语言实现一个thin client。目前Ignite发布了两种语言的thin client的实现,一个是基于Java实现,一个是基于.Net实现。
当然thin client虽然轻量化,也有它的问题。 Thin client写数据时只能先把数据发给其连接的节点,再由该节点将数据发送给集群内的其他节点做存储(同理,读数据也需要通过该节点才能传给thin client),这样thin client和这个节点间的网络很有可能就成为瓶颈。而server/client节点间可以互联,利用数据分区,可以充分使用节点间的带宽。另外,当前连接节点出故障后,thin client只能随机选择一个启动时已知的节点进行重试,由于其不感知集群拓扑,即便有新节点加入,thin client也无法知道其存在,更不可能和其进行通讯了。 所以还是要根据自己应用的场景,看看到底是server/client节点还是thin client更合适。
Ignite Java Thin Client例子
上一篇文章中,我们用Dbeaver连接Ignite后,用SQL语句进行建表,插入数据和查询数据。 在这个例子里,我们就来看看如何通过Ignite的thin client支持的JCache APIs进行相同的操作。
首先我们先用用maven命令创建一个新的project,然后在pom.xml文件中添加以下ignite-core的依赖:
<dependencies>
<dependency>
<groupId>org.apache.ignite</groupId>
<artifactId>ignite-core</artifactId>
<version>${ignite.version}</version>
</dependency>
</dependencies>
在看具体代码之前,让我们先来大概了解一下这个例子中我们要进行哪些操作以及步骤:
- 首先,我们通过thin client连接上我们已经启动的Ignite集群。
- 然后,通过API创建两个cache(cache的名字分别为province和city),一个用来存省份信息,一个用来存城市信息。 province缓存的key是省份的id,city缓存的key是城市的名称。
- 我们分别往两个cache里写入一些数据。
- 启动该程序时,可以从命令行传入多个城市名称,在终端我们会打印出该城市所在的省份信息。
下面是主程序的代码:
import org.apache.ignite.Ignition;
import org.apache.ignite.client.ClientCache;
import org.apache.ignite.client.ClientException;
import org.apache.ignite.client.IgniteClient;
import org.apache.ignite.configuration.ClientConfiguration;
public class IgniteThinClientExample {
private static ClientCache<Integer, Province> provinceCache;
private static ClientCache<String, City> cityCache;
public static void main(String[] args) {
System.out.println();
System.out.println("Ignite thin client example started.");
//连接到Ignite集群,默认端口号为10800
ClientConfiguration cfg = new ClientConfiguration().setAddresses("192.168.0.110:10800");
//用java的try-with-resource statement启动client
try (IgniteClient igniteClient = Ignition.startClient(cfg)){
System.out.println();
System.out.println("Begin create cache and insert data.");
//创建两个缓存,具体步骤见该函数
creatCacheAndInsertData(igniteClient);
System.out.println();
System.out.println("Begin query cache.");
//根据输入开始查询
for(String city : args)
{
//先用城市名字,查询city缓存
City c = cityCache.get(city);
Province p = null;
if (c != null)
{
//在用城市数据中的province id查询province缓存
p = provinceCache.get(c.getProvinceId());
}
//输出查询结果
if (c != null && p != null) {
System.out.println("Find " + c.getName() + " in province " + p.getName());
}
else
{
System.out.println("Cannot find " + city + " in any province.");
}
}
}
catch (ClientException e) {
System.err.println(e.getMessage());
}
catch (Exception e) {
System.err.format("Unexpected failure: %s\n", e);
}
}
private static void creatCacheAndInsertData(IgniteClient igniteClient)
{
//创建province缓存,用来存放省份信息,该缓存以省的id为key
final String PROVINCE_CACHE_NAME = "province";
provinceCache = igniteClient.getOrCreateCache(PROVINCE_CACHE_NAME);
//往province缓存中写入一些数据
int provinceId = 1;
final Province on = new Province(provinceId++, "Ontario");
final Province ab = new Province(provinceId++, "Alberta");
final Province qc = new Province(provinceId++, "Quebec");
provinceCache.put(on.getId(), on);
provinceCache.put(ab.getId(), ab);
provinceCache.put(qc.getId(), qc);
System.out.println("Successfully insert all provinces data.");
//创建city缓存,用来存放城市信息,该缓存以城市的名字为key
final String CITY_CACHE_NAME = "city";
cityCache = igniteClient.getOrCreateCache(CITY_CACHE_NAME);
//往city缓存写入一些数据
int cityId = 1;
final City toronto = new City(cityId++, "Toronto", on.getId());
final City edmonton = new City(cityId++, "Edmonton", ab.getId());
final City calgary = new City(cityId++, "Calgary", ab.getId());
final City montreal = new City(cityId++, "Montreal", qc.getId());
cityCache.put(toronto.getName(), toronto);
cityCache.put(edmonton.getName(), edmonton);
cityCache.put(calgary.getName(), calgary);
cityCache.put(montreal.getName(), montreal);
System.out.println("Successfully insert all city data.");
}
}
public class City {
private int id;
private String name;
private int provinceId;
...
}
public class Province {
private int id;
private String name;
...
}
成功的编译project后,我们可以启动这个client看看程序的输出结果:
$java -cp $IGNITE_HOME/libs/*:./ignite-thin-client-example-1.0-SNAPSHOT.jar IgniteThinClientExample Toronto Markham Edmonton Calgary
Ignite thin client example started.
Begin create cache and insert data.
Successfully insert all provinces data.
Successfully insert all city data.
Begin query cache.
Find Toronto in province Ontario
Cannot find Markham in any province.
Find Edmonton in province Alberta
Find Calgary in province Alberta
因为我们的city缓存中,并没有Markham的信息,所以查询Markham的时候我们也找不到对应的省份信息。但是查询Toronto,Edmonton和Calgary的时候,程序是能正确的返回其省份信息的。
在上面的例子中,有几个需要注意的地方:
- 在我们连接Ignite集群的时候,用的端口号10800。默认配置下,Ignite会监听该端口,等待thin client的连接。如果需要让Ignite集群用不同的端口号,可以修改集群启动时的配置文件,加入以下配置项(如果你是用上一篇文章的方法启动的Ignite集群, 配置文件在$IGNITE_HOME/config/default-config.xml):
<bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
<!-- Thin client connection configuration. -->
<property name="clientConnectorConfiguration">
<bean class="org.apache.ignite.configuration.ClientConnectorConfiguration">
<property name="host" value="192.168.0.100"/>
<property name="port" value="新的端口号"/>
<property name="portRange" value="30"/>
</bean>
</property>
</bean>
我们的插入和查询数据的时候,只用到了最简单缓存API--put和get。其实Ignite缓存的查询API比其他缓存更丰富,支持scan/SQL/text方式进行查询,这个我们会在后面的文章慢慢介绍。
我们用城市的名字查询完city缓存后,再拿着province id去查询province缓存。这两步查询其实是可以合并成一个SQL的join查询,在后面介绍SQL查询时,我们再来看看把两个缓存当做两张表做join操作。
总结
这篇文章我们介绍了Ignite的thin client,并用Ignite的Java think client实现了一个简单的例子,解释如何用thin client连接上Ignite集群,创建缓存,写入数据以及查询。 完整的代码和maven工程文件戳这里。
下一篇文章,我们看看如何在自己的Java代码里启动Ignite集群及其相关配置。
Apache Ignite 学习笔记(二): Ignite Java Thin Client的更多相关文章
- 学习笔记(二)--->《Java 8编程官方参考教程(第9版).pdf》:第七章到九章学习笔记
注:本文声明事项. 本博文整理者:刘军 本博文出自于: <Java8 编程官方参考教程>一书 声明:1:转载请标注出处.本文不得作为商业活动.若有违本之,则本人不负法律责任.违法者自负一切 ...
- Apache Ignite 学习笔记(一): Ignite介绍、部署安装和REST/SQL客户端使用
Apache Ignite 介绍 Ignite是什么呢?先引用一段官网关于Ignite的描述: Ignite is memory-centric distributed database, cachi ...
- Apache Ignite 学习笔记(三): Ignite Server和Client节点介绍
在前两篇文章中,我们把Ignite集群当做一个黑盒子,用二进制包自带的脚本启动Ignite节点后,我们用不同的客户端连接上Ignite进行操作,展示了Ignite作为一个分布式内存缓存,内存数据库的基 ...
- Java学习笔记二十:Java中的内部类
Java中的内部类 一:什么是内部类: (1).什么是内部类呢? 内部类( Inner Class )就是定义在另外一个类里面的类.与之对应,包含内部类的类被称为外部类. (2).那为什么要将一个类定 ...
- Apache Ignite 学习笔记(四): Ignite缓存冗余备份策略
Ignite的数据网格是围绕着基于内存的分布式key/value存储能力打造的.当初技术选型的时候,决定用Ignite也是因为虽然同样是key/value存储,它有着和其他key/value存储系统不 ...
- Apache Ignite 学习笔记(6): Ignite中Entry Processor使用
之前的文章我们其实已经用到了两种不同的方式访问Ignite中的数据.一种方式是第一篇文章中提到通过JDBC客户端用SQL访问数据,在这篇文章中我们也会看到不使用JDBC,如何通过Ignite API用 ...
- GuavaCache学习笔记二:Java四大引用类型回顾
前言 上一篇已经讲了,如何自己实现一个LRU算法.但是那种只是最基本的实现了LRU的剔除策略,并不能在生产中去使用.因为Guava Cache中使用的是SoftReference去做的value实现, ...
- Java基础学习笔记二十三 Java核心语法之反射
类加载器 类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,链接,初始化三步来实现对这个类进行初始化. 加载就是指将class文件读入内存,并为之创建一个Class对象.任 ...
- Java学习笔记二十七:Java中的抽象类
Java中的抽象类 一:Java抽象类: 在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就 ...
随机推荐
- Hadoop HBase概念学习系列之HRegion服务器(三)
所有的数据库数据一般是保存在Hadoop分布式系统上面的,用户通过一系列HRegion服务器获取这些数据.一台机器上一般只运行一个HRegion服务器,而且每一分区段的HRegion也只会被一个HRe ...
- 微软撤回sharepoint 2013 sp1
微软撤回sharepoint 2013 sp1, 现在已经不能下载32bits和64bits. 以下是我们发现的问题(未必一定和SP1有关) - Search SSA managed metadata ...
- LeetCode 休闲计划
老年退役选手的 LeetCode 休闲之旅 前言 不知不觉两年多的大学时光悄然流逝,浑浑噩噩的状态似乎从来没有离开过自己. 这两年刷题似乎一直是常态.在退役之后的现在,深感有些东西一段时间没有接触,很 ...
- C++第六次作业
前言 拿到作业的时候,整个人都不好了,虽然之前和同学说以后一起写游戏,画界面,然而现在的自己对界面的知识一窍不通,虽然同学分享了一些资料,但是通过这次作业,发现自己火候还是不够-- 问题描述及仓库地址 ...
- Django商城项目笔记No.15用户部分-用户中心邮箱验证
首先增加前端页面success_verify_email.html页面 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitiona ...
- canvas实例_在线画图工具
fadsfklasdjfklasjdklfjasdlk;fjasd;lfjaskl;dfjal
- Nowcoder 提高组练习赛-R1
https://www.nowcoder.com/acm/contest/172#question 单人报名300元,五人合报免费,于是就和学弟同学学长们组了一个三世同堂的队伍,高一的学长wzhqwq ...
- Linux chmod +755和chmod +777 各是什么意思呢?
你可以在linux终端先输入ls -al,可以看到如: -rwx-r--r-- (一共10个参数)第一个跟参数跟chmod无关,先不管.2-4参数:属于user5-7参数:属于group8-10参数: ...
- robotframe 自定义开发库
site-packages(这个路径一定要在系统path路径中)下面创建一个UserDefineLibrary文件夹:目录结构如下 ---- ----- UserDefineLibrary __ in ...
- C#委托+回调详解
今天写不完,明天会接着写的,,,, 学习C#有一段时间了,不过C#的委托+回调才这两天才会用,以前只是知道怎么用.前面的一篇文章,函数指针,其实是为这个做铺垫的,说白了委托就相当于C语言中的函数指针, ...