内存数据库之Apache Ingite

内存数据库(in-memory database,IMDB)是指那些完全用主存作为数据存储的数据库管理系统,由于节省下来磁盘的I/O开销,与基于磁盘的传统数据库管理系统而言效率要高很多。

内存数据库非常适合在

小规模数据应用

快速原型系统实现

软件测试

等场景中应用。还清晰记得记得当时我们在一个项目中即想利用数据库的查询优化、但是数据量又小到足以被内存容纳的情况下,满街找DB2中类似的开关……

现在有不少比较成熟基于Java的内存数据库,使用起来跟连接一个jar没什么区别。下面介绍我使用过的一些开源免费的产品。

HSQLDB

HSQLDB是一个开源免费的纯Java数据库,与ANSI-92 SQL兼容得不错,速度非常快,而且同时支持嵌入式和C/S模式。1.8.0.10整个jar包仅仅700K,使用起来跟普通jar包没有不同。如果没有弄错的话,HSQLDB还被OpenOffice采用。期待1.9.0早日来到。

H2

个人觉得H2是HSQLDB的一个重写。非常快(感觉比HSQLDB更快)、开源免费、提供JDBC和ODBC接口,同时支持嵌入式、C/S模式以及阵列模式,仅仅占用1M左右的内存。此外,H2还很贴心地提供了一个很小的基于Applet的SQL工具。在我的使用过程中,感觉H2与HSQLDB一样对SQL 92支持得很不错。

Apache Derby

源自IBM的数据库,与HSQLDB和H2想比,主要感觉速度慢,而且对SQL 92的兼容性不佳,个别被MySQL支持的语句都无法顺利在Derby上执行。还有些bug,虽然在升级包中修复了。虽然如此,Derby被捐献到Apache基金后,相信会有更大的作为吧。

随着时间的推移,相信内存数据库会更成熟、有更广阔的应用空间。

最近一段时间研究了内存数据库,总结了一下,分享给大家。我们先从应用场景说起。

一. 内存数据库的应用场景

  • 数据缓存:将经常使用的数据存放在内存中,全局共享,减少和数据库之间的交互频率,提升数据访问速度,主要用于应用程序全局共享缓存。
  • 内存计算:支持通过标准SQL或者LINQ的方式实现对内存数据的聚合、计算和查询,充分发挥、利用应用服务器的资源。

二. 业界有哪几类主流的内存数据库

1. 关系型内存数据库

  • 传统关系型数据库场景下,应用层的数据缓存
  • 将传统的关系型数据库表搬到内存中,内存数据和数据库数据之间进行结构映射
  • 支持通过SQL语句的方式实现对内存数据的访问,更加贴合业务实现
  • 将经常使用的数据存放在内存中,减少和数据库之间的交互频率,提升数据访问速度
  • 数据实时/定时同步
  • 有限的事务保证

2. 键值对内存数据库

  • 键值对存储结构
  • 按Key进行数据读取
  • Value支持各种数据类型
  • 类似Redis

3. 传统数据库的内存数据库引擎

  • SQL Server  2016 In Memory OLTP
  • MySQL Memory Engine
  • 在数据库层面提供了内存数据库引擎机制,最大程度的减少磁盘IO
  • 数据类型有一定的限制
  • 事务支持
  • 数据持久化保证

还有Oracle 的Timesten、SAP的HANA等,这些商业中间件不在我们研究的范围之内。

那么,传统数据库和内存数据库之间是什么关系? 相互补充、珠联璧合的关系

内存数据库不会独立于传统数据库而单独存在,因为内存是易失的。现在具有持久化功能的内存库,如redis、couchbase等,其持久化功能相较传统数据库还较溥弱,持久化性能也不如传统数据库。因此,内存数据库在一段时期内,将是传统数据库的一种强有力的补充。

如果说传统数据库是一支军队,那么内存数据库就是为执行某种特殊任务的特种部队,不要求功能多,但一定要快速、迅猛。

我们继续一一对比分析一下上面所述的几类内存数据库。

三. 业界主流的内存数据库

1. SQL Server 2016 In-Memory OLTP

SQL Server 2016的In-Memory OLTP,通俗地讲,是内存数据库,使用内存优化表(Memory-Optimized Table,简称MOT)来实现,MOT驻留在内存中,使用 Hekaton 内存数据库引擎访问。在查询MOT时,只从内存中读取数据行,不会产生Disk IO消耗;在更新MOT时,数据的更新直接写入到内存中。内存优化表能够在Disk上维护一个数据副本,该副本只用于持久化数据,不用于数据读写操作。

