1.Hazelcast开源与商业化
Hazelcast 有开源版本和商用版本。
开源版本遵循 Apache License 2.0 开源协议免费使用。
商用版本需要获取特定的License。商用版本提供了数据高密度存储。
我们都知道jvm有自己特定的GC机制,无论数据是在堆还是栈中,只要发现无效引用的数据块,就有可能被回收。
而Hazelcast的分布式数据都存放在jvm的内存中,频繁的读写数据会导致大量的GC开销。使用商业版的Hazelcast会拥有高密度存储的特性,大大降低Jvm的内存开销,从而降低GC开销。
2.Hazelcast的特点
Hazelcast有以下几个突出特点。
2.1.去中心化集群
Hazelcast 没有任何中心节点(文中的节点可以理解为运行在任意服务器的独立jvm,下同),或者说Hazelcast 不需要特别指定一个中心节点。在运行的过程中,它自己选定集群中的某个节点作为中心点来管理所有的节点。
2.2.分布式存储
Hazelcast 的数据是分布式存储的。他会将数据尽量存储在需要使用该项数据的节点上,以实现数据去中心化的目的。在传统的数据存储模型中(MySql、MongDB、Redis 等等)数据都是独立于应用单独存放,当需要提升数据库的性能时,需要不断加固单个数据库应用的性能。即使是现在大量的数据库支持集群模式或读写分离,但是基本思路都是某几个库支持写入数据,其他的库不断的拷贝更新数据副本。这样做的坏处一是会产生大量脏读的问题,二是消耗大量的资源来传递数据——从数据源频繁读写数据会耗费额外资源,当数据量增长或创建的主从服务越来越多时,这个消耗呈指数级增长。
使用 Hazelcast 可以有效的解决数据中心化问题。他将数据分散的存储在每个节点中,节点越多越分散。每个节点都有各自的应用服务,而Hazelcast集群会根据每个应用的数据使用情况分散存储这些数据,在应用过程中数据会尽量“靠近”应用存放。这些在集群中的数据共享整个集群的存储空间和计算资源。
2.3.抗单点故障
集群中的节点是无中心化的,每个节点都有可能随时退出或随时进入。因此,在集群中存储的数据都会有一个备份(可以配置备份的个数,也可以关闭数据备份)。这样的方式有点类似于 hadoop,某项数据存放在一个节点时,在其他节点必定有至少一个备份存在。当某个节点退出时,节点上存放的数据会由备份数据替代,而集群会重新创建新的备份数据。
2.4.简易性
所有的 Hazelcast 功能只需引用一个jar包,除此之外,他不依赖任何第三方包。因此可以非常便捷高效的将其嵌入到各种应用服务器中,而不必担心带来额外的问题(jar包冲突、类型冲突等等)。他仅仅提供一系列分布式功能,而不需要绑定任何框架来使用,因此适用于任何场景。
Hazelcast 还支持服务器/客户端模型,支持脚本管理、能够和 Docker 快速整合等等。
3.Hazelcast数据管理
Hazelcast通过分片来存储和管理所有进入集群的数据,采用分片的方案目标是保证数据可以快速被读写、通过冗余保证数据不会因节点退出而丢失、节点可线性扩展存储能力。
3.1.分片原理
Hazelcast的每个数据分片(shards)被称为一个分区(Partitions)。分区是一些内存段,根据系统内存容量的不同,每个这样的内存段都包含了几百到几千项数据条目,默认情况下,Hazelcast会把数据划分为271个分区,并且每个分区都有一个备份副本。
当启动一个集群成员时,这271个分区将会一起被启动。
当增加更多的成员时,Hazelcast会将主数据和备份数据一个接一个的迁移到新成员上,最终达成成员之间数据均衡且相互备份。当Hazelcast发生扩展的时候,只有最小数量的分区被移动。
在Hazelcast 3.6版本中,新增了一种集群成员:“精简成员”(lite members),他的特点是不拥有任何分区。“精简成员”的目标是用于“高密度运算”任务(computationally-heavy task executions。估计是指CPU密集型运算)或者注册监听(listener) 。虽然“精简成员”没有自己的分区,但是他们同样可以访问集群中其他成员的分区。
当集群中的节点发送变动时(进入或退出),都会导致分区在节点中移动并再平衡,以确保数据均匀存储。但若是“精简节点”的进入或退出,并不会出现重新划分分区情况,因为精简节点并不会保存任何分区。
3.2.分区与数据
创建了分区以后,Hazelcast会将所有的数据存放到每个分区中。它通过哈希运算将数据分布到每个分区中。获取存储数据Key值(例如map)或value值(例如topic、list),然后进行以下处理:
(1)将设定的key或value转换成byte[];
(2)对转换后的byte[]进行哈希计算;
(3)将哈希计算的结果和分区的数量(271)进行模运算(同余运算、mod运算、%运算)。
因为byte[]是和271进行同模运算,因此计算结果一定会在0~270之间,根据这个值可以指定到用于存放数据的分区。
3.3.分区表
当创建分区以后,集群中的所有成员必须知道每个分区被存储到了什么节点。因此集群还需要维护一个分区表来追踪这些信息。
当启动第一个节点时,一个分区表将随之创建。表中包含分区的ID和标记了他所属的集群节点。
分区表的目标就是让集群中所有节点(包括“精简节点”)都能获取到数据存储信息,确保每个节点都知道数据在哪。集群中最老的节点(通常情况下是第一个启动的成员)定期发送分区表给所有的节点。
以这种方式,当分区的所有权发生变动时,集群中的所有节点都会被通知到。分区的所有权发生变动有很多种情况,比如,新加入一个节点、或节点离开集群等。如果集群中最早启动的节点被关闭,那么随后启动的节点将会继承发送分区表的任务,继续将分区表发送给所有成员。
4.Hazelcast vs redis
同样是内存数据库,Hazelcast和redis有什么不同呢?
4.1.线程模型
虽然Redis是单线程的,但它使用高性能核心和非常低的内存占用。这个优势使您可以在单台机器上轻松运行多个Redis实例,充分利用所有的CPU核心。
"脑裂"问题是一种网络问题,当节点之间失去通信,每个节点都认为自己是主节点,这可能导致数据损坏,因为多个节点访问同一个文件或磁盘。Redis的单线程模型能够在写操作期间防止"脑裂"问题;然而,Hazelcast的多线程模型则不能避免这个问题。
4.2.集群
Hazelcast通过UDP协议自动发现组播路由器。而Redis则不支持自动发现。Redis的开发者认为,与解决问题和管理完整环境的成本相比,自动发现并不能节省时间。
因此,Redis可以作为完全托管的服务提供商的一部分使用AWS、AZURE等云服务。这些完全托管的服务提供了诸如完全Redis自动化、支持、监控和管理等优势。因此,它们允许开发者专注于构建应用程序,而不是关注数据库本身。
4.3.内存处理
由于可靠的jemalloc内存分配器,Redis可以轻松处理数TB的内存。并且redis中的散列、列表和集合等数据类型被编码为非常高效地使用内存,平均节省了5倍的内存。
与此同时,Hazelcast的非商业版本将所有分布式数据存储在Java垃圾回收器服务的堆内存中。因此,随着数据量的增长,垃圾回收可能会导致应用程序执行中的暂停。这些暂停会影响应用程序的性能,并可能引发更严重的问题和错误。
4.4.性能对比
可参考官网的数据https://hazelcast.com/resources/hazelcast-vs-redis/
redis受限于并发线程数,而hazelcast可线性扩展并发线程数。