摘要:本文整顿自蔚来汽车大数据部门数据开发、OLAP 平台 tech lead 吴江在 Flink Forward Asia 2021 行业实际专场的演讲。次要内容包含:

  1. 实时计算在蔚来的倒退历程
  2. 实时计算平台
  3. 实时看板
  4. CDP
  5. 实时数仓
  6. 其余利用场景

点击查看直播回放 & 演讲PDF

一、 实时计算在蔚来的倒退历程

  • 18 年 5 月份左右,咱们开始接触实时计算的概念,最后是用 Spark Streaming 做一些简略的流式计算数据的解决;
  • 19 年 9 月份咱们引入了 Flink,通过命令行的形式进行提交,包含治理整个作业的生命周期;
  • 到了 21 年 1 月份,咱们上线了实时计算平台 1.0,目前正在进行 2.0 版本的开发。

二、实时计算平台

在实时计算平台 1.0,咱们是通过将代码进行编译,而后上传 jar 包到一个服务器上,以命令行的形式进行提交。这个过程中存在很多问题:

  • 首先,所有流程都是手动的,十分繁琐而且容易出错;
  • 其次,不足监控,Flink 自身内置了很多监控,然而没有一个主动的形式将它们加上去,还是须要手动地去做配置;
  • 此外,工作的保护也十分麻烦,一些不太熟悉的开发人员进行操作很容易呈现问题,而且呈现问题之后也难以排查。

实时计算平台 1.0 的生命周期如上图。工作写完之后打成 jar 包进行上传提交,后续的开启工作、进行、复原和监控都可能主动进行。

作业管理次要负责作业的创立、运行、进行、复原和更新。日志次要记录 Flink 工作提交时的一些日志,如果是运行时的日志还是要通过 Yarn 集群里的 log 来查看,略微有点麻烦。对于监控和告警模块,首先 metrics 监控次要是利用 Flink 内置的指标上传到 Prometheus,而后配置各种监控的界面,告警也是利用 Prometheus 的一些指标进行规定的设置,而后进行告警的设置。Yarn 负责整体集群资源的治理。

上图是实时计算平台 1.0 的界面,整体性能比较简单。

上图是实时计算平台 2.0。绝对于 1.0,最大的区别是蓝色的局部。对于实时计算平台的状态,可能并没有一个对立的规范,它与每个公司自身的状况非亲非故,比方公司自身的体量和规模、公司对实时计算平台的资源投入等,最终还是应该以实用于公司自身的现状为最佳规范。

2.0 版本咱们减少从开发到测试两个阶段性能的反对。简略介绍一下它们的具体性能:

  • FlinkSQL:它是很多公司的实时计算平台都反对的性能,它的长处在于能够升高应用老本,也比较简单易用。
  • 空间治理:不同的部门和不同的组能够在本人的空间里进行作业的创立、治理。有了空间的概念之后,咱们能够利用它做一些权限的管制,比方只能在本人有权限的空间里进行一些操作。
  • UDF 治理:应用了 FlinkSQL 的前提下,就能够基于 SQL 的语义用 UDF 的形式裁减性能。此外,UDF 还能用于 Java 和 Schema 工作,能够把一些专用的性能包装成 UDF,升高开发成本。它还有一个很重要的性能就是调试,能够简化原有的调试流程,做到用户无感知。

实时计算平台 2.0 的实现,带给咱们最大的影响就是加重了数据团队的累赘。在咱们原先的开发流程里,常常须要数据团队的染指,但实际上其中的很大一部分工作都是比较简单的,比方数据同步或数据的简略解决,这类工作并不一定须要数据团队去染指。

咱们只须要把实时计算平台做得更欠缺、易用和简略,其余的团队就能够应用 FlinkSQL 去做上述简略的工作,现实的状况下他们甚至不须要晓得 Flink 的相干概念就能够做一些 Flink 的开发。比方后盾人员做业务侧开发的时候,对于一些比较简单的场景就不须要依赖数据团队,大大降低沟通老本,进度会更快。这样在部门内有一个闭环会更好一点。而且以这样的形式,各个角色其实都会感觉比拟开心。产品经理的工作也会变得更轻松,在需要的阶段不须要引入太多的团队,工作量也会变少。

所以,这是一个以技术的形式来优化组织流程的很好的例子。

三、实时看板

