阿里巴巴是世界上最大的电子商务零售商。 我们在2015年的年销售额总计3940亿美元,超过eBay和亚马逊之和。阿里巴巴搜索(个性化搜索和推荐平台)是客户的关键入口,并承载了大部分在线收入,因此搜索基础架构团队需要不断探索新技术来改进产品。
在电子商务网站应用场景中,什么能造就一个强大的搜索引擎?答案就是尽可能的为每个用户提供实时相关和准确的结果。同样一个不容忽视的问题就是阿里巴巴的规模,当前很难找到能够适合我们的技术。
Apache Flink®就是一种这样的技术,阿里巴巴正在使用基于Flink的系统Blink来为搜索基础架构的关键模块提供支持,最终为用户提供相关和准确的搜索结果。在这篇文章中,我将介绍Flink在阿里巴巴搜索中的应用,并介绍我们选择在搜索基础架构团队中使用Flink的原因。
我还将讨论如何改进Flink以满足我们对Blink的独特需求,以及我们如何与data Artisans和Flink社区合作,将这些更改贡献给Flink社区。一旦成功地将我们的修改合并到开源项目中,我们会将现有系统从Blink转移到Apache Flink。
Part 1: Flink在阿里巴巴搜索中的应用
文档创建
为用户提供世界级搜索引擎的第一步是创建可供搜索的文档。在阿里巴巴的应用场景中,文档是由数百万个商品列表和相关的商品数据组成。
因为商品数据存储在许多不同的地方,所以搜索文档创建也是一个很大的挑战,搜索基础架构团队将商品相关的所有信息汇总在一起并创建完整的搜索文档。一般来说,整个过程分为3个阶段:
这3个阶段实际上是在经典的“lambda架构”中的2个不同的pipeline上运行:全量构建pipeline和增量构建pipeline。
搜索算法实时A/B测试
我们的工程师会定期测试不同的搜索算法,并且需要尽可能快地评估出效果。现在这种评估每天运行一次,因为想实时分析效果,所以我们使用Blink构建了一个实时A/B测试框架。
在线日志(展示,点击,交易)由解析器和过滤器收集和处理,然后使用业务逻辑连接在一起。接下来聚合数据,将聚合结果推送到Druid,在Druid内部,我们可以编写查询语句并对数据执行复杂的OLAP分析,并查看不同算法的效果。
在线机器学习
在这部分中Flink有两个应用场景。首先,我们来讨论它在商品特征实时更新中的应用。阿里巴巴搜索排序中使用的一些商品特征包括商品CTR,商品库存和商品点击总数。这些数据随时间而变化,如果可以使用最新的数据,我们就能为用户提供更相关的搜索结果排序。Flink pipeline为我们提供在线特征更新,并大大提高了转化率。
其次,每年的特定日子(如光棍节),有些商品折扣力度很大,有时甚至高达50%。因此,用户行为也会发生很大的变化。交易量巨大,通常比我们在平时看到的高出很多倍。以前训练的模型在这个场景作用有限,因此我们使用日志和Flink流式作业构建了在线机器学习模型,这个模型会将实时用户行为数据反馈到系统中。结果在这些不常见但非常重要的营销节日的转换率有了很大的提升。
Part 2: 选择一个框架来解决问题
选择Flink应用到搜索基础架构中,我们在四个方面做过评估。 Flink在四个方面都满足我们的要求。
一般来说,有两种方法来将批处理和流式处理统一起来。一种方法是将批处理作为基本出发点,在批处理框架上支持流式处理。这可能不符合真正意义上低延迟,因为用微批量处理(micro-batching)模拟流式处理需要一些固定的开销。因此,当试图减少延迟时,开销的比例也会相应增加。在我们的规模上,为每个微批量处理器调度1000个任务,需要重新建立连接并重新加载状态。因此在某种程度上,微批处理方法代价太高将变得没有意义。
Flink从另一个角度来解决这个问题,即将流式处理作为基本出发点,在流式处理框架上支持批量处理,将批处理作为流式处理的一种特殊情况。使用这种方法,不会丢掉我们在批处理模式(批处理模式下流是有限的)下做出的优化,你仍然可以做一些批量处理上的优化。
Part 3: Blink是什么?
Blink是Flink的一个分支版本,我们做了一定的改进以满足阿里巴巴的一些特定需求。因此,Blink在几个不同的集群上运行,每个集群有大约1000台机器,大规模集群的性能对我们来说非常重要。
Blink的改进主要包括两个方面:
Table API更完整,因此我们可以使用相同的SQL进行批处理和流式处理。
更强大的YARN模式,但仍然100%兼容Flink的API和更广泛的生态系统。
Table API
我们首先添加了对用户自定义函数UDF的支持,方便在Flink中实现独特的业务逻辑。我们还添加了一个流对流的join的功能,由于Flink对于状态比较好的支持,所以实现起来比较容易。我们添加了几个聚合函数以及滑动窗口的支持,最有趣的一个是distinct_count。
(编辑注:FLIP-11涵盖了与上述功能相关的一系列Table API和SQL改进,对该主题感兴趣的可以阅读)
接下来,我们将介绍运行时改进,可以分为四个不同的类别。
Yarn上的Blink
当我们开始项目时,Flink支持2种集群模式:standalone模式和YARN上的Flink。在YARN模式中,作业不能动态请求和释放资源,而是需要预先分配所有需要的资源。不同的作业可能共享相同的JVM进程,这有利于资源利用和资源隔离。
Blink中每个作业都有自己的JobMaster,以根据作业需要请求和释放资源。并且不同的作业不能在同一个Java进程中运行,这将在作业和任务之间得到最佳隔离。阿里巴巴团队目前正在与Flink社区合作,将这项工作贡献给开放源代码,改进工作在FLIP-6(除了YARN之外还扩展到其他集群管理器)中得到了体现。
Operator缩放
在生产环境中,我们的客户端可能需要改变Operator的并行性,但同时他们不想失去当前状态。当我们开始使用Blink时,Flink不支持在保持状态的同时改变Operator的并行性。Blink引入了“bucket”的概念作为状态管理的基本单位。有比任务更多的bucket,并且每个任务将被分配多个bucket。当并行性改变时,我们将重新分配任务的bucket。 使用这种方法,可以改变Operator的并行性并维持状态。
(编者注:Flink社区同时在Flink 1.2版本中解决了的这个问题 - 该功能在最新版本的主分支中可用。Flink的“key groups”概念在很大程度上等同于上面提到的“bucket”,但是实现时使用的数据结构略有不同。更多信息,请在Jira查看FLIR-3755)
增量Checkpoint
在Flink中,Checkpoint操作分为两个阶段:在本地获取状态快照,然后将状态快照保存到HDFS(或另一个存储系统),并且每个快照的整个状态存储在HDFS中。我们的状态数据太大了,这种方法是不可行的,所以Blink只存储修改的状态在HDFS中,这能够大大提高Checkpoint的效率。这种修改使我们能够在生产环境中使用很大的状态数据。
异步I/O
我们的job在生产环境中很大瓶颈在访问外部存储器上,如HBase。为了解决这个问题,我们引入了异步I/O,我们将致力于为社区做出贡献,并在FLIP-12中有详细描述。
(编辑笔记:data Artisans认为FLIP-12足够强大,可以在不久的将来在某个时间拥有自己的独立写入。所以我们只是简单地介绍一下这里的想法,如果你想了解更多,可以查看FLIP writeup)
Part 4: 阿里巴巴的Flink未来计划是什么?
我们将继续优化我们的流式job,特别是更好地处理临时倾斜(temporary skew)和慢节点(slow machines),同时不会对反压机制(backpressure)和故障快速恢复造成影响。正如在Flink Forward大会上大家讨论的,我们认为Flink作为批处理框架以及流式处理框架有着巨大潜力。我们正在努力利用Flink的批处理能力,希望在几个月内在生产环境中使用Flink批处理模式。
会议的另一个热门话题是流式SQL,我们将继续在Flink中添加更多的SQL支持和Table API的支持。阿里巴巴的业务持续增长,这意味着我们的job会越来越大,确保我们可以扩展到更大的集群变得越来越重要。
非常重要的是,我们期待与社区继续合作,以便将我们的工作贡献回开源社区,以便所有Flink用户都能从我们加入Blink的工作中受益。我们期待着在2017年Flink Forward大会上向您介绍我们的进展情况。
本文作者:王庆
来源:51CTO