i 技术会笔记 | Druid在爱奇艺的实践和技术演进
- 导读 -
爱奇艺大数据服务团队评估了市面上主流的OLAP引擎,最终选择Apache Druid时序数据库来满足业务的实时分析需求。本文将介绍Druid在爱奇艺的实践情况、优化经验以及平台化建设的一些思考。
爱奇艺大数据OLAP服务
爱奇艺大数据OLAP服务在2015年前主要以离线分析为主,主要基于Hive+MySQL、HBase等。2016年起引入Kylin和Impala分别支持固定报表和Ad-hoc查询。2018年以来引入Kudu和Druid支持实时分析需求。
在引入Druid之前,业务的一些场景无法通过离线分析满足,如广告主想要实时基于投放效果调整投放策略、算法工程师调整模型推到线上A/B要隔天离线报表才能看到效果。这些场景都可以归纳为对海量事件流进行实时分析,经典的解决方案有如下几种:
离线分析:
实时分析:
用ElasticSearch或OpenTSDB,由于数据结构本质是行存储,聚合分析速度都比较慢;可以通过查询缓存、OpenTSDB预计算进行优化,但不根本解决问题; 用流任务(Spark/Flink)实时地计算最终结果,存储在MySQL提供进一步服务;问题是每当需求调整,如维度变更时,则需要写新的流任务代码; 使用Kudu和Impala结合能够做到实时分析。在实践过程中发现,Kudu受限于内存和单机分区数,支撑海量数据成本很大;
Lambda架构:
实时可见:消息摄入后分钟级查询可见 交互查询:查询延时在秒级,核心思想为内存计算和并行计算 维度灵活:支持几十个维度任意组合,仅在索引时指定的维度查询可见 易于变更:需求变更后调整索引配置立马生效; 流批一体:新版本KIS模式可实现Exactly Once语义
上图为Druid架构图,大体分为几个模块:
MiddleManager:索引节点,负责实时处理消息,将其转成列式存储,并通过Rollup精简数据量;索引节点定期将内存中数据持久化为不可修改的文件(Segment),保存至HDFS保证数据不会丢失; Historical:历史节点,将Segment加载到本地,负责大部分查询的计算;
Broker:查询节点,将查询分解为实时和离线部分,转发给索引节点和历史节点,并汇总最终的查询结果; Overlord:负责索引任务管理; Coordinator:负责负载均衡,确保Segment在历史节点之间尽量均衡;
Druid在爱奇艺的实践
Druid很好地填补了爱奇艺在实时OLAP分析领域的空白,随着业务实时分析需求的增加,Druid集群和业务规模也在稳步增长。目前集群规模在数百个结点,每天处理数千亿条消息,Rollup效果在10倍以上。平均每分钟6千条查询,P99延时一秒内,P90延时在200毫秒内。在建设Druid服务过程中,我们也不断遇到规模增长带来的性能瓶颈和稳定性问题。
当时的挑战是实时索引任务经常被阻塞。Druid的Handoff总结如下,索引节点将Segment持久化到HDFS,然后Coordinator制定调度策略,将计划发布到ZooKeeper。历史节点从ZooKeeper获取计划后异步地加载Segment。当历史节点加载完Segment索引节点的Handoff过程才结束。这个过程中,由于Coordinator制定计划是单线程串行的,如果一次触发了大量Segment加载,执行计划制定就会很慢,从而会阻塞Handoff过程,进而索引节点所有的Slot均会被用满。
• 历史节点因硬件故障、GC、主动运维退出
• 调整Segment副本数、保留规则
分析清楚原因后,很容易了解到Druid新很容易了解到Druid新版本提供了新的负载均衡策略(druid.coordinator.balancer.strategy = CachingCostBalancerStrategy),应用后调度性能提升了10000倍,原先一个历史节点宕机会阻塞Coordinator1小时到2小时,现在30秒内即可完成。
4.Tranquility vs KIS
刚使用Druid时,当时主力模式是Tranquility。Tranquility本质上仍然是经典的Lambda架构,实时数据通过Tranquility摄入,离线数据通过HDFS索引覆盖。通过离线覆盖的方式解决消息延迟的问题,缺点是维护两套框架。对于节点失败的问题,Tranquility的解决方案是链路冗余,即同时在两个索引节点各起一份索引任务,任一节点失败仍有一份能够成功,缺点是浪费了一倍的索引资源。自0.14版本起,Druid官方建议使用KIS模式索引数据,它提供了Exactly Once语义,能够很好地实现流批一体。
和Tranquility的Push模式不同,KIS采取Pull模式,索引任务从Kafka拉取消息,构建Segment。关键点在于最后持久化Segment的时候,KIS任务有一个数据结构记录了上一次持久化的Offset位置,如图例左下角所示,记录了每个Kafka Partition消费的Offset。在持久化时会先检查Segment的开始Offset和元信息是否一致。如果不一致,则会放弃本次持久化,如果一致,则触发提交逻辑。提交中,会同时记录Segment元信息和Kafka Offset,该提交过程为原子化操作,要么都成功,要么都失败。
以下是KIS在爱奇艺的一个实例,左下图为业务消息量和昨天的对比图,其中一个小时任务持久化到HDFS失败了,看到监控曲线有一个缺口。之后Druid后台启动了一个新的KIS任务,一段时间后,随着KIS补录数据完成,曲线图恢复到右下图所示。那么,如果业务不是一直盯着曲线看,而是定期查看的话,完全感受不到当中发生了异常。
基于Druid的实时分析平台建设
数据摄入需要撰写一个索引配置,除了对数据自身的描述(时间戳、维度和度量),还需要配置Kafka信息、Druid集群信息、任务优化信息等 查询的时候需要撰写一个JSON格式的查询,语法为Druid自定义,学习成本高 返回结果为一个JSON格式的数据,用户需自行将其处理成最终图表、告警 报错信息不友好,上述所有配置均通过JSON撰写,一个简单的逗号、格式错误都会引起报错,需花费大量时间排查
全向导配置:业务无需手写ETL任务 计算存储透明:业务无需关心底层OLAP选型 丰富报表类型:支持常见的线图、柱状图、饼图等 数据延时低:从APP数据采集到生成可视化报表的端到端延时在5分钟内,支持数据分析师、运营等业务实时统计分析UV、VV、在线用户数等 秒级查询:大部分查询都是秒以内 灵活变更:更改维度后重新上线即可生效
未来展望
参考资料
招聘信息
爱奇艺大数据服务团队诚招Spark/Flink实时计算服务技术专家/架构师。爱奇艺大数据服务团队负责公司大数据基础设施的建设工作,提供涵盖数据采集、数据处理、数据开发、数据应用等整个大数据处理流程的一系列大数据开源服务及相应的开发平台,具备万台以上大规模分布式服务能力。
简历发送:liangjianhuang@qiyi.com
邮件主题:大数据实时计算资深研发工程师-${姓名}
扫一扫下方二维码,更多精彩内容陪伴你!