实时看板是一个比拟常见的性能,在咱们的具体实现中,次要发现了以下几个难点:

  • 第一,数据提早上报。比方业务数据库产生问题后,进行 CDC 接入的时候就须要中断,包含后续写到 Kafka,如果 Kafka 集群负载很高或 Kafka 产生问题,也会中断一段时间,这些都会造成数据的提早。上述提早在实践上能够防止,但实际上很难完全避免。此外还有一些实践上就不能完全避免的提早,比方用户的流量或信号有问题导致操作日志无奈实时上传。
  • 第二,流批一体。次要在于历史数据和实时数据是否对立。
  • 第三,维度的实时抉择。实时看板可能须要灵便抉择多个维度值,比方想先看北京的沉闷用户数,再看上海的沉闷用户数,最初看北京 + 上海的沉闷用户数,这个维度是依据须要能够灵便抉择的。
  • 第四,指标的验证。指标的验证在离线的状况下,相对来说比较简单一些,比如说能够做一些数据分布,看看每个散布的大略状况,也能够通过 ODS 层数据的计算与两头表进行比对,做穿插验证。然而在实时的状况下就比拟麻烦,因为实时处理是始终在进行的,有些状况很难去复现,此外也很难进行指标范畴或散布的验证。

实时看板个别存在两个方面的需要:

  • 首先是时延方面,不同的场景对时延的要求是不同的,比方有些场景下可能承受数据提早 1-2 分钟达到,但有的场景下只容许提早几秒钟。不同场景下实际的技术计划复杂度不一样。
  • 其次,须要兼顾实时与历史看板的性能。有些场景下,除了须要看实时的数据变动,还须要比照着历史数据来一起剖析。

实时与历史数据应该进行对立的存储,否则可能会存在很多问题。首先,实现的时候表构造比较复杂,查问的时候可能须要判断哪段时间是历史数据,哪段时间是实时数据,而后对它们进行拼接,会导致查问的实现老本过高。其次,在历史数据进行切换的时候也很容易呈现问题,比方每天凌晨定时刷新历史数据,此时如果历史工作产生提早或谬误,很容易导致查出来的数据是谬误的。

咱们外部对实时看板的延时性要求比拟高,个别要求在秒级以内,因为咱们心愿大屏幕上的数字是时刻在跳动和变动的。传统的计划个别是采纳拉的形式,比如说每秒查一次数据库,实现的难度比拟大,因为一个页面会蕴含很多指标,须要同时发送很多接口去查问数据,想让所有数据都在一秒钟之内返回是不太可能的。另外,如果很多用户同时进行查问,会导致负载很高,时效性更难以保障。

所以咱们采取了推的形式,上图是具体实现的架构图,次要分为三层。第一层是数据层即 Kafka 的实时数仓,通过 Flink 对这些数据进行解决后将它们实时地推到后盾,后盾再实时地把它们推到前端。后盾与前端的交互是通过 web socket 来实现的,这样就能够做到所有的数据都是实时推送。

在这个需要场景下,有一些性能会比较复杂。

举个简略例子,比方统计实时去重人数 UV,其中一个维度是城市,一个用户可能对应多个城市,抉择上海和北京两个城市的 UV 数,就意味着要把上海和北京的人放到一起进行去重,算进去去重的实时 UV 数据,这是一件比拟麻烦的事件。从离线的角度来看,选多个维度是非常简单的,把维度选好之后间接取出数据进行聚合即可。然而在实时场景下,要在哪些维度进行聚合是提前指定好的。

第一个计划是,在 Flink 状态中存储所有 user ID 和呈现过的维度,并间接计算所有可能的维度组合 UV,而后将更新过的 UV 推送给前端。

但这种形式会减少很多计算成本,而且会导致维度爆炸,从而导致存储老本也急剧减少。

第二种计划的架构图如上。咱们把 sink 作为一个流式的外围,把端到端整体作为一个流式利用,比方把数据的接入、在 Flink 中数据的解决计算、再到后盾、通过 web socket 推给前端这一整体作为一个利用来思考。

咱们会在 Flink 外面存储每个用户所有的维度值,后盾的 Flink 推送的用户具体情况也会存在每个城市下 user ID 的 list 里。Flink 领有一个很要害的排除性能,如果用户曾经呈现过,那么在 Flink 阶段就不会把变更推送到前端和后盾;如果用户没呈现过,或者用户呈现过但城市没呈现过,那就会把用户与城市的组合推送给后盾,保障后盾能够拿到每个城市下用户 ID 去重的 list。

