概述
注意: 本期主要介绍hazelcast数据存储的功能, 因此原理调研仅针对于数据网格这一部分进行调研。
简介
首先看官网介绍图:
官网介绍:
Hazelcast是一个统一的实时数据平台,专门用于处理数据。它拥有高性能、高可用、故障恢复、云无关性、可调一致性、安全、可扩展的特性。
Hazelcast 采用 Java 语言实现,拥有 Java、C++、.NET、REST、Python、Go 和 Node.js 客户端。 Hazelcast 还支持 Memcached 和 REST 协议。您的云原生应用程序可以轻松使用 Hazelcast。它足够灵活,可以用作开箱即用的数据和计算平台,也可以用作您自己的云原生应用程序和微服务的框架。
整体认知
对hazelcast的这个产品的整体认知可以从官网的这张图感受出来, 即从各种数据源获取的数据, 通过hazelcast分布式数据处理平台处理后,在吐给其他数据处理中间件
拥有的产品
- hazelcast platform: 大而全的分布式计算和存储平台
- hazelcast management: 后台管理平台, 用于可视化的管理hazelcast 计算和存储平台
- hazelcast IMDG: hazelcast数据网格,主要提供分布式存储能力,内置了一些开箱即用的分布式数据结构(queue, map等等)
- hazelcast Cloud: hazelcast云平台, 支持各大云厂商的接入,即满足云无关性(cloud agnostic)
数据网格
简介
Hazelcast IMDG是一个开源分布式内存对象存储,支持多种数据结构, 之所以被称之为数据网格,是因为其数据分散在多个分区。
Hazelcast IMDG 具有高度可扩展性和可用性。分布式应用程序可以将其用于分布式缓存、同步、集群、处理、发布/订阅消息传递等。它是用 Java 语言实现的,拥有 Java、C++、.NET、REST、Python、Go 和 Node.js 的客户端。 Hazelcast IMDG 还支持 Memcached 和 REST 协议。它插入 Hibernate,并且可以轻松地与任何现有数据库系统一起使用。
Hazelcast IMDG 通过提供许多开发人员友好的接口的分布式实现,使分布式计算变得简单。例如,Map 接口提供了内存中键值存储,这在开发人员友好性和开发人员生产力方面赋予了 NoSQL 的许多优势。
特性
- 自治集群:无中心化:不需要指定中心节点,运行的过程中自己选定某个节点作为中心点来管理所有节点
- 数据按应用分布式存储:数据分散地存储在每个节点中,节点越多越分散。每个节点都有各自的应用服务,集群会根据每个应用的数据使用情况分散存储这些数据,数据共享整个集群的存储空间和计算资源。
- 抗单点故障:集群中的数据可配置备份数,也可关闭备份。配置备份的情况下,当某个节点退出,节点上存放的数据会由备份数据代替,集群会重新创建新的备份数据。
- 简易性:引入功能只需要一个jar包。因此可以高效地嵌入到各种应用服务器中,不必担心额外问题。仅提供一系列分布式功能,不需要绑定任何框架。
架构图
集群部署方式
C/S模式
- 概念: 独立部署节点集群,应用通过客户端api进行读写调用。Hazelcast数据和服务集中在一个或多个节点上,应用通过客户端读写数据。可以部署一个提供服务的独立Hazelcast集群,服务集群可以独立创建,独立扩展。客户端通过和集群中的节点交互来获取Hazelcast数据和服务。Hazelcast提供Java,.NET、C++、Memcache和REST客户端。
- 结构:
- 优缺点:
- 优点:集群服务独立部署,不与业务耦合,业务重启不影响缓存数据;
- 不便于业务持久化的实现;客户端访问节点数据,存在节点间数据通信的开销
内嵌模式
- 概念:Hazelcast集群中的一个节点包括:应用程序,Hazelcast分区数据,Hazelcast服务三部分;如果更关注异步或高性能计算和执行大量任务,使用内嵌部署模式比较合适
- 结构:
- 优缺点:
- 优点: 随应用服务的集群启动服务节点,直接通过服务节点访问数据,性能开销低;
- 缺点:依赖应用服务的启停,缓存数据需要重新初始化;
数据分片
对于集群数据,分片的目标是
- 数据能被快速读写;
- 备份数据不因节点退出而丢失;
- 线性可扩展存储能力。
分片过程
每个数据分片称为一个分区,其实是一些内存段,所有数据默认会划分为271个主分区,每个分区都有一个备份副本
- 启动一个集群成员时,271个分区会被一起启动;
- 启动第二个成员时,第一个成员有135个主分区,并在第二个成员中存在一个副本;同样第一个成员也有第二个成员的副本数据;
- 启动增加更多成员时,hz会将主数据和备份数据一个接一个迁移到新成员上,最终达成数据均衡且相互备份
总体上说,hz会平均分配成员之间的分区,并均匀地在成员之间创建备份;节点的进入或退出,都会让分区在节点间移动再平衡。
数据如何分片
分区算法
hz将数据通过对key(例如map)或者value(例如topic,list)哈希运算后将数据存放到对应分区中。
- 将设定的key或者value转换成byte[];
- 对转换后的byte[]进行hash计算;
- hash结果对271进行模运算,得到指定的分区。(该模的结果 - MOD(哈希结果,分区计数) - 是将存储数据的分区,即分区 ID 。对于集群中的所有成员,给定键的分区 ID 始终相同。)
分区表
当启动一个成员时,会在其中创建一个分区表。该表存储分区 ID 及其所属的集群成员。该表的目的是让集群中的所有成员(包括lite成员)都知道这些信息,确保每个成员都知道数据在哪里。
集群中最老的成员(第一个启动的成员)定期向所有成员发送分区表。通过这种方式,集群中的每个成员都会收到有关分区所有权的任何更改的通知。例如,当新成员加入集群或成员离开集群时,所有权可能会发生更改。
重新分区
当成员加入或离开集群时,Hazelcast 会执行重新分区。
集群配置选项
静态配置
静态配置允许您在运行前通过提供配置文件或使用 API 来配置 Hazelcast。静态配置在运行时无法更改。
静态配置方式,类似spring的配置方式:
- 声明式: 使用hazelcast.xml来启动
- 编程式: 使用代码来进行集群配置
- 系统配置: 使用系统属性来配置 Hazelcast 集群
- spring集成: Configure Hazelcast for Spring integration
集群发现机制
官方提供了自动检测(auto-detection),组播协议Multicast,TCP/IP协议,AWS,K8s,Azure,GCP,Eureka等发现方式进行集群搭建
组播模式
Hazelcast 允许集群成员使用多播通信找到彼此。组播模式就是在内网部署的情况下,同一台机器里部署多个成员, 成员间会自动发现并组成集群。
<hazelcast>
...
<network>
<join>
<multicast enabled="true">
<multicast-group>224.2.2.3</multicast-group>
<multicast-port>54327</multicast-port>
<multicast-time-to-live>32</multicast-time-to-live>
<multicast-timeout-seconds>2</multicast-timeout-seconds>
<trusted-interfaces>
<interface>192.168.1.102</interface>
</trusted-interfaces>
</multicast>
</join>
</network>
...
</hazelcast>
<multicast> 元素用来配置 组播协议 组网的相关参数。当设置 <multicast> 元素中 enabled 属性为 true 时,表示启用 组播协议 组网。每个参数如下:
multicast-group:组播分组的IP地址。当要创建同一个网段的集群时,需要配置这个参数。取值范围从224.0.0.0到239.255.255.255,默认224.2.2.3。
multicast-port:组播协议启用套接字的端口(socket port),这个端口用于Hazelcast监听外部发送来的组网请求。默认54327。
multicast-time-to-live:组播协议发送包的生存时间周期(TTL)。可以从 协议官方文档 详细了解组播协议的TTL。
multicast-timeout-seconds:当节点启动后,这个参数(单位:秒)指定了当前节点等待其他节点响应的时间周期。例如,设置为60秒时,每一个节点启动后通过组播协议广播消息,如果主节点在60秒内返回响应消息,则新启动的节点加入这个主节点所在的集群,如果设定时间内没有返回消息,那么节点会把自己设置为一个主节点,并创建新的集群(主节点可以理解为集群的第一个节点)。默认值为2秒。
trusted-interfaces:可信任成员的IP地址。当一个节点试图加入集群,如果其不是一个可信任节点,他的加入请求将被拒绝。可以在IP的最后一个数字上使用通配符()来设置一个IP范围(例如:192.168.1. 或192.168.1.100-110)。
自动检测
默认情况下,Hazelcast 尝试根据运行时环境自动检测适用的发现机制。该模式需要手动指定成员的发现策略,如果没有指定, hazelcast会退回组播模式进行成员的发现
TCP协议组建集群
<hazelcast>
<network>
<join>
<multicast enabled="false">
</multicast>
<tcp-ip enabled="true">
<required-member>192.168.1.104</required-member>
<member>192.168.1.104</member>
<members>192.168.1.105,192.168.1.106</members>
<connection-timeout-seconds>60</connection-timeout-seconds>
</tcp-ip>
</join>
</network>
</hazelcast>
首先需要将<tcp-ip>元素中的enabled属性设置为true表示启用TCP/IP协议来组网。然后每个元素对应的含义如下:
required-member:加入集群的成员IP地址,只有这些IP地址的成员存在时集群才会组建。也就是说如果要当前节点加入集群,必须<required-member>元素中的指定的IP地址已经有集群节点先启动了,该节点才能启动,可以用于限制节点的启动顺序。
member:成员的IP地址。指定要加入集群的成员IP地址,这些IP地址中的成员会相互发现对方。
members:member的复数形态。在元素中可以使用逗号(“,”)分割多个IP地址。还可以使用-或等符号来表达多个IP*地址。
connection-timeout-seconds:定义连接超时时间。Hazelcast尝试连接到一个已知的节点(member元素指定)的最大超时时间,如果在指定时间内连接失败,将会放弃连接。当参数设置太小时,可能会导致一个成员可能无法连接到集群。设置太高时,成员启动的等待时间会比较久,因为当某些<member>元素标记的节点未启动时,需要花费较多时间等待。如果有较多的不同IP地址的成员需要加入集群,可以适当增加这个值,以保证所有的成员可以正确加入集群。默认值为5。
源码阅读
组播模式下自动加入集群
等待其他成员加入
- HazelcastInstance instance = Hazelcast.newHazelcastInstance(hzconfig);
- node.start();
- connectionManager.start(); com.hazelcast.nio.tcp.TcpIpConnectionManager#start
- startAcceptor()
- AcceptorIOThread是一个线程类, 直接看run方法
6.acceptLoop()
代码会阻塞在第162行, 当有新的连接请求过来时,会继续执行
7.handleSelectionKeys
8.configureAndAssignSocke
9.newConnection
10.
最终会打印以上连接成功的日志
本文由mdnice多平台发布
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。