在内存数据库中,不是所有的数据都需要存储在内存中,有些数据仍然能够存储在Disk上,硬盘表(Disk-Based Table,简称DBT)是传统的表存储结构,每个Page是8KB,在查询和更新DBT时,产生Disk IO操作,将数据从Disk读取到内存,或者将数据更新异步写入到Disk中。

内存数据库将原本存储在Disk上的数据,存储在内存中,利用内存的高速访问优势实现数据的快速查询和更新,但是,内存数据库,不仅仅是存储空间的变化,Hekaton 内存数据库访问引擎实现本地编译模块(Natively compiled),交叉事务(Cross-Container Transaction)和查询互操作(Query Interop):

本地编译模块:如果代码模块只访问MOT,那么可以将该模块定义为本地编译模块,SQL Server直接将TSQL脚本编译成机器代码;SQL Server 2016支持本地编译的模式有:存储过程(SP),触发器(Trigger),标量值函数(Scalar Function)或内嵌多语句函数(Inline Multi-Statement Function)。相比于解释性(Interpreted)TSQL 模块,机器代码直接使用内存地址,性能更高。

交叉事务:在解释性TSQL模块中,一个事务既能访问硬盘表,也能访问内存优化表;实际上,SQL Server创建了两个事务,一个事务用于访问硬盘表,一个事务用于访问内存优化表,在DMV中,分别使用transaction_id 和 xtp_transaction_id 来标识。

查询互操作:解释性TSQL脚本能够访问内存优化表和硬盘表,本地编译模块只能访问内存优化表。

内存数据被整合到SQL Server关系引擎中,使用内存数据库时,客户端应用程序甚至感受不到任何变化,DAL接口也不需要做任何修改。由于Query Interop的存在,任何解释性TSQL脚本都能透明地访问MOT,只是性能没有本地编译TSQL脚本性能高。在使用分布式事务访问MOT时,必须设置合适的事务隔离级别,推荐使用Read Committed,如果发生MSSQLSERVER_41333 错误,说明产生交叉事务隔离错误(CROSS_CONTAINER_ISOLATION_FAILURE),原因是当前事务的隔离级别太高。

 

内存数据库技术选型

本文中,我们继续深入研究Apache Ignite,同时分享一些我们.Net的编码实践。

首先,Apache Ignite是一个内存数据组织是高性能的、集成化的以及分布式的内存平台,他可以实时地在大数据集中执行事务和计算,和传统的基于磁盘或者闪存的技术相比,性能有数量级的提升。

其中:

Data Grid:Ignite内存数据网格是一个内存内的键值存储,他可以在分布式集群的内存内缓存数据。
它通过强语义的数据位置和关系数据路由,来降低冗余数据的噪声,使其可以节点数的线性增长,直至几百个节点。
Ignite数据网格速度足够快,经过官方不断的测试,目前,他是分布式集群中支持事务性或原子性数据的最快的实现之一。

SQL Grid:内存SQL网格为Apache Ignite提供了分布式内存数据库的功能,它水平可扩展,容错并且兼容SQL的ANSI-99标准。 SQL网格支持完整的DML命令,包括SELECT, UPDATE, INSERT, MERGE以及DELETE。 同时支持分布式SQL Join关联

RDBMS集成: Ignite支持与各种持久化存储的集成,它可以连接数据库,导入模式,配置索引类型,以及自动生成所有必要的XML OR映射配置和Java领域模型POJO,这些都可以轻易地下载和复制进自己的工程。
Ignite可以与任何支持JDBC驱动的关系数据库集成,包括Oracle、PostgreSQL、MS SQL Server和MySQL

Apache Ignite 的功能特性有:

  • 分布式键值存储:Ignite数据网格是一个内存内的键值存储,分布式的分区化的哈希,集群中每个节点都持有所有数据的一部分,这意味着集群内节点越多,就可以缓存的数据越多。 Ignite通过可插拔的哈选算法来决定数据的位置,每个客户端都可以通过插入一个自定义的哈希函数来决定一个键属于那个节点,并不需要任何特殊的映射服务或者命名节点。
  • 内存优化:Ignite在内存中支持2种模式的数据缓存,堆内和堆外。当缓存数据占用很大的堆,超过了Java主堆空间时,堆外存储可以克服JVM垃圾回收(gc)导致的长时间暂停,但数据仍然在内存内。
  • SQL查询:Ignite支持使用标准的SQL语法(ANSI 99)来查询缓存,可以使用任何的SQL函数,包括聚合和分组。
  • 分布式关联:Ignite支持分布式的SQL关联和跨缓存的关联。
  • ACID事务:Ignite提供了一个完全符合ACID的分布式事务来保证一致性。 支持乐观和悲观的并发模型以及读提交、可复制读和序列化的隔离级别。 Ignite的事务使用了二阶段提交协议,适当地也进行了很多一阶段提交的优化。
  • 同写和同读:通写模式允许更新数据库中的数据,通读模式允许从数据库中读取数据。
  • 数据库异步更新:Ignite提供了一个选项,通过后写缓存来异步地执行数据库更新
  • 自动持久化:自动化地连接底层数据库并且生成XML的对象关系映射配置和Java领域模型POJO
  • 数据库支持:Ignite可以自动地与外部数据库集成,包括RDBMS、NoSQL和HDFS。