前端抉择维度之后,能够对后盾不同维度的 user ID 进行增量的订阅。这里有两个点须要留神:

  • 第一是在前端刚关上在抉择纬度的时候,有一个初始化的过程,它会从后盾读取所选维度的全量用户 ID 来做一个合集,而后计算 UV 人数。
  • 在第二个阶段新的用户 ID 达到之后,会通过 Flink 推送给后盾,而后盾只会推送增量 ID 给前端,而后前端因为曾经保留了之前的合集,对于增量的 ID,它就能够间接用 O(1) 的工夫去算出新的合集,并且计算出它的 UV 人数。

可能有人会问,在这个计划下,用户太多怎么办?前端会不会占用太多的资源?

首先,从目前咱们的理论应用场景来看,这个计划是够用的,如果当前 ID 数激增,用 bitmap 也是一种抉择,但只用 bitmap 也不足以解决问题。因为不同公司用户 ID 的生成规定不一样,有些是自增 ID,有些是非自增 ID 或者甚至都不是一个数值,那就须要做映射,如果是一个离散的数值也须要额定做一些解决。

第一种计划把 ID 从 1 开始从新编码,使它变得比拟小且间断。目前大部分场景下大家可能都是用 RoaringBitMap,它的特点是如果 ID 十分稠密,它在理论存储的时候会应用一个 list 来存,而不是用 bitmap 来存,也就无奈达到缩小占用内存的目标。所以要尽量让 ID 的空间变小,让 ID 的值比拟间断。

但这样还不够,如果 ID 是之前没呈现过的,就须要给它重新分配一个 ID,然而解决这些数据的时候,Flink task 的并行度可能大于 1,这个时候多个节点同时生产数据的话,它们可能都会遇到同样的新 ID,如何给这个 ID 调配对应的新的映射的小 ID?

举个例子,一个节点查问之后须要生成一个新 ID,同时又要保障其余节点不会再生成雷同的 ID,能够通过在新 ID 上做惟一索引来保障,把索引创立胜利就生成了新 ID,失败的节点能够进行重试操作,去取当初的 ID mapping,因为方才曾经有其余节点生成这个 ID 了,所以它在重试取 mapping 阶段肯定会胜利。

除此之外,还须要思考一种场景,比方用户注册实现后,马上产生一些行为,而用户注册与一些业务模块的行为表可能是由不同业务部门开发,也可能会存在不同的数据库、不同的表外面,甚至是不同类型的数据库,上述情况的接入形式也会不一样,可能会导致尽管是先注册,然而注册数据流可能会略微晚于行为数据流达到,这会不会导致呈现什么问题?

目前看来是不会的,只须要行为数据流与新用户注册数据流共享一个 ID mapping 即可。

综上,一个好的架构,即便面对数据量激增的状况,也是不须要在架构层面进行大改的,只须要在细节上进行从新设计。

第二个问题是前端会不会有很大的计算负载?

答案是:不会。尽管人数的去重是由前端来做,但只有前端第一次加载的时候才须要将用户全量拉取,之后的增量 user ID 都会间接用 O(1) 的形式退出到目前的汇合里,所以前端的计算累赘是很低的,整个过程齐全是流式的。

第三个问题是实时报表同时拜访的用户数很多怎么办?

从目前的架构上来看,对 Flink 和后盾侧根本没有影响,惟一的影响就是如果有很多用户同时拜访,他们的页面须要同时与后盾建设 web socket 连贯。然而因为实时报表次要还是外部应用,不会对外,所以同时的访问量不会太多。

而且咱们把数据 ID 去重的一部分职责放在前端,即便有多个用户同时拜访,计算职责也会摊派到不同的用户浏览器外面去,实际上也不会有过多负载。

四、CDP

CDP 是一个经营平台,负责偏后盾的工作。咱们的 CDP 须要存储一些数据,比方属性的数据存在 ES 里、行为的明细数据包含统计数据存在 Doris 里、工作执行状况存在 TiDB。也存在一些实时场景的利用。

第一个是属性须要实时更新,否则可能造成经营成果不佳。第二个是行为的聚合数据有时候也须要实时更新。

五、实时数仓

实时数仓重点考量点有以下几个:

  • 元信息管理,包含 Catalog 的治理。
  • 分层,如何进行正当的分层。
  • 建模,实时数仓应该如何建模,它与离线数仓的建模形式有什么区别?
  • 时效性,时延越低越好,链路越短越好。

