Apache Ignite内存数据组织
1.Ignite是什么?
Apache Ignite是一个支持水平扩展和容错的分布式内存计算平台,面向数据密集型应用,可以在TB级的数据上以内存级的速度构建实时应用。
1.1.Ignite定位
Ignite是不是内存数据库?
是,虽然Ignite的固化内存在内存和磁盘中都工作得很好,但是磁盘持久化可以禁用从而成为一个纯粹的内存数据库,支持SQL和分布式关联。
Ignite是不是内存数据网格(IMDG)?
是,Ignite是一个全功能的分布式键-值数据网格,它既可以用于纯内存模式,也可以带有Ignite的原生持久化,它也可以与任何第三方数据库集成,包括RDBMS和NoSQL。
Ignite是不是一个分布式缓存?
是,如果禁用原生持久化,Ignite就是一个分布式缓存,它实现了JCache规范(JSR107),并且提供了比规范更多的功能,包括分区和复制分布式模式、分布式ACID事务、SQL查询、原生持久化等等。
Ignite是不是分布式数据库?
是,在整个集群的多个节点中,Ignite中的数据要么是分区模式的,要么是复制模式的,这给系统带来了伸缩性,增加了弹性。Ignite可以自动地控制数据如何分区,另外,开发者也可以插入自定义(关系)函数,以及为了提高效率将部分数据并置在一起。
Ignite是不是关系型SQL数据库?
不完整,尽管Ignite的目标是和其他的关系型SQL数据库具有类似的行为,但是在处理约束和索引方面还是有不同的。Ignite支持一级和二级索引,但是只有一级索引支持唯一性,Ignite还不支持外键约束。
Ignite是不是磁盘或者只有内存的存储?
都是,Ignite中的原生持久化是可以开关的,这使得Ignite可以持有比可用内存量大得多的数据。尤其是,少量的操作型数据集可以只保存在内存中,而更大的无法放在内存中的数据集,可以放在磁盘上,将内存作为一个缓存层,可以获得更好的性能。
Ignite是不是一个NoSQL数据库?
不确切,和其他的NoSQL数据库一样,Ignite支持高可用和水平伸缩,但是,和其它的NoSQL数据库不同,Ignite支持跨越整个集群的ACID事务和SQL。
Ignite是不是事务型数据库?
不完整,ACID事务是支持的,但是仅仅在键-值API级别,Ignite还支持跨分区的事务,这意味着事务可以跨越不同服务器不同分区中的键。
在SQL层,Ignite支持原子性,还不是事务型一致性,社区计划在未来的版本中实现SQL事务。
Ignite是不是一个多模型数据库?
是,Ignite数据的建模和访问,同时支持键值和SQL,另外,Ignite还为在分布式数据上的计算处理,提供了强大的API。
Ignite是不是一个键-值存储?
是,Ignite提供了丰富的键-值API,兼容于JCache (JSR-107),并且支持Java,C++和.NET。
2.关键特性
2.1.分布式内存级SQL数据库
Ignite带来了一个兼容于ANSI-99、支持水平扩展和容错的分布式SQL数据库,根据需要,分布模式既可以是跨整个集群的分区模式,也可以是全复制模式。
和其它的分布式SQL数据库不同,Ignite的持久化存储将内存和磁盘都视为有效的存储层,磁盘层,即原生持久化存储,默认是禁用的,这时Ignite就是一个纯粹的内存数据库(IMjDB)。
和其他的SQL存储一样,也可以使用JDBC或者ODBC与Ignite进行交互,Ignite还为Java、.NET和C++开发者提供了原生的SQL API,并且性能更好。
Ignite的一个显著优势是,完全支持分布式SQL关联,Ignite的数据关联支持并置模式和非并置模式。如果是并置模式,关联是在每个节点的本地可用数据集上执行,而不需要在网络间移动大量的数据,在分布式数据库中,这样的方式提供了最好的扩展性和性能。
除了标准的SQL,Ignite还提供了强大的处理API。
-
键值API:Ignite的键值API可以使用户以键值存储的方式与Ignite交互,除了JCache规范(JSR107)支持的标准键值操作,Ignite还提供了分布式ACID事务、持续查询、扫描查询这样的扩展支持;
-
并置处理:这个方式允许直接在数据所在的节点直接执行分布式SQL关联或者自定义业务逻辑,避免了昂贵的序列化和网络开销。
2.2.键-值内存数据网格
Ignite提供了广泛的键-值API,可以作为一个内存数据网格,可以将Ignite视为一个分布式分区化的哈希映射,每个节点持有整个数据集的一部分,和其他的内存数据网格(IMDG)不同,Ignite可以同时将数据保存在内存和磁盘上,因此也就可以存储比可用物理内存多得多的数据。
目前,Ignite数据网格是分布式架构支持ACID事务或者原子化数据更新最快的实现之一。
第三方数据库
通过在应用和数据库层之间嵌入一个分布式缓存,Ignite会改进已有第三方数据库的性能和可扩展性,比如RDBMS、NoSQL或者基于Hadoop的存储,这种做法不需要对已有的数据进行替换,通过通读和通写,会保持与底层数据库的同步,Ignite会自动地与底层数据库事务进行合并,向用户透明地提供事务保证。
但是,这种方法也有限制,比如,SQL和扫描查询只能处理保存在缓存中的数据,不包括外部数据库,因为Ignite无法索引外部数据,如果希望磁盘上的数据也应该被索引到并且可以通过SQL访问,建议使用Ignite的原生持久化。
JCache API
Ignite的键-值API符合JCache规范(JSR107),支持如下功能:
-
内存键值存储;
-
基本的缓存操作;
-
ConcurrentMap API;
-
并置处理(EntryProcessor);
-
事件和指标;
-
可插拔的持久化。
扩展键-值API
除了标准的JCache API,Ignite还支持分布式的ACID事务、持续查询、并置处理等等。
Ignite数据网格甚至可以线性地增长到几百个节点,它通过强语义的数据位置和关系数据路由,来降低冗余数据噪声。它可以被视为一个分布式分区化的哈希映射,每个节点可以持有整个数据集的一部分,这意味着节点越多,缓存的数据也可以越多。
2.3.ACID事务
Ignite是一个强一致的平台,完全支持分布式ACID事务,内存和磁盘层,都提供一样的一致性保证。
Ignite的事务,可以跨越多个节点,多个缓存(或者说表)以及多个分区。对于应用来说,乐观锁和悲观锁都是可用的,乐观模式还支持无死锁事务,可以在业务代码层面避免分布式死锁。
二阶段提交协议
在分布式系统中,事务可能跨越多个节点,显然,要保证所有参与节点的数据一致性是一个很大的挑战。比如,如果一个节点故障,故障节点的事务就不能完整提交,在这类场景中,要保证数据一致性,一个广泛使用的方法是二阶段提交协议(2PC)。
Ignite带来了二阶段提交协议的最快实现,另外,如果事务只涉及一个分区或者一个节点,Ignite会使用一个更快的一阶段提交协议。在一个事务中,如果数据发生了变化,那么在变化提交之前,Ignite会在本地事务映射中保存一个事务的状态,提交时,数据会被发送到相关的远程节点,其中只有持有相关数据主副本的节点,才会参与事务。
一致性和Ignite持久化
如果使用了Ignite的原生持久化,那么所有的更新都会写入预写日志(WAL)文件中来保证一致性,即使事务执行期间集群或者某个节点故障,也没有问题。
WAL的目的是,以附加模式将更新传播到磁盘,这是将数据持久化到磁盘的最快方式,如果集群或者某个节点故障,WAL提供了一个故障场景的恢复机制,集群总是可以恢复到最近成功提交的事务状态。
一致性和第三方持久化
如果Ignite作为缓存层运行于第三方数据库之上,比如RDBMS,Ignite仍然会保证缓存数据和外部数据的事务一致性。比如,如果RDBMS作为持久化层,Ignite会在将提交消息发给相关的集群节点之前,将事务写入数据库,这样的话,如果在数据库层发生事务故障,Ignite仍然会将回滚消息发给所有的相关节点,从而保持两者之间的数据一致性。
2.4.并置处理
基于磁盘的系统,比如RDBMS以及NoSQL,通常使用传统的C/S模式,这时数据是要从服务端传输到客户端的,在客户端进行处理,然后可能被丢弃。这个方法无法扩展,因为在分布式系统中通过网络移动大量数据是非常昂贵的操作。
一个扩展性更好的方法是并置处理,它会反过来将计算带到数据实际驻留的服务端节点,它会在数据实际存储的地方执行高级的业务逻辑或者分布式SQL,甚至关联,避免了昂贵的序列化和网络开销。
2.5.机器学习
Ignite的机器学习(ML)是一套简单、可扩展以及高效的工具,可以构建可预测的机器学习模型,而不需要昂贵的数据传输。
将机器和深度学习加入Ignite的原理是很简单的,当前,如果要想让机器学习成为主流,数据科学家要解决两个主要的问题:
问题#1:常规数据迁移(ETL)
首先,模型是在不同的系统中训练和部署(训练结束之后)的,数据科学家需要等待ETL或者其他的数据传输过程,来将数据移至比如Apache Mahout或者Apache Spark这样的系统进行训练,然后还要等待这个过程结束并且将模型部署到生产环境。在系统间移动TB级的数据可能花费数小时的时间,此外,训练部分通常发生在旧的数据集上。
问题#2:水平扩展能力缺乏
第二个问题和扩展性有关。机器学习和深度学习需要处理的数据量不断增长,已经无法放在单一的服务器上。这促使数据科学家要么提出更复杂的解决方案,要么切换到比如Spark或者TensorFlow这样的分布式计算平台上。但是这些平台通常只能解决模型训练的一部分问题,这给开发者之后的生产部署带来了很多的困难。
无ETL和大规模扩展性
Ignite的机器学习依赖于Ignite基于内存的存储,这给机器学习和深度学习任务带来了大规模的扩展性,并且取消了在不同系统间进行ETL产生的等待。比如,在Ignite集群的内存和磁盘中存储的数据上,开发者可以直接进行深度学习和机器学习的训练和推理,然后,Ignite提供了一系列的机器学习和深度学习算法,对Ignite的分布式并置处理进行优化,这样在处理大规模的数据集或者不断增长的输入数据流时,这样的实现提供了内存级的速度和近乎无限的扩展性,而不需要将数据移到另外的存储。通过消除数据的移动以及长时间的处理等待,Ignite的机器学习可以持续地进行学习,可以在最新数据到来之时实时地对决策进行改进。
容错和持续学习
Ignite的机器学习能够对节点的故障容错。这意味着如果在学习期间节点出现故障,所有的恢复过程对用户是透明的,学习过程不会被中断,就像所有节点都正常那样获得结果。
2.6.多语言支持
Ignite是以Java语言为主进行开发的,因此可以在JVM支持的任何操作系统和架构上部署和运行,比如,Ignite可以部署在Linux、Windows、MacOS、Oracle Solaris等操作系统上,支持x86、x64、SPARC、PowerPC指令集架构。
Java的API支持Ignite的所有功能,使用Java或者Scala开发的应用,相关的逻辑可以直接嵌入Ignite,然后借助于SQL以及键-值操作与集群进行交互,执行分布式计算和机器学习算法等等。
除了Java,Ignite还支持.NET平台,Ignite.NET和Ignite C++使用JNI,会把大部分的调用转发给Java,这里需要注意的是,JNI的负载非常小,不会导致性能的下降,尤其是在分布式环境,整体的应用性能中网络是主要的开销。
使用标准的JDBC或者ODBC连接,可以像其他的SQL存储一样与Ignite进行交互。Ignite还为Java、.NET和C++开发者提供原生的SQL API,性能更好。
要使用其他的语言访问Ignite,比如Python、Ruby、PHP或者NodeJS,可以考虑使用Ignite的二进制客户端协议,JDBC或者ODBC驱动,或者文档中提到的其他客户端协议。
3.扩展特性
3.1.服务网格
服务网格可以在集群中任意部署自定义的服务,可以实现和部署任意服务,比如自定义计数器,ID生成器,分级映射等。
服务网格的主要应用场景是提供了在集群中部署各种单例服务的能力。但是,如果需要一个服务的多实例,Ignite也能保证所有服务实例的正确部署和容错。
3.2.数据注入和流计算
Ignite流式计算允许以可扩展和容错的方式处理连续不中断的数据流。在一个中等规模的集群中,数据注入Ignite的比例会很高,很容易达到每秒百万级的规模。
Ignite可以与主要的流处理技术和框架进行集成,比如Kafka、Camel、Storm或者JMS,他们可以为基于Ignite的架构带来非常强大的功能。
数据加载
Ignite提供了若干种技术来对数据进行预加载,比如,开启原生持久化后,Ignite的流处理API就是一个好的选择,如果使用第三方存储,那么使用CacheStore
API可以直接接入。
工作方式:
-
客户端将流式数据注入Ignite;
-
数据在Ignite数据节点中自动分区;
-
数据在
滑动窗口
中并发处理; -
客户端在流式数据中执行并发
SQL查询
; -
客户端订阅数据变化的
持续查询
。
3.3.RDBMS集成
Ignite支持与各种持久化存储进行集成,它可以接入数据库、导入模式、配置索引类型、以及自动化地生成所有必要的XML OR映射配置和Java领域模型POJO,他们可以很容易地导入自己的开发工程。
Ignite可以与任何支持JDBC驱动的关系型数据库(RDBMS)进行集成,包括Oracle, PostgreSQL, Microsoft SQL Server, 和MySQL。
RDBMS集成向导
通过Web控制台,Ignite支持自动化的RDBMS集成,它是一个交互式的配置向导、管理和监控工具,功能包括:
-
创建和下载各种集群的配置文件;
-
从任何RDBMS模式中自动化地构建Ignite的SQL元数据;
-
在内存缓存中执行SQL查询;
-
查看查询的执行计划、内存模式和流化图表。
这个Web控制台是一个创新的工具,它提供了丰富的功能来管理集群,并不限于上述提到的这些功能。
3.4.分布式数据结构
Ignite以分布式的形式支持基于java.util.concurrent
框架的大部分数据结构。比如,可以在一个节点上使用java.util.concurrent.BlockingQeque
加入一些东西,然后再另一个节点上获取它。或者有一个分布式的ID生成器,他可以保证所有节点上的ID唯一性。
支持的数据结构包括:
-
Concurrent Map (Cache)
-
分布式队列和集合
-
AtomicLong
-
AtomicReference
-
AtomicSequence (ID生成器)
-
CountDownLatch
-
ExecutorService
3.5.消息和事件
Ignite提供了集群范围的高性能的消息功能,支持基于发布-订阅以及直接点对点通信模型的数据交换。消息可以以有序的,也可以以无序的方式进行交换。有序消息会稍微有点慢,但是如果使用的话,Ignite会保证收到消息的顺序和发送消息的顺序一致。
当在分布式网格环境中发生各种事件时,Ignite的分布式事件功能可以使应用收到通知。可以自动地收到集群内的本地和远程节点上发生的任务执行、读写和查询操作的通知,事件通知也可以分组在一起然后分批或者定期地发送。
4.架构
4.1.集群和部署
Ignite集群基于无共享架构,所有的集群节点都是平等的,独立的,整个集群不存在单点故障。
通过灵活的Discovery SPI组件,Ignite节点可以自动地发现对方,因此只要需要,可以轻易地对集群进行缩放。
Ignite可以独立运行,可以组成集群,可以运行于Kubernetes和Docker容器中,也可以运行在Apache Mesos以及Hadoop Yarn上,可以运行于虚拟机和云环境,也可以运行于物理机,从技术上来说,集群部署在哪里,是没有限制的。
服务端、客户端和协议
Ignite中定义有两种类型的节点,客户端和服务端节点,分别有不同的用途。
服务端节点作为数据和计算的容器,一旦接入,Ignite就会作为分布式数据库(或者叫数据网格)存储数据,然后参与查询的处理、计算的执行、数据流处理等等。
而对于客户端节点,提供了远程接入分布式数据库(一组服务端节点)的功能,Ignite的原生客户端可以使用完整的Ignite API,包括SQL、事务、计算、数据流、服务等等。
除了客户端节点,还可以通过Ignite的二进制客户端协议、JDBC/ODBC驱动、REST API接入集群。
公有云
对于公共云环境,Ignite原生集成了Amazon AWS
以及Google Compute Engine
,对于其他的云环境,Ignite集成了JCloud,它支持了大部分的已有云服务商。
容器
Ignite完全支持容器环境,Ignite与Docker
的集成可以在服务启动之前,自动地将业务代码构建并且部署进Ignite。
Ignite也可以部署在Kubernetes
中,可以自动地部署和管理容器化的应用。
资源管理器
Ignite提供了对Hadoop Yarn
,Kubernetes
和Apache Mesos
的原生支持,可以很容易地部署到这些环境。
4.2.基于内存的存储
Ignite基于分布式的内存架构,它将内存计算的性能和扩展性,与磁盘持久化和强一致性整合到一个系统中。
基于内存的方式和传统的基于磁盘的方式的主要不同是,Ignite将内存视为全功能的存储,而不是像传统大多数数据库那样仅仅是一个缓存层。比如,Ignite可以运行于纯内存模式,这时它就是一个内存数据库(IMDB)和内存数据网格(IMDG)。
另一方面,如果打开了持久化,Ignite就变成了一个处理是在内存中进行的基于内存的系统,但是数据和索引又持久化到磁盘上。这里与传统的基于磁盘的RDBMS或NoSQL系统的主要区别是,Ignite支持强一致、水平扩展、并且同时支持SQL和键-值处理API。
并置和C/S处理
基于磁盘的系统,比如RDBMS或者NoSQL,通常采用传统的C/S模式,数据需要从服务端传输到要处理的客户端,通常最终又被废弃,这种方法不可扩展,因为在分布式系统中,通过网络移动大量数据是非常昂贵的开销。
一个更有扩展性的方式是,通过将计算放在数据实际存储的服务端上,反过来实现并置处理,这个方法可以直接在数据实际存放的地方直接执行业务逻辑或者分布式SQL关联,避免了昂贵的序列化和网络开销。
分区和复制
根据配置,Ignite在内存存储中,可以是分区模式,也可以是复制模式,复制模式中,数据在集群中的每个节点都有一份副本,而分区模式,Ignite会在多个集群节点上对数据进行平均拆分,因此可以在内存及磁盘上存储TB级的数据。
冗余
Ignite可以配置多个副本,来保证故障时的数据弹性。
一致性
不管使用哪种复制方案,Ignite都会保证整个集群的数据一致性。
Ignite作为内存存储
持久化对Ignite来说是可选的,这时整个集群就会工作于纯内存模式,所有的数据和索引都会只存储于内存中,这样会得到最高的性能,因为数据不需要写入磁盘。为了避免可能的节点故障导致数据丢失,建议适当地配置一些备份(或者叫复制因子)。
Ignite持久化
可以有两种方式开启持久化,第一个方式是,使用它自己的分布式、ACID以及兼容SQL的持久化,这可以透明地与所有的内存架构透明且高效地集成。
如果开启了原生持久化,Ignite会在磁盘上存储数据的超集,然后在内存中存储尽可能多的数据。比如,一共有100条数据,内存有能力存储20条,那么磁盘会存储所有的100条,而为了高性能,内存可以只缓存20条。
Ignite与第三方数据库
第二个开启持久化的方式,是将Ignite部署在已有的第三方数据库之上,比如RDBMS、Apache Cassandra或者MongoDB。这种方式通过将部分数据的副本放在内存中,用于对底层数据库进行加速。Ignite支持通读和通写模式,确保数据一致性以及两者之间的同步。
4.3.固化内存
Ignite基于固化内存架构,如果开启了原生持久化,可以同时处理存储于内存和磁盘上的数据和索引。
固化内存架构,它将内存计算的性能和扩展性,与磁盘持久化和强一致性整合到一个系统中。
Ignite固化内存的操作方式,类似于比如Linux这样的操作系统的虚拟内存。但是两者的显著区别是,如果开启了持久化存储,除了将整个或者部分数据保存在内存中,还会将整个数据集加上索引放在磁盘上,而虚拟内存只是在内存用尽时才使用磁盘,磁盘只是用于交换用途。
Ignite原生持久化
Ignite原生持久化是数据持久化的一个非常灵活、可扩展以及方便的方式,它广泛应用于应用需要一个分布式内存数据库的场景中。
Ignite的原生持久化是一个分布式的、ACID、兼容SQL的磁盘存储,它可以与Ignite的固化内存无缝地集成,Ignite原生持久化是可选的,可以打开和关闭,如果关闭,Ignite就是一个纯内存存储。
下面是Ignite作为一个平台,如果固化内存和原生持久化同时使用的优势和特点:
内存
-
堆外内存
-
避免明显的GC暂停
-
自动碎片整理
-
可预测的内存消耗
-
高SQL性能
磁盘
-
可选的持久化
-
支持闪存、SSD以及Intel的3D Xpoint
-
存储数据的超集
-
全事务化(预写日志WAL)
-
集群瞬时启动
第三方持久化
Ignite可以用于已有第三方数据库的缓存层,包括RDBMS、NoSQL或者HDFS。该方式用于对保存数据的底层数据库进行加速,Ignite将数据保存在内存中,在多个节点中进行分布,提供了更快的数据访问,它减少了应用和数据库之间因为数据移动导致的网络负载。但是与原生持久化相比,是有很多限制的,比如,SQL查询只能在内存中保存的数据上执行,因此,首先需要将数据预先从磁盘加载到内存中。
交换空间
如果不希望使用原生持久化或者第三方持久化,还可以开启交换,这时,如果内存过载,内存中的数据会被移动到磁盘上的交换空间中,如果开启了交换空间,Ignite将数据存储于内存映射文件(MMF)中,根据当前的内存使用量,操作系统会将MMF的内容交换到磁盘。交换空间通常用于避免由于内存过载导致的内存溢出错误(OOME),以及需要更多时间来对集群进行缩放,从而对数据集进行更平均的分布的场景。
5.数据可视化
Ignite可以与很多数据可视化工具集成,通过图表或者丰富的图形,协助对存储在分布式缓存中的数据进行分析和解释,甚至提供可操作的建议。
IgniteWeb控制台
Ignite的Web控制台是一个基于Web的交互式管理工具, 功能包括:
-
创建、下载Ignite的各种配置;
-
从RDBMS中自动加载SQL元数据;
-
接入Ignite集群然后执行SQL;
-
管理和监控Ignite节点和缓存;
-
查看堆、CPU以及其它有用的节点和缓存的指标;
Tableau
Tableau是一个聚焦于商业智能的交互式数据可视化工具,通过Ignite的ODBC驱动,Tableau就可以接入Ignite集群,功能包括:
-
查询集群中存储的分布式数据;
-
缓存数据的表格或者图形展示;
-
使用Tableau支持的各种方式对数据进行分析;
Zeppelin
Apache Zeppelin是一个基于Web的记事本,可以交互式地对数据进行分析,通过Ignite的JDBC驱动,Zeppelin就可以接入集群,功能包括:
- 通过Ignite的SQL解释器获取分布式数据; - 缓存数据的表格或者图形展示; - 通过Scala执行分布式的计算。
6.Ignite & Spark
6.1.Spark共享内存层
Ignite共享RDD
Apache Ignite提供了一个Spark RDD抽象的实现,他允许跨越多个Spark作业时方便地在内存内共享状态,在不同的Spark作业、worker或者应用之间,IgniteRDD为内存中的相同数据提供了一个共享、可变的视图,原生的SparkRDD无法在多个Spark作业或者应用之间进行共享。
IgniteRDD
作为Ignite分布式缓存的视图,既可以在Spark作业执行进程中部署,也可以在Spark worker中部署,也可以在它自己的集群中部署。根据预配置的部署模型,状态共享既可以只存在于一个Spark应用的生命周期的内部(嵌入式模式
),或者也可以存在于Spark应用的外部(独立模式
)。
虽然SparkSQL支持丰富的SQL语法,但是它没有实现索引。这样即使在一个不太大的数据集上执行查询,也可能花费比较长的时间,因为需要对数据进行全部扫描。如果使用Ignite,开发者可以配置一级和二级索引,带来上千倍的性能提升。
Ignite DataFrames
Spark的DataFrame API引入了模式的概念来描述数据,这样Spark就可以以表格的形式管理模式和组织数据。简而言之,DataFrame就是组织成命名列的分布式数据集合。它从概念上来说,等价于关系数据库的表,会促使Spark执行查询优化器,产生比RDD更高效的执行计划,而RDD仅仅是集群中的一个分区化的元素集合。
Ignite扩展了DataFrame,如果将Ignite作为Spark的内存层,会简化开发以及提高性能,好处包括:
-
通过向Ignite读写DataFrames,可以在Spark作业之间共享数据和状态;
-
通过高级的索引以及避免数据在网络中的移动,优化Spark的查询执行计划,使Spark查询速度更快。