Apache Ignite高性能分布式网格框架-初探
Apache Ignite初步认识
今年4月开始倒腾openfire,过程中经历了许多,更学到了许多。特别是在集群方面有了很多的认识,真正开始认识到集群的概念及应用方法。
在openfire中使用的集群解决方案是代理+分布式内存。所谓代理便是通过一个入口转发请求到多个服务实例。而分布式内存就是解决服务实例间数据共享问题。通过这两步就可以搭建出一套水平扩展的集群系统。
openfire使用的分布式内存计算框架是hazelcast,并不了解它,大概只知道它是分布式网格内存计算框架。听许多openfire开发者都吐槽hazelcast有许多问题,集群效果上不太好,也因此意外间的发现了Ignite。
Ignite是apache基金的一个开源项目,功能与hazelcast非常类似:
Apache Ignite内存数据组织是高性能的、集成化的以及分布式的内存平台,他可以实时地在大数据集中执行事务和计算,和传统的基于磁盘或者闪存的技术相比,性能有数量级的提升。
特性:
可以将Ignite视为一个独立的、易于集成的内存组件的集合,目的是改进应用程序的性能和可扩展性,部分组件包括:
- 高级的集群化
- 数据网格(JCache)
- 流计算和CEP
- 计算网格
- 服务网格
- Ignite文件系统
- 分布式数据结构
- 分布式消息
- 分布式事件
- Hadoop加速器
- Spark共享RDD
已经有国内的大神做了翻译,可以看看这个链接:https://www.zybuluo.com/liyuj/note/481591
这里面有Ignite的手册,介绍的还是比较清楚的。
启动一个Ignite吧
只要少量的代码我们就可以将Ignite应用到自己的系统中,比如我需要做一个缓存。
- 在工程中通过Maven引入
Ignte的最小引入包就是一个ignite-core.jar包依赖
<dependency> <groupId>org.apache.ignite</groupId> <artifactId>ignite-core</artifactId> <version>${ignite.version}</version> </dependency>
这样就行啦。。
- 启动Ignite创建并使用缓存
我们需要创建一个缓存,那么如何整呢?
Ignite ignite = Ignition.start();
这一句代码就启动了一个Ignite节点,整个过程不需要配置就这么简单的跑起来了。
好了,再创建一个缓存用来存用户的ID和姓名:
IgniteCache<Integer, String> cache = ignite.getOrCreateCache("userInfo");
cache.put(1, "小明");
这样就over了,是不是感觉和使用hashmap差不多?但重要的是什么,如果有另外一个ignite节点起来了,它们会自动发现并组成集群,那么userInfo这个缓存就会自动的完成分布式存储咯。
只不过有点问题,默认情况下缓存模式是分区模式,当然分区模式下需要设置缓存的备份数量backups,如果不设置的话缓存并不会在其他节点上做备份。
什么意思呢?就是说系统中有一个节点node1,这时候存了userInfo,此时node2启动了,并且自动发现后node1和node2建立了集群,不过node1突然挂了,此时系统会访问node2的数据,结果就失败啦。也就是说默认配置下数据是不会自带分布式存储的。需要做一下缓存的配置才行。
可以在创建缓存的时候指定一下缓存的配置:
CacheConfiguration cfg = new CacheConfiguration(); cfg.setCacheMode(CacheMode.PARTITIONED); cfg.setBackups(1); cfg.setName("userInfo"); IgniteCache<Integer, String> cache = ignite.getOrCreateCache(cfg); cache.put(1, "小明");
Ignite提供了三种不同的缓存操作模式,分区、复制和本地。可以参考这里的介绍:https://www.zybuluo.com/liyuj/note/393469#33缓存模式
Ignite配置Tomcat WebSession练练手
我最开始拿Ignite的用处主要是做缓存使用,而且其支持JCache的特性和集群化做缓存非常合适,特别是未来部署成分布式也很平滑。但是目前我使用的还比较浅,估计入门都不算,这也可见Ignite使用多么简单,基本上看看手册就可以上手了。
这些天我还是想尝试一下Ignite的WebSession的集群功能,为以后Web系统集群做一个基础。之前的使用Redis的方案总觉得不是特别爽,虽然对代码的侵入性低,但不是java系列的。目前Ignite官方给出了WebSession集群的指南:https://www.zybuluo.com/liyuj/note/393469#318web会话集群化
我根据这个指南做了尝试,效果基本达到,但是对于像我这样的初学者面对这个手册会遇到一些问题。首先在配置后启动系统后发现会报一个异常:
严重: Exception starting filter IgniteWebSessionsFilter class org.apache.ignite.IgniteException: Cache for web sessions is not started (is it configured?): partitioned at org.apache.ignite.cache.websession.WebSessionFilter.initCache(WebSessionFilter.java:336) at org.apache.ignite.cache.websession.WebSessionFilter.init(WebSessionFilter.java:292) at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:279) at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:260) at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:105) at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4854) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5546) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1575) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1565) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745)
这个问题我查了蛮久,后来还是@李玉珏给了指导解决了。问题的原因是WebSessionFilter初始化时找不到对应的缓存。我查看了代码:
@SuppressWarnings("unchecked") void initCache() { cache = webSesIgnite.cache(cacheName); binaryCache = webSesIgnite.cache(cacheName); if (cache == null) throw new IgniteException("Cache for web sessions is not started (is it configured?): " + cacheName);
报错的代码就是因为cache为null导致的。这里比较重要的是
cache = webSesIgnite.cache(cacheName);
在前面举的例子中我们获取一个缓存是用getOrCreateCache方法,这个方法会在缓存不存在的情况下自动创建一个缓存,但是cache方法却不会。所以要解决这个问题就是要在Ignite启动后先把缓存创建好。
但是整个过程我们并没有手动显式的去启动Ignite,是WebSessionFilter在Init的时候获取的,所以我们可以通过配置的方式将缓存首先创建。
如何指定Ignite XML文件加载?
需要创建一个XML文件,并将其放在Web目录的META-INF目录下面,比如创建一个default-config.xml文件,文件内容如下:
<?xml version="1.0" encoding="UTF-8"?> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="org.apache.ignite.configuration.IgniteConfiguration" > <property name="cacheConfiguration"> <bean class="org.apache.ignite.configuration.CacheConfiguration"> <!-- Cache name. --> <property name="name" value="partitioned"/> <property name="cacheMode" value="PARTITIONED"/> <property name="backups" value="1"/> </bean> </property> </bean> </beans>
这里的配置意思是创建一个name为partitioned的缓存,使用分区模式,备份数为1.再次启动web程序就可以啦。
结合Spring方式
对于使用Spring的应用是可以集成Ignite缓存的,配置方式需要通过一个缓存抽象类来完成org.apache.ignite.cache.spring.SpringCacheManager。
在自己项目的Spring里做如下配置:
<!-- Provide configuration bean. --> <bean id="cacheManager" class="org.apache.ignite.cache.spring.SpringCacheManager"> <property name="configuration"> <bean class="org.apache.ignite.configuration.IgniteConfiguration"> <property name="cacheConfiguration"> <bean class="org.apache.ignite.configuration.CacheConfiguration"> <!-- Cache name. --> <property name="name" value="partitioned"/> <property name="cacheMode" value="PARTITIONED"/> <property name="backups" value="1"/> </bean> </property> </bean> </property> </bean>
总结
可以看到Ignite的使用还是非常简单的,特别是其配置的简单性,很容易上手,轻松就搭建了一套分布式内存系统。而且对于Ignite来说还有更多的高级特性,参考"特性"部分。接下来还需要再继续深入了解。
另外对于作为缓存使用我在j2cache开源项目里有简单的集成,代码可以看:https://github.com/mini188/j2cache