上图是咱们目前的实时数仓架构图。它整体上与离线数仓十分类似,也是有一个原始层、DWD 层、DWS 层和 Application 层。

不同之处在于它有一个维度层 (DIM 层),外面有很多不同的存储介质,维度信息能够放在 TiDB,并通过 AIO 的形式拜访维度表;也能够放在 Hive,用 Temporal Join 的形式去进行关联;有一些数据是始终在变动的,或者须要做一些基于工夫的关联,能够把数据放到 Kafka 里,而后用 Broadcast 或者 Temporal Join 去进行关联。

左侧是咱们正在布局中的能力。

  • 第一个是血缘关系,它对于问题的溯源,以及对改变的影响的评估是有帮忙的;
  • 第二个是元信息管理,咱们心愿把所有数据都表化,在进行数据处理的时候能够间接用 SQL 搞定;
  • 第三个是权限治理,对于不同的数据源、不同的表,都是须要做权限治理的;
  • 第四个是数据品质,如何进行数据品质的保障。

上面是对这些将来布局的具体论述。

第一,Catalog 治理,这个性能目前暂未开发。咱们心愿为所有数据源创立一个表,不论外面的数据是维表还是其余表,是存在 MySQL 还是存在 Kafka,创立表之后都能够将这些细节屏蔽,通过 SQL 的形式就能轻松应用它。

第二,正当的分层。分层会对实时数仓造成多方面的影响。

  • 首先,分层越多,时延越大。实时数仓是否须要这么多分层,值得沉思。
  • 其次,实时数据的品质监控会比离线数据更简单,因为它是在不停地进行解决,分层越多,越难以发现问题、定位问题并进行回溯或复现,包含数据集成的散布也不易监控。
  • 最初,如何进行正当的分层。必定须要尽可能减少层数,并且进行正当的业务性能垂直划分,如果不同业务之间的交加很少,就尽量在各自业务畛域内建设本人独自的分层。

第三,建模。这是离线数仓十分重要的局部,因为离线数仓十分大的一部分用户是分析师,他们日常工作就是用 SQL 进行数据的查问和剖析,这个时候就必须要思考到易用性,比方大家都喜爱大宽表,所有相干字段都放到一个表里。所以在离线数仓建模和设计表构造的时候,就须要尽量把一些可能用到的维度都加上。

而实时数仓面对的更多的是开发者,所以更强调实用性。因为在实时数仓的需要下,宽表里每减少一个字段都会减少时延,特地是维度的减少。所以说实时数仓的场景维表和建模更适宜按理论需要来做。

第四,时效性。实时数仓自身还是须要有 raw 层,然而时效性比拟高的场景,比方要同步一些线上的数据,这个数据最初同步快充也是线上的业务应用,要尽量减少链路,缩小时延。比方能够用一些 Flink CDC 的形式缩小中间层,这样不单缩小了整体的链路和时延,链路节点缩小也意味着问题产生的概率变小。对于时延要求没有那么高的外部剖析场景,尽量抉择应用实时数仓,能够缩小数据的冗余。

六、其余利用场景

其余的应用场景还包含 CQRS 类利用。比方业务部门的性能更多的是思考增删改查或者是传统数据库操作,但后续还是会存在数据分析的场景,这个时候用业务库去做剖析是一个不太正确的办法,因为业务库的设计原本就没有思考剖析,更适宜应用剖析的 OLAP 引擎来做这项工作。这样也就把业务部门要负责的工作和数据部门负责的工作宰割开来,大家各司其职。

此外还有指标的监控和异样检测。比方对各种指标通过 Flink 进行实时的检测,它会 load 一个机器学习模型,而后实时检测指标的变动是否合乎预期,和预期的差距有多大,还能够设置一个区域值来进行指标的异样检测。

实时数据的场景越来越多,大家对实时数据的需要也越来越多,所以将来咱们会持续进行实时数据方面的摸索。咱们在流批一体的实时和离线存储对立上曾经有了一些产出,咱们也会在这方面投入更多精力,包含 Flink CDC 是否真的能够缩小链路,进步响应效率,也是咱们会去思考的问题。


点击查看直播回放 & 演讲PDF

更多 Flink 相干技术问题,可扫码退出社区钉钉交换群
第一工夫获取最新技术文章和社区动静,请关注公众号~