本文根据阿里资深搜索专家蒋晓伟在首届阿里巴巴在线峰会上的分享整理而成。 此次分享的重点是Blink计算引擎,它是阿里巴巴搜索的流计算和批处理引擎。相比于Flink,在上层,Blink具有批和流一体化的完备Table API,使得其能够支撑各类业务需求;在底层,Blink重新开发了兼容Flink以及生态的Runtime,实现了流处理和批处理完美的统一。
直播视频:
(点击图片查看视频)
幻灯片下载:点此进入
以下为整理内容。
搜索文档的创建和更新
要建立一个搜索系统,首先需要创建搜索文档,具体的创建过程分为三个步骤:第一步,将分散在各地的数据同步到HBase上,数据同步之后,HBase中就包含了创建文档所需的全部数据;第二步,将HBase中的数据进行汇总,经过业务逻辑的处理后,将产生的需要搜索的文档存在结果表当中;第三步,将HBase中的结果表导出到搜索引擎中,即完成了搜索文档的创建。值得注意的是:上述每一步骤都包括全量和增量两个流程。
物化视图
结果表可以当做是物化视图,物化视图是一种延伸数据,类似于索引。数据库可以确保物化视图和其对应的表的一致性。从物化视图的观点出发,可以对全量和增量进行重新解释,所谓的全量,是相当于索引的创建和重建的流程;而增量则意味着索引的维护。通过物化视图,仅使用同一句SQL语句即可同时解决增量和全量的问题。
流和表的对偶性
要在大数据内实现增量和全量的统一处理,首先我们需要了解几个概念。
第一个概念是流和表的对偶性。上图的左半部分是一个流,它包括word和 count两列,记载了每一词的出现次数;右边是一张历史表,同样包含word和count两列,但是word列是具有对应主键的。如果利用左边的流更新右边的历史表,就会由原来的五条记录缩减到三条记录。通过物化操作,可以把一个流转化为历史表;当历史表存在时,我们可以通过查看、导出历史表的修改日志,恢复原来的流。在某种意义上,流和历史表所包含的信息量是相同的。流和表的对偶性,意味着我们可以将流计算和批处理结合起来。有一点需要注意的是,这里表是指动态的表,里面的内容是不断修改的。
第二个概念是流的等价性,两个流当且仅当它们产生相同的正则历史表时,两个流等价。如果有两个流用来更新同一个历史表,假设在不同的时间点,它们都能得到相同的历史表,则这两个流就是等价的。流的等价性给流处理带来了很大的灵活性,正是这种灵活性使得我们可以在Blink中完美地结合流处理和批处理。
什么是Blink?
Blink是阿里巴巴搜索团队基于Flink开发的计算引擎,其目的是为了支撑阿里巴巴大规模的计算需求。Blink实现了流处理和批处理完美的统一。相比于Flink,在上层,Blink具有批和流一体化的完备Table API,使得其能够支撑各类业务需求;在底层,Blink重新开发了兼容Flink以及生态的Runtime。
Blink的Table API
Blink的Table API的设计原则是实现流和批的一体化处理。秉着该原则,Blink开发了一系列的功能,包括:
- UDF/UDTF/UDAGG,用户可以利用这些函数轻松实现业务逻辑的表达;
- 双流Join;
- Aggregation(min、max、avg、sum、count、distinct_count);
- Windowing;
- Retraction撤回机制。
Blink的Runtime
Blink在Runtime上也做了很多改进。首先Blink实现与YARN的原生态整合;其次对Checkpoint和状态管理进行了优化,使其能够真正用于生产环境中;同时,Blink在容错性、高可用性、稳定性和可运维性等方面都有很大的改进;此外,Blink还支持动态伸缩。
Flink On YARN
上图展示的是Flink在YARN上的架构,YARN是Hadoop内的调度系统。Flink与YARN整合的思路十分简单:在运行Flink之前,首先需要启动Flink集群,该集群需要实现配置好;集群启用之后,Flink集群就可以接收用户提交的工作;Flink集群接收到用户提供的工作之后,通过JobManger将从YARN处获取的资源分配给不同的Job。在每个YARN Node上存在一个YARN NodeManager,它用来调用不同的Container。该架构存在几个明显缺陷:第一,不同的Flink Job的任务可能会运行在同一Flink TaskManager中,即不同Job的任务可能运行在同一个进程内,其中一个Job的任务失败可能会杀死整个进程,隔离性较差;第二点,由于Flink集群需要事先配置,一旦资源被Flink占用后,YARN就无法再将这些资源分配给其他的集群,这样就有可能导致一定程度的资源浪费,同时如果事先配置的资源不足,Flink集群是无法简单地扩容;第三点,由于管理全部Job的Flink JobManager进程运行在一个独立的container,当Job急剧增加时,Flink JobManager就成了整个架构可伸缩性的瓶颈。
Blink YARN的原生态整合
在Blink YARN的原生态整合中,去掉了单点的JobManager。当用户提交Job时,YARN ResourceManager会启用一个Job Master,两者一一对应,当Job内的Task需要资源时,再通过Job Master向YARN申请资源,实现资源的动态分配;同时,不同的Job处于不同的Container中,确保Job之间的隔离。
Blink的失败处理机制
在分布式系统中,失败是不可避免的。面对机器挂掉、进程崩溃时,如何保证系统的一致性是一个很大的挑战。一致性主要包括至少一次和恰好一次两个语义。至少一次是说,流来的每个消息能够保证至少处理一次,不会丢失消息。至少一次相对而言比较容易实现,只需要记录哪些消息成功处理过了,即使某个消息处理失败,也只需要从最后一条成功处理的消息之后重新开始处理即可。
恰好一次是指处理过的消息与状态的一致性。如何实现恰好一次这种逻辑呢?在分布式系统中,我们可以通过Chandy-Lamport算法实现恰好一次的逻辑。在流的源头上,当需要做Checkpoint时,插入名为Barrier的特别消息即可。它的作用是将state 获取快照之前的消息和之后的消息区分开来。Barrier同其他消息一样,同样会流入每一个operator中。
Blink Worker的错误恢复
Blink Worker的错误恢复分为两种情形:第一种是At Least Once,如果一个节点Fail了,我们只需要重启该节点,然后找到影响该节点的源头,再将源头进行回放即可,无需重启整个Job;第二种是Exactly Once,如果有一个节点Fail,我们需要找到该节点的连通图,将该节点重启,然后将连通图回退到上次checkpoint的位置进行回放即可。
Blink Master的高可用性
当Blink的JobMaster失败之后,YARN会重新启动该JobMaster,但是此时JobMaster已经丢失了原来的状态。为了保证JobMaster不丢失原来的状态,我们将JobMaster内的代码写成了状态机,每次状态修改之前都需要Log到HDFS;在新的JobMaster启动之前,通过HDFS的回放得到其原有状态,从而保障了Blink Master的高可用性。
Blink的动态伸缩
在流计算中,实验和真正上线使用时是存在偏差的,而且随着业务的增加,流量也会随之改变。通过引入bucket,动态支持Blink的伸缩。此外,在Blink中,我们添加了多个监控指标,用于观测Job性能。
现状与计划
目前Blink在阿里已经实现上千台机器规模的集群上线,用于支撑搜索和推荐的核心业务。同时,集团内外对Blink表现出了浓厚的兴趣,包括Uber、FaceBook等在内的企业都在考虑使用Blink。