Apache Flink 在滴滴出行的应用与实践
本文来自于余海林在2018年8月11日Apache Flink Community China线下Meetup·北京站的分享。余海林目前在滴滴出行负责实时流计算相关工作,研发主要是集中在Apache Flink上。之前任职于阿里巴巴,主要负责TCP/IP协议栈以及手淘的无线网络优化。
本文主要内容主要包括以下几个方面:
1、 Apache Flink在滴滴的背景
2、 Apache Flink在滴滴的平台化
3、 Apache Flink在滴滴的生产实践
4、 StreamSQL
5、展望规划
Apache Flink在滴滴
在滴滴,所有的数据基本上可以分为四个大块:
1、轨迹数据:轨迹数据和订单数据往往是业务方特别关心的。同时因为每一个用户在打车以后,都必须要实时的看到自己的轨迹,所以这些数据有强烈的实时需求。
2、交易数据:滴滴的交易数据,
3、埋点数据:滴滴各个业务方的埋点数据,包括终端以及后端的所有业务数据,
4、日志数据:整个的日志系统都有一些特别强烈的实时需求。
1、在滴滴应用发展的过程中,有一些对延迟性要求特别高的应用场景。比如说滴滴的轨迹数据,以及滴滴网关的日志监控,都对我们的引擎提出了非常大的挑战,要求我们在一个秒级或者说在一个很短的时间内能够给业务方一个反馈。在调研以及对比各个流计算引擎以后,由于Apache Flink(以下简称Flink)是一个纯流式的处理引擎。发现Flink比较满足我们的业务场景。
2、在滴滴的内部,一个业务形态是事业部特别多,然后有很多业务需要进行实时处理,很多业务部门选择自己搭建Storm或者Spark Streaming小集群。但是一个个小集群会带来一定的问题,例如:由于业务方不会有人专门去做维护流式计算引擎这些相关工作,所以每一次业务方出问题以后,实时计算团队做的最多事情就是进行重启集群,减少这样的一些成本也是对我们一个很大的挑战,
3、实时计算团队需要能够掌握住流计算引擎,也就是说我们必须要有一个统一的入口,来供大家更方便或者是更快捷更稳定的让业务方使用流计算服务。所以综上考虑,我们最终选择了Flink来作为流计算引擎的一个统一入口。
Flink在滴滴的平台化
平台化的优点
· 平台化能带来什么样的好处呢?很明显就是业务方不再需要自己去维护自己的小集群,也不需要过多的去关心流计算引擎相关的一些问题,业务方只需要专注于业务即可,这显然能够降低业务方的成本。
· 然后各个业务方如果自己去维护一个小集群的话,就相当于是说每个业务方这里有十台机器,另外一个业务可能也有个七八台机器,然后每个集群上的机器可能就跑了很少的几个应用,业务方的机器的利用率根本上不去,这对公司内部和机器资源来说都是浪费。
· 第三个就是如果每个业务方自己维护一个小集群的话,无法也没人给业务方任何的稳定性保障,如果将流计算进行平台化以后,平台会给每个业务方承诺一个稳定性保障,并且会有一个稳定性的保障体系。总之流计算平台化的优点可以归结为以下三点:
1、降低流计算使用门槛
2、统一流计算平台,降低机器运维成本,提升机器利用率
3、稳定性保障
平台化整体架构
通过看上面这一张图,很明显滴滴平台化可以分为以下几个部分:
· 第一个是上游的数据源,在滴滴内部,数据源用的比较多的有两类,第一类是Kafka, Kafka作为滴滴的一个大型的日志系统,用的会比较多,然后还有DDMQ(滴滴内部自研的一个消息队列),这两类中件间在数据流输入方面用的比较多。
· 然后对于中间这一块,是滴滴流计算平台的核心部分,应用管控、StreamSQL、WebIDE、诊断系统都是围绕着这个核心来做的。在滴滴内部现在主要维护了两个引擎,一个是Flink,还有一个是Spark Streaming,滴滴流计算平台上的这两个引擎,用户都是能够非常方便的使用到的。
· 再往下,用户提交上来的流计算应用都是由平台去做应用管理的,无论是Flink还是Spark Streaming应用都是以On Yarn模式运行的,流计算平台使用Yarn来管理计算资源和集群。对于需要持久化的一些依赖,在底层平台是存储在HDFS上的。
· 最后是流计算平台的下游,在下游当然也包括上游的一些中间件,比如Kafka和DDMQ,当然在流计算的过程中,不可避免地要使用到HBase或者MySQL, KV数据库等下游存储。综上所述这就是滴滴的一个整体平台化的架构。
引擎改进
对于引擎我们主要做了以下这些优化:
· 平台化我们第一个做的工作就是将整个任务提交以及任务管控的各个方面都进行服务化了,既然要流计算平台化,服务化是肯定要做的。
· 第二是在流计算平台化的过程中,为了能够更好的去限制每一个应用,更好的管理应用的资源,流计算平台限制了每个Yarn-session上只能提交一个Job,如果在一个Yarn-session上提交多个Job,平台会进行提示或报错,保证Job提交不上去。
· 然后是应用在使用的过程中无法避免的会去做一些升级的操作,比如说一个Flink Application在今天使用的时候,很可能没有预估到明天流量会涨很多,这就导致应用在启动的过程中申请到的资源不够,用户可能要重启去修改代码,修改算子的并行度等。但是重启总是会带来一定的业务延迟,因此流计算平台提供了支持动态扩容的新特性。Flink Application在重启的时候,以前已经在使用的资源不会被释放,而是会被重新利用,平台会根据新的资源使用情况来进行动态的缩扩。
· 最后一个是在使用官方Flink版本的过程中,碰到比较多的问题,例如在Zookeeper这一层面就碰到了不少的问题,平台内部修复了很多围绕Zookeeper相关的一些问题。例如Zookeeper抖动会导致获取不到CheckPoint的ID,在官方的版本里面会存留一些bug,平台内部已经进行修复了。
流计算任务开发
· 流计算平台化很大的一个目标,就是让用户开发更简单,能够更加便捷的去使用平台,因此流计算平台提供了多元化的开发方式。在早期主要有两种,第一种是用户在WebIDE上进行开发,第二种就是用户在本地的IDE中进行开发。现在流计算平台提供了第三种方式:StreamSQL IDE,流计算平台希望通过StreamSQL大大的降低用户开发使用流计算的门槛。
Flink任务监控
· 对于流计算平台,用户非常关心任务每时每刻的运行情况,并且用户需要非常实时的进行查看和确认,既然是流式任务,自然对实时要求比较高,因此用户特别关心应用的延迟有多少。所以流计算平台提供了一个完善的监控大盘,让用户来可以实时的看到他们所关心的每一个指标,当然用户还可以去自定义更个性化的指标。在下面的图中,分别给出了延迟,和吞吐量(就是应用最大能够消费多大的一个数据量,极限是多少)的实时数据。同时对用户来说,不可能实时的去盯着监控大盘,查看这个任务到底有没有出问题,因此流计算平台也提供了针对各个指标的报警服务,平台会根据适当的策略进行实时告警。
任务诊断体系
· 虽然流计算平台提供了监控报警的服务,但是用户看到报警数据以后,有可能没法及时有效的去判断自己的实时计算作业到底发生了什么,出现了什么问题。因此流计算平台还提供了任务诊断的服务,流计算平台会把用户任务的一些日志,包括流计算引擎里面的日志进行实时的采集,然后实时的接入到ES里面,这样用户就可以实时的查到指定应用的日志了。然后对于监控大盘里面看到的监控数据,流计算平台还会在Druid中保存一段时间。然后流计算平台修复了Watermark没法正常显示等Flink UI上面的问题。这样可以让用户能够更好地去查看监控,以及对问题进行诊断。
Flink在滴滴的生产实践
生产实践
滴滴的流计算业务在滴滴内部来讲,对于用户认可的业务场景来说,简单的归纳一下,主要是以下四种:
· 实时ETL
· 实时数据报表
· 实时业务监控。
· 然后还有一个就是CEP在线业务。
业务场景——实时网管监控
背景
· 相信很多公司都会有一个业务网关,从网关上面可以看到的各个业务线,网关上面会对每一个业务线去做一些像业务分发这样的逻辑,如果业务线非常庞大,例如滴滴就有很多业务线。
· 如果某一个业务在某一时刻出现了故障,我们怎么能够快速的发现,同时怎么快速的定位到问题。例如网关后面的每一个业务都会有相关的调用关系,一个Service A有可能会依赖于Service B或者是Service C,然后如果一个服务出现故障以后,依赖这个服务的其他服务也有可能会出问题。
· 但是从应用最上层来看,某个业务曲线出现了下跌,或者是说曲线毛刺很高,这是不符合预期,是异常的。对于这样的一些问题,对内部系统来说,如果一个个模块去排查,是很难排查的,相当于说需要将链路上面的每一个调用关系都一个一个的进行排查,这个过程是相当复杂的。
· 因此滴滴内部做了一套实时的日志监控系统,能够实时的按业务线进行监控。每一个业务都会细化到每一个子业务,实时的去反映一个系统的服务到底是好还是坏。为了能够支持这样的一些业务场景,我们进行了适当的抽象,把所有的网络日志全部采集到Kafka的一个topic里面,Topic里面的日志能够覆盖到滴滴90%的业务,然后我们会按照业务和服务去做一些Filter, Group By以及一定范围内的Window聚合等计算服务。
架构
在前面是介绍了我们这个系统的背景,然后现在来看看滴滴这个系统的架构设计。最前面是滴滴的数据采集服务,然后日志数据会被统一收集到Kafka中,在中间这一块,主要由Flink Streaming来进行处理,这里面是一个Pipline,例如在这个Pipline里面会进行一系列操作:数据展开,数据展开以后,会根据具体的规则进行实时匹配,同时因为规则会动态更新,所以匹配的过程中是需要考虑的。对于规则的动态更新,在滴滴是通过配置流来实现的。配置流更新以后,会广播到下游的算子中去,下游的算子接收到规则更新以后,会对主数据流进行相应的变更。数据处理完以后,会把数据落到后端的一些系统里面去。比如ES,数据进入ES以后,会有各种各样的使用方式,比如说实时的进行展示,基于这些数据进行判断是否需要进行告警。从整个链路上面来讲,整个实时网关日志架构还是非常清晰的。
StreamSQL
滴滴内部的StreamSQL正在开发中,以后会作为滴滴内部流计算主要的使用方式,滴滴内部的StreamSQL的核心功能如下:
· 第一个就是支持DDL。滴滴内部使用的数据比较多,格式也比较多,所以滴滴StreamSQL的DDL具有支持多格式以及多数据源的特点。
· 第二个就是支持DML,对于DML在滴滴,只有一种即:INSERT INTO TABLE,就是插入流数据到某一张表,这个表的一定是一张Sink表,并且只能插入到要输出的一个下游。
· 然后是一些常用的、核心的一些功能点。比如Group Agg、Window Agg, Join。Join的场景主要有两种:一种是双流上面no-window join以及流和维度表的Join,同时也支持UDF、UDTF、UDAF等用户自定义函数。
在这里简单的介绍一下滴滴定义数据源的一种方式,比如说现在要从Kafka中加载数据,我们的元数据具有各种各样的格式,比如说是JSON的,需要用户去指定所定义的数据流的Schema,同时定义Schema的时候,必须要指定数据类型。然后在滴滴用的比较多的一个业务场景是分流SQL,也就是说一条数据可能会往多个地方写,例如既要写Hbase又要写Kafka这样的一些需求。Flink官方的Stream SQL是不支持这么去做的,原因可能是因为SQL的一些限制导致的,但是滴滴的Stream SQL支持分流这一新特性。同时Stream Join也是我们正在着力推进的一个功能点,双流noWindow的join,在滴滴也是准备支持的,也是滴滴正在不断研发的一个新特性。当然noWindow是滴滴给出的一个复杂概念,真正的数据当然还是有一定的状态,Window里面的数据还是会有一定的过期时间的,只是说滴滴正在尝试天级别的一个过期时间。在用户设置以后,会在指定的一个时间,比如说每天凌晨或者说固定的一个时间点,将一些过去的数据一次性的清空掉。最后对于维度表,滴滴Stream SQL Join的永远是当前表,并且只支持当前表,不支持和历史表进行Join,也不支持数据的回撤。
展望规划
前面讲到的StreamSQL,滴滴内部正在不断推进。下图是Flink在滴滴内部的一个大致的规划和展望。
1、我们希望StreamSQL以后会承载滴滴内部至少90%的流计算任务,越来越多的任务都会慢慢的往StreamSQL上面迁移,比如说增加的新任务,以及历史遗留的一些任务。
2、第二个是关于CEP,滴滴也会将其融入到StreamSQL的体系中,同时会不断的进行这方面性能优化。
3、第三点是关于业务场景的,在滴滴,监控和实时报表这样的一些业务场景会占比较多的一个部分。以后滴滴会探索开发更多业务场景,让Flink不断成长。
4、第四点是为了去应对流量突发带来的稳定性的一些问题,滴滴会在动态扩容上做更多的一些事情,同时滴滴也正在尝试在算子级别进行资源的自动缩扩。