数据摄入
方式
- 流式数据:指不断产生数据的数据源,如消息队列,日志等;Druid提供了Push和Pull两种方式
- Pull方式需要启动一个实时节点,通过不同的Firehose摄入
- Push方式需要启动索引服务,提供一个Http接口来接受数据推送
- 静态数据:指已经产生完全,不会产生新数据的源,如离线数据;也可通过上述两种方式来摄取
流式数据摄取
Pull
- 定义配置文件,包含三部分
- dataSchema 包括数据源的描述,数据类型,列,指标列等等;参考文档
- ioConfig 指定了具体的数据源,如Kafka Topic,Server等配置
- tuningConfig 优化参数
Push
- 启动索引任务,需要向统治节点发送一份Ingestion Spec
- 通过push-event接口发送数据
静态数据摄取
- 索引方式:向统治节点提交索引任务
- 以Hadoop方式摄取:向统治节点Post一个请求,启动Hadoop Index Job,Druid会提交一个MR任务到Hadoop,适合离线数据生成历史分片
流式与批量数据摄取的结合
Lambda架构
满足一个稳定的大规模数据处理系统所需的容错性,低延迟,可扩展性;
– 任何数据可定义为 query = func(all data)
– 人为容错性:数据是易丢失的
– 数据不可变性:数据是只读的,不再变化
– 重新计算:基于上面两个原则,运行函数重新计算结果是可能的
该架构具有如下特点:
– 所有新数据分别分发到批处理层和实时处理层
– 批处理层有两个功能,管理主要数据(只能增加,不能更新)和为下一步计算批处理视图做预计算
– 服务层计算出批处理视图中的数据做索引,以提供低延时,即席查询
– 实时处理层仅处理实时数据,并为服务层提供查询服务
– 任何查询可通过实时层和批处理层的查询结果合并得到
解决时间窗口问题
Druid中,超过时间窗口的数据会被丢弃,为了解决这个问题,参考Lambda架构,实现方式如下:
1. 源数据都进入Kafka
2. 数据通过实时节点或索引服务进入Druid
3. 同时数据通过Flume备份到Hadoop
4. 定时或DQC发现数据丢失时,通过Druid Hadoop Index Job 重新摄入数据
其他
Druid数据以时间分片,当短时间内涌入大量数据时会造成Segment文件过大,从而影响查询;Druid通过数据分片和复制使得数据分布到更多节点以提高效率
数据分片
- 实时节点数据分片(可以通过tuningConfig中的shardSpec指定分片方式)
- Linear分片:
- 添加新的实时节点时,不用更改原实时节点的配置
- 查询时,即使分片缺失,所有分片都会被查询
- Numbered分片
- DruidIndexJob分片(只能设置一种)
- targetPartitionSize 通过设置分片大小计算分片个数
- numShards 直接设置分片个数
- HadoopIndex Job 分片(通过partitionSpec设置)
- 哈希分片:基于维度值的哈希值分区(更快,分布更均匀)
- 范围分区:基于纬度值的取值范围分区
数据复制
- DeepStorage:系统一般自带副本能力,保证数据不丢失
- Druid内部数据复制:通过蛇者Segment副本来保证
通过Tranquility操作索引服务
pass
高基数维度优化
- Cardinality aggregator(SQL中Count(distinct x)的默认方法)
- 基于HyperLoglog算法
- 只在查询时优化,不减少存储容量
- 效率比存储时预聚合的 HyperUnique aggregator低
- HyperUnique aggregator
Kafka索引服务
设计背景
- 保证数据摄入的Exactly Once语义
- 不受windowPeriod的约束,可以摄入任意时间戳的数据,而不仅仅是当前的数据
- 操作易用性,自适应性强,可以根据Kafka分区增加或减少任务的数量
windowPeriod的设定会导致超出时间窗口延迟的数据被丢弃,而过长的时间窗口会影响索引服务的任务完成退出和查询性能;影响数据不重复摄入的主要是Kafka的Offset管理。在最初的KafakDireChief采用高层的消费者,这会自动完成类似Broker的Leader选择,Offset维护,管理分区和消费者之间的均衡和重平衡等功能,同一个Group中的消息只会被一个消费者消费一次。
- 同一个Group的消息只能被消费一次,导致很难实现多副本来保证高可用和查询一致性
- 高等级消费者采用ZK存储Offset,导致内存增量持久化和Offset提交不在同一事物中。会存在持久化成功但是没提交的情况下节点失败会导致这条消息被重复消费。
实现
** 采用了Supervisor(监督者)的方式运行在Overlord上**
- KafkaSupervisor:负责索引任务创建和管理整个生命周期;监管索引任务状态来协调移交,管理失败,保障可扩展性等
- KafkaPartitions来记录Topic和分区->Offset的映射关系
- KafkaIndexTask从 KafkaIOConfig->startPartition的Offset开始读取,直到endPartition结束,发布移交Segment。执行过程中,startPartition->Offset不会改变,KafkaSupervisor通过修改endPartition来控制任务结束
- 运行中的任务分读取和发布状态;任务会保持读取状态,直到达到taskDuartion后进入发布状态。接下来保持发布状态直到生成Segment并推送到DeepStorage,并且等待历史节点加载
- TaskGroup是KafkaSupervisor管理Kafka分区,Offset的数据结构
- Appenderator:索引数据,类似LSM-Tree的架构
- FiniteAppendderatorDriver驱动Appenderator完成有限流式数据的索引,在索引完成后执行移交操作
- SegmentAllocator 根据给定的时间戳,分配一个Segment
- 检查任务是否达到任务的持续时间(taskDuration,默认一小时)。达到则发送信号提示停止读取数据,进入发布阶段
终止taskGroup的流程
优势
- 去掉时间窗口,读取数据后根据时间戳使用SegmentAllocator分配到合适的Segment(缺点是这样会产生碎片化的Segment)
- Segment的发布和Offset的提交在同一事务中处理,都在发布截断完成,可以解决重复摄入的问题
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请
点击举报。