Apache Ignite具有非常先进的集群能力,部署非常灵活。

  • 节点平等:Ignite没有master节点或者server节点,也没有worker节点或者client节点,按照Ignite的观点所有节点都是平等的。但是开发者可以将节点配置成master,worker或者client以及data节点。
  • 自动发现机制:Ignite节点之间会自动感知,集群可扩展性强,不需要重启集群,简单地启动新加入的节点然后他们就会自动地加入集群。这是通过一
  • 个发现机制实现的,他使节点可以彼此发现对方,Ignite默认使用TcpDiscoverySpi通过TCP/IP协议来作为节点发现的实现,也可以配置成基于多播的或者基于静态IP的,这些方式适用于不同的场景。
  • 部署模式:Ignite可以独立运行,也可以在集群内运行,也可以将几个jar包嵌入应用内部以嵌入式的模式运行,也可以运行在Docker容器以及Mesos和Yarn等环境中,可以在物理机中运行,也可以在虚拟机中运行,这个广泛的适应性是他的一个很大的优势。
  • 配置方式:Ignite的大部分配置选项,都同时支持通过基于Spring的XML配置方式以及通过Java代码的编程方式进行配置。
  • 客户端和服务端:Ignite中各个节点是平等的,但是可以根据需要将节点配置成客户端或者服务端,服务端节点参与缓存,计算,流式处理等等,而原生的客户端节点提供了远程连接服务端的能力。Ignite原生客户端可以使用完整的Ignite API,包括近缓存,事务,计算,流,服务等等。
  • 所有的Ignite节点默认都是以服务端模式启动的,客户端模式需要显式地启用。

上面大致介绍了Apache Ignite的架构和功能特性,现在我们以代码示例的方式,分享一下做的技术原型验证:

1. 启动Apache Ignite

代码中通过调用Ignition.Start()启动一个Ignite节点。

直接执行apache.Ignite.exe也可以启动一个Ignite节点,其内部引用了Apache.Ignite.Core.dll,调用了Ignition.Start()方法

  • Ignite可以Host在Console和Winform中
  • Ignite依赖Oracle JDK 7及更高版本
  • Ignite可以独立运行
  • 存在跨进程访问的情况

2. 创建指定的缓存区域

3. 数据写入缓存

4.数据查询

5. 数据关联查询

6.查询指定的字段

 

7.全文搜索

8. Apache Ignite集群部署

节点平等

Ignite没有master节点或者server节点,也没有worker节点或者client节点,按照Ignite的观点所有节点都是平等的。但是开发者可以将节点配置成master,worker或者client以及data节点。

自动发现机制

Ignite节点之间会自动感知,集群可扩展性强,不需要重启集群,简单地启动新加入的节点然后他们就会自动地加入集群。这是通过一个发现机制实现的,他使节点可以彼此发现对方,Ignite默认使用TcpDiscoverySpi通过TCP/IP协议来作为节点发现的实现,也可以配置成基于多播的或者基于静态IP的,这些方式适用于不同的场景。

部署模式

Ignite可以独立运行,也可以在集群内运行,也可以将几个jar包嵌入应用内部以嵌入式的模式运行,也可以运行在Docker容器以及Mesos和Yarn等环境中,可以在物理机中运行,也可以在虚拟机中运行,这个广泛的适应性是他的一个很大的优势。
配置方式
Ignite的大部分配置选项,都同时支持通过基于Spring的XML配置方式以及通过Java代码的编程方式进行配置,这个也是个重要的优点。

9. 客户端和服务端

Ignite中各个节点是平等的,但是可以根据需要将节点配置成客户端或者服务端,服务端节点参与缓存,计算,流式处理等等,而原生的客户端节点提供了远程连接服务端的能力。Ignite原生客户端可以使用完整的Ignite API,包括近缓存,事务,计算,流,服务等等。

代码以Client模式启动Ignite

Client/Server架构,带来了很大的问题!!

  • 每个使用Ignite的主机都要安装JDK,同时启动一个Ignite Client节点
  • 开发、运维、管理成本很高

10. Apache Ignite REST API

 

来源: https://blog.csdn.net/zdy0_2004/article/details/79520492

 

https://ignite.apache.org/