目录
一、为什么在Kylin中建立实时流
- 提供毫秒级的数据准备延迟
Kylin为极大的数据集提供了亚秒级的查询延迟,其潜在的魔力是预先计算立方体。但是建立多维数据集通常会花费很长时间(对于大型数据集通常要花费数小时),在某些情况下,分析人员需要实时数据进行分析,因此我们想提供实时OLAP,这意味着可以在以下情况下立即查询数据生产到系统。
- 支持Lambda架构
实时数据通常不可靠,这可能是由多种原因引起的,例如,上游处理系统存在错误,或者一段时间后需要更改数据等。因此,我们需要支持Lambda架构,这意味着可以从流源(如Kafka)构建多维数据集,并且可以从批处理源(如Hive)刷新历史多维数据集数据。
- 更少的MR作业和HBase表
自Kylin 1.6以来,社区提供了流解决方案,它使用MR来消耗Kafka数据,然后进行批处理多维数据集构建,它可以提供分钟级的数据准备延迟,但是要确保数据延迟,您需要非常短的调度MR(5分钟或更短),这将导致过多的Hadoop作业和系统中小的hbase表,并显着增加Hadoop系统的负载。
二、流多维数据集引擎如何工作
1)流数据写入
- 协调员向流数据源kafka询问多维数据集的所有分区
- 协调器确定要分配给哪些流接收器receiver以使用流数据,并要求流接收器开始使用数据。
- 流接收器开始消费流数据,并设置索引
- 一段时间后,流式接收器将不可变的段从本地文件复制到远程HDFS文件
- 流接收器通知协调已经将Segment段持久化保存到HDFS
- 在所有receiver接收者都提交了段之后,协调器将多维数据集构建作业提交给Build Engine,以触发多维数据集的完整构建
- Build Engine从HDFS文件构建所有长方体
- Build Engine将长方体数据存储到Hbase,然后协调器将要求流接收器删除相关的本地Segment数据。
2)流数据查询
在新架构下,数据查询请求根据“ 时间戳分区列”分为两部分。最近时间段的查询请求将发送到实时节点,历史数据的查询请求仍将发送到HBase区域服务器。查询服务器需要合并两者的结果,并将其返回给客户端。👍
三、流多维数据集详细概念和作用
1、Assigment
Assignment是一个数据结构,它是一个Map,此Map的键是副本集的ID,值是分配给此副本集的分区列表(使用Java语 言:)Map<Integer, List< Partition>>
,如下图是一个简单的例子。
分配非常重要,它显示了哪个Kafka主题分区负责哪个副本集,了解如何使用与Rebalance相关的API和学习Streaming元数据非常重要。
根据群集资源和主题分区的当前数量,可以使用不同的策略来进行适当的分区分配。这些策略由Assigner处理。分配器当前有两个实现,CubePartitionRoundRobinAssigner,DefaultAssigner。
2、副本集
副本集是一组行为相同的流接收器,即同一个副本集里面所有的receiver都接收相同的数据,互为备份作用,当其中一个receiver挂了,不影响数据的正常接收,达到高可用的作用。同一个副本集中的receiver会通过zookeeper选举出一个leader,最终Segment变成Immutable后,由leader负责上传至HDFS。
3、流接收器
一个流接收器只隶属于某一个副本集,副本集可以拥有多个流接收器,所有流接收器的集合统称流接收器集群。
一个流接收器底层拥有多个Segment段,包括 Active Segment 和 Immutable Segment。
职责:
1. 摄取实时数据;
2.在某个段中的内存建立一个长方体,定期将存储在内存中的长方体数据刷新到磁盘上(形成一个Fragment文件);
3.定时检查并合并片段文件;
4.接受对其负责的分区的查询请求;
5.当该段变得不可变时,将其上传到HDFS或在本地将其删除(取决于配置);
4、流协调器
流协调器主要负责管理流接收器receiver,包括将Kafka主题分区分配/取消分配给指定的副本集,暂停或恢复消耗,收集并显示各种统计指标。当kylin.server.mode
设置为all
或时stream_coordinator
,该节点为流协调器。协调器仅处理元数据和群集调度。
流协调器可以拥有多个,多个流协调器组成一个流协调器集群。只能有一个leader,只有leader才能处理和响应请求,其余都是高可用。
5、Segment段
段由两部分组成:MemoryStore和Fragment File。
在MemoryStore内部,使用来存储聚合数据Map<String[], MeasureAggregator[]>>
,其中key是维度值的字符串数组,而value是MeasureAggregator数组。
由于Receiver不断接收消息,因此当MemoryStore中的数据行数达到阈值(kylin.stream.index.maxrows
)时,将触发刷新。接收器会将整个MemoryStore刷新到磁盘并形成一个Fragment File。要读取片段文件,Receiver使用内存映射文件来加快读取速度。此外,片段文件使用多种方法来优化扫描和筛选性能。
当Receiver接收新消息并且该消息的时间分区列的值不包含在任何现有Segment中时,Receiver将在本地创建一个新的Segment,即初始该段的状态为Active,并且该段的开始时间和结束时间等于Segment Window,所有来自该时间段的数据都会流入这个Segment。每个创建的Segment并不会马上变成Immutable状态,需要等一段时间,达到一定条件后才会被触发变成Immutable状态,这时候才会被上传至HDFS。例:{"time":"2019-01-01 12:01:02"}
201901011100-201901011200
例如,我们有一个流分段,其分段范围开始为2020-01-01 10:00:00
,分段范围结束为2020-01-01 11:00:00
(由 kylin.stream.cube.window决定
)。我们将有一个滑动窗口,其长度由kylin.stream.cube.duration决定
。其默认范围应为[2020-01-01 11:00:00, 2020-01-01 12:00:00]
。假如我们现在有一条事件时间为 2020-01-01 10:40:00 的数据流入(摄取时间也相同),按照上面的规则,这时候滑动窗口为[2020-01-01 10:40:00, 2020-01-01 11:40:00],我们需要等待 1小时 直至 11:40 分,当达到滑动窗口的结束时间时,10:00-11:00的Segment段将会变成Immutable状态。
由于它是一个滑动窗口,因此每个较晚的消息都会触发滑动窗口的移动。
假如在数据流入之前,滑动窗口为[2020-01-01 10:40:00, 2020-01-01 11:40:00
], 我们现在有一条事件时间为 2020-01-01 10:50:00 的数据流入(摄取时间 11:30 分),这时候滑动窗口将会往后移动,这时候滑动窗口为
[2020-01-01 11:30:00, 2020-01-01 12:30:00
]。
但是这并不会一直无止尽的滑动下去,需要有另外一个参数来限制这个滑动,即 kylin.stream.cube.duration.max
,限制最大能滑动的窗口时间。
kylin.stream.cube.window:
3600(默认值为一小时)kylin.stream.cube.duration:
3600(默认值为一小时)kylin.stream.cube.duration.max:
43200(默认值为12小时)
6、保留策略
当段转换为IMMUTABLE时,有两个配置将决定如何处理段的本地数据。
kylin.stream.segment.retention.policy
默认值:false。确定当sgement不变时是否清除或上传本地段。
kylin.stream.segment.retention.policy.purge.retentionTimeInSec
当kylin.stream.segment.retention.policy
设置为true时,此设置确定不可变段被清除之前的生存时间
1)FULL_BUILD,即上传本地段。当段变成Immutable后将该段上传至HDFS,上传成功后,协调器将段状态设置为。REMOTE_PERSISTED状态,然后当构建完成cube变成ready后,将自动删除该本地段数据。 如果单个接收方下多维数据集中不可变和RemotePersisted的段数太大(由kylin.stream.immutable.segments.max.num
决定
),则kafka将停止消费,直到不可变 / RemotePersisted的数量低于该阈值。
2)PURGE ,即定时清除本地段。该段不会上传到HDFS,当时间达到设置的值时,会自动清除本地段数据。
四、重新分配Assigment
为了应对Kafka消息量的快速增长,或者在其他情况下Receiver需要脱机,需要重新设置副本集和Kafka主题,以使整个Receiver群集处于负载状态。平衡状态。因此,您需要重新分配操作。
通过“ 重新分配”操作,Kylin将停止需要删除的属于副本集的接收器的接收/使用,并将先前负责的kafka分区移交给新的副本集。此过程由协调器完成,该过程不需要数据移动。整个过程的耗时取决于重新分配中涉及的节点数,通常要在几秒钟内完成。应当注意,重新分配动作完成后,切勿立即杀死被移走的接收器。原因是不能保证数据成功上传到HDFS,并且查询请求也需要删除的副本集。
1)重新分配步骤:
重新分配是一个从CurrentAssignment到NewAssignment的过程。整个重新分配操作是一个分布式事务,可以分为四个步骤。如果一个步骤失败,将执行自动回滚操作。
- StopAndSync停止消费和同步偏移
- 停止消耗CurrentAssignment的所有接收器,并且每个接收器将分区偏移量报告给协调器
- 协调器合并每个分区的偏移量,保留最大的偏移量,通知接收器消耗到统一的(最大)偏移量,然后再次停止消耗
- AssignAndStart
- AssignNew发送分配请求的所有接收机NewAssignment,更新他们的任务
- StartNew向所有NewAssignment的接收者发送一个startConsumer请求,要求他们根据上一步中的Assignment启动使用者。
- ImmutableRemoved向删除的副本集所属的所有接收方发送ImmutableCube请求,要求它们强制将所有活动段转换为Immutable
- 更新MetaData更新元数据并将NewAssignment + RemovedAssignment记录到元数据(在Reassign完成后,删除的ReplicaSet仍将接受查询请求)
2)重新分配图
具体步骤如下
- StopAndSync
在此步骤中,我们停止CurrentAssigment中包含的所有RS的消耗行为,但是跳过Same RS,即RS-2
。 - AssignAndStart
在这一步中,我们发出分配和StartConsumer请求包含在所有RS NewAssignment,也跳过同一个RS,RS-2
。 - ImmutableRemoved
在此步骤中,我们向Removed RS发送了一个强制性的Immutable请求,并且Removed RS将尽快将其负责的数据部分上传到HDFS。 - 更新元数据
在此步骤中,协调器将更新元数据并将NewAssignment加上Removed RS作为真实的NewAssignment写入元数据。
在已删除的RS完成上载并将相关段成功构建到HBase中之前,查询请求将发送RS-0
到RS-3
。
五、现有的BUG
- 点击assigment,重新分配,会导致无法消费kafka数据,需要重新disable/enable,会导致receiver内存数据丢失
- assigment没有做限制,一个kafka分区能被多个副本集使用,会存在问题
- segment无持续流入数据的话,不会触发变成IMMUTABLE状态
- receiver内存数据不会被定时刷到磁盘,有存在数据丢失的风险
- 存在内存泄露的问题
以上是kylin3.0存在的问题,希望后面的迭代版本会被修复,期待!!!