乐趣区

关于Flink:快手基于-Flink-构建实时数仓场景化实践

本文整顿自快手数据技术专家李天朔在 5 月 22 日北京站 Flink Meetup 分享的议题《快手基于 Flink 构建实时数仓场景化实际》,内容包含:

  1. 快手实时计算场景
  2. 快手实时数仓架构及保障措施
  3. 快手场景问题及解决方案
  4. 将来布局

一、快手实时计算场景

快手业务中的实时计算场景次要分为四块:

  • 公司级别的外围数据: 包含公司经营大盘,实时外围日报,以及挪动版数据。相当于团队会有公司的大盘指标,以及各个业务线,比方视频相干、直播相干,都会有一个外围的实时看板;
  • 大型流动实时指标: 其中最外围的内容是实时大屏。例如快手的春晚流动,咱们会有一个总体的大屏去看总体流动现状。一个大型的流动会分为 N 个不同的模块,咱们对每一个模块不同的玩法会有不同的实时数据看板;
  • 经营局部的数据: 经营数据次要包含两方面,一个是创作者,另一个是内容。对于创作者和内容,在经营侧,比方上线一个大 V 的流动,咱们想看到一些信息如直播间的实时现状,以及直播间对于大盘的牵引状况。基于这个场景,咱们会做各种实时大屏的多维数据,以及大盘的一些数据。

    此外,这块还包含经营策略的撑持,比方咱们可能会实时挖掘一些热点内容和热点创作者,以及目前的一些热点状况。咱们基于这些热点状况输入策略,这个也是咱们须要提供的一些撑持能力;

    最初还包含 C 端数据展现,比方当初快手里有创作者核心和主播核心,这里会有一些如主播关播的关播页,关播页的实时数据有一部分也是咱们做的。

  • 实时特色: 蕴含搜寻举荐特色和广告实时特色。

二、快手实时数仓架构及保障措施

1. 指标及难点

1.1 指标

  • 首先因为咱们是做数仓的,因而心愿所有的实时指标都有离线指标去对应,要求实时指标和离线指标整体的数据差别在 1% 以内,这是最低标准。
  • 其次是数据提早,其 SLA 规范是流动期间所有外围报表场景的数据提早不能超过 5 分钟,这 5 分钟包含作业挂掉之后和复原工夫,如果超过则意味着 SLA 不达标。
  • 最初是稳定性,针对一些场景,比方作业重启后,咱们的曲线是失常的,不会因为作业重启导致指标产出一些显著的异样。

1.2 难点

  • 第一个难点是数据量大。每天整体的入口流量数据量级大略在万亿级。在流动如春晚的场景,QPS 峰值能达到亿 / 秒。
  • 第二个难点是组件依赖比较复杂。可能这条链路里有的依赖于 Kafka,有的依赖 Flink,还有一些依赖 KV 存储、RPC 接口、OLAP 引擎等,咱们须要思考在这条链路里如何散布,能力让这些组件都能失常工作。
  • 第三个难点是链路简单。目前咱们有 200+ 外围业务作业,50+ 外围数据源,整体作业超过 1000。

2. 实时数仓 – 分层模型

基于下面三个难点,来看一下数仓架构:

如上所示:

  • 最上层有三个不同的数据源,别离是客户端日志、服务端日志以及 Binlog 日志;
  • 在公共根底层分为两个不同的档次,一个是 DWD 层,做明细数据,另一个是 DWS 层,做公共聚合数据,DIM 是咱们常说的维度。咱们有一个基于离线数仓的主题预分层,这个主题预分层可能包含流量、用户、设施、视频的生产生产、风控、社交等。

    • DWD 层的外围工作是标准化的荡涤;
    • DWS 层是把维度的数据和 DWD 层进行关联,关联之后生成一些通用粒度的聚合档次。
  • 再往上是应用层,包含一些大盘的数据,多维分析的模型以及业务专题数据;
  • 最下面是场景。

整体过程能够分为三步:

  • 第一步是做业务数据化,相当于把业务的数据接进来;
  • 第二步是数据资产化,意思是对数据做很多的荡涤,而后造成一些规定有序的数据;
  • 第三步是数据业务化,能够了解数据在实时数据层面能够反哺业务,为业务数据价值建设提供一些赋能。

3. 实时数仓 – 保障措施

基于下面的分层模型,来看一下整体的保障措施:

保障层面分为三个不同的局部,别离是品质保障,时效保障以及稳固保障。

  • 咱们先看蓝色局部的品质保障。针对品质保障,能够看到在数据源阶段,做了如数据源的乱序监控,这是咱们基于本人的 SDK 的采集做的,以及数据源和离线的一致性校准。研发阶段的计算过程有三个阶段,别离是研发阶段、上线阶段和服务阶段。

    • 研发阶段可能会提供一个标准化的模型,基于这个模型会有一些 Benchmark,并且做离线的比对验证,保证质量是统一的;
    • 上线阶段更多的是服务监控和指标监控;
    • 在服务阶段,如果呈现一些异常情况,先做 Flink 状态拉起,如果呈现了一些不合乎预期的场景,咱们会做离线的整体数据修复。
  • 第二个是时效性保障。针对数据源,咱们把数据源的提早状况也纳入监控。在研发阶段其实还有两个事件:

    • 首先是压测,惯例的工作会拿最近 7 天或者最近 14 天的峰值流量去看它是否存在工作提早的状况;
    • 通过压测之后,会有一些工作上线和重启性能评估,相当于依照 CP 复原之后,重启的性能是什么样子。
  • 最初一个是稳固保障,这在大型流动中会做得比拟多,比方切换演练和分级保障。咱们会基于之前的压测后果做限流,目标是保障作业在超过极限的状况下,依然是稳固的,不会呈现很多的不稳固或者 CP 失败的状况。之后咱们会有两种不同的规范,一种是冷备双机房,另外一种是热备双机房。

    • 冷备双机房是:当一个单机房挂掉,咱们会从另一个机房去拉起;
    • 热备双机房:相当于同样一份逻辑在两个机房各部署一次。

以上就是咱们整体的保障措施。

三、快手场景问题及解决方案

1. PV/UV 标准化

1.1 场景

第一个问题是 PV/UV 标准化,这里有三个截图:

第一张图是春晚流动的预热场景,相当于是一种玩法,第二和第三张图是春晚当天的发红包流动和直播间截图。

在流动进行过程中,咱们发现 60~70% 的需要是计算页面里的信息,如:

  • 这个页面来了多少人,或者有多少人点击进入这个页面;
  • 流动一共来了多少人;
  • 页面里的某一个挂件,取得了多少点击、产生了多少曝光。

1.2 计划

形象一下这个场景就是上面这种 SQL:

简略来说,就是从一张表做筛选条件,而后依照维度层面做聚合,接着产生一些 Count 或者 Sum 操作。

基于这种场景,咱们最开始的解决方案如上图左边所示。

咱们用到了 Flink SQL 的 Early Fire 机制,从 Source 数据源取数据,之后做了 DID 的分桶。比方最开始紫色的局部按这个做分桶,先做分桶的起因是避免某一个 DID 存在热点的问题。分桶之后会有一个叫做 Local Window Agg 的货色,相当于数据分完桶之后把雷同类型的数据相加。Local Window Agg 之后再依照维度进行 Global Window Agg 的合桶,合桶的概念相当于依照维度计算出最终的后果。Early Fire 机制相当于在 Local Window Agg 开一个天级的窗口,而后每分钟去对外输入一次。

这个过程中咱们遇到了一些问题,如上图左下角所示。

在代码失常运行的状况下是没有问题的,但如果整体数据存在提早或者追溯历史数据的状况,比方一分钟 Early Fire 一次,因为追溯历史的时候数据量会比拟大,所以可能导致 14:00 追溯历史,间接读到了 14:02 的数据,而 14:01 的那个点就被丢掉了,丢掉了当前会产生什么?

在这种场景下,图中上方的曲线为 Early Fire 回溯历史数据的后果。横坐标是分钟,纵坐标是截止到以后时刻的页面 UV,咱们发现有些点是横着的,意味着没有数据后果,而后一个陡增,而后又横着的,接着又一个陡增,而这个曲线的预期后果其实是图中下方那种平滑的曲线。

为了解决这个问题,咱们用到了 Cumulate Window 的解决方案,这个解决方案在 Flink 1.13 版本里也有波及,其原理是一样的。

数据开一个大的天级窗口,大窗口下又开了一个小的分钟级窗口,数据按数据自身的 Row Time 落到分钟级窗口。

  • Watermark 推动过了窗口的 event_time,它会进行一次下发的触发,通过这种形式能够解决回溯的问题,数据自身落在实在的窗口,Watermark 推动,在窗口完结后触发。
  • 此外,这种形式在肯定水平上可能解决乱序的问题。比方它的乱序数据自身是一个不抛弃的状态,会记录到最新的累计数据。
  • 最初是语义一致性,它会基于事件工夫,在乱序不重大的状况下,和离线计算出来的后果一致性是相当高的。

以上是 PV/UV 一个标准化的解决方案。

2. DAU 计算

2.1 背景介绍

上面介绍一下 DAU 计算:

咱们对于整个大盘的沉闷设施、新增设施和回流设施有比拟多的监控。

  • 沉闷设施指的是当天来过的设施;
  • 新增设施指的是当天来过且历史没有来过的设施;
  • 回流设施指的是当天来过且 N 天内没有来过的设施。

然而咱们计算过程之中可能须要 5~8 个这样不同的 Topic 去计算这几个指标。

咱们看一下离线过程中,逻辑应该怎么算。

首先咱们先算沉闷设施,把这些合并到一起,而后做一个维度下的天级别去重,接着再去关联维度表,这个维度表包含设施的首末次工夫,就是截止到昨天设施首次拜访和末次访问的工夫。

失去这个信息之后,咱们就能够进行逻辑计算,而后咱们会发现新增和回流的设施其实是沉闷设施里打的一个子标签。新增设施就是做了一个逻辑解决,回流设施是做了 30 天的逻辑解决,基于这样的解决方案,咱们是否简略地写一个 SQL 去解决这个问题?

其实咱们最开始是这么做的,但遇到了一些问题:

  • 第一个问题是:数据源是 6~8 个,而且咱们大盘的口径常常会做微调,如果是单作业的话,每次微调的过程之中都要改,单作业的稳定性会十分差;
  • 第二个问题是:数据量是万亿级,这会导致两个状况,首先是这个量级的单作业稳定性十分差,其次是实时关联维表的时候用的 KV 存储,任何一个这样的 RPC 服务接口,都不可能在万亿级数据量的场景下保障服务稳定性;
  • 第三个问题是:咱们对于时延要求比拟高,要求时延小于一分钟。整个链路要防止批处理,如果呈现了一些工作性能的单点问题,咱们还要保障高性能和可扩容。

2.2 技术计划

针对以上问题,介绍一下咱们是怎么做的:

如上图的例子,第一步是对 A B C 这三个数据源,先依照维度和 DID 做分钟级别去重,别离去重之后失去三个分钟级别去重的数据源,接着把它们 Union 到一起,而后再进行同样的逻辑操作。

这相当于咱们数据源的入口从万亿变到了百亿的级别,分钟级别去重之后再进行一个天级别的去重,产生的数据源就能够从百亿变成了几十亿的级别。

在几十亿级别数据量的状况下,咱们再去关联数据服务化,这就是一种比拟可行的状态,相当于去关联用户画像的 RPC 接口,失去 RPC 接口之后,最终写入到了指标 Topic。这个指标 Topic 会导入到 OLAP 引擎,供应多个不同的服务,包含挪动版服务,大屏服务,指标看板服务等。

这个计划有三个方面的劣势,别离是稳定性、时效性和准确性。

  • 首先是稳定性。松耦合能够简略了解为当数据源 A 的逻辑和数据源 B 的逻辑须要批改时,能够独自批改。第二是工作可扩容,因为咱们把所有逻辑拆分得十分细粒度,当一些中央呈现了如流量问题,不会影响前面的局部,所以它扩容比较简单,除此之外还有服务化后置和状态可控。
  • 其次是时效性,咱们做到毫秒提早,并且维度丰盛,整体上有 20+ 的维度做多维聚合。
  • 最初是准确性,咱们反对数据验证、实时监控、模型进口对立等。

此时咱们遇到了另外一个问题 – 乱序。对于上方三个不同的作业,每一个作业重启至多会有两分钟左右的提早,提早会导致上游的数据源 Union 到一起就会有乱序。

2.3 提早计算计划

遇到下面这种有乱序的状况下,咱们要怎么解决?

咱们总共有三种解决计划:

  • 第一种解决方案是用“did + 维度 + 分钟”进行去重,Value 设为“是否来过”。比方同一个 did,04:01 来了一条,它会进行后果输入。同样的,04:02 和 04:04 也会进行后果输入。但如果 04:01 再来,它就会抛弃,但如果 04:00 来,依旧会进行后果输入。

    这个解决方案存在一些问题,因为咱们按分钟存,存 20 分钟的状态大小是存 10 分钟的两倍,到前面这个状态大小有点不太可控,因而咱们又换了解决方案 2。

  • 第二种解决方案,咱们的做法会波及到一个假如前提,就是假如不存在数据源乱序的状况。在这种状况下,key 存的是“did + 维度”,Value 为“工夫戳”,它的更新形式如上图所示。

    04:01 来了一条数据,进行后果输入。04:02 来了一条数据,如果是同一个 did,那么它会更新工夫戳,而后依然做后果输入。04:04 也是同样的逻辑,而后将工夫戳更新到 04:04,如果前面来了一条 04:01 的数据,它发现工夫戳曾经更新到 04:04,它会抛弃这条数据。

    这样的做法大幅度缩小了自身所须要的一些状态,然而对乱序是零容忍,不容许产生任何乱序的状况,因为咱们不好解决这个问题,因而咱们又想出了解决方案 3。

  • 计划 3 是在计划 2 工夫戳的根底之上,加了一个相似于环形缓冲区,在缓冲区之内容许乱序。

    比方 04:01 来了一条数据,进行后果输入;04:02 来了一条数据,它会把工夫戳更新到 04:02,并且会记录同一个设施在 04:01 也来过。如果 04:04 再来了一条数据,就依照相应的时间差做一个位移,最初通过这样的逻辑去保障它可能容忍肯定的乱序。

综合来看这三个计划:

  • 计划 1 在容忍 16 分钟乱序的状况下,单作业的状态大小在 480G 左右。这种状况尽管保障了准确性,然而作业的复原和稳定性是齐全不可控的状态,因而咱们还是放弃了这个计划;
  • 计划 2 是 30G 左右的状态大小,对于乱序 0 容忍,然而数据不精确,因为咱们对准确性的要求十分高,因而也放弃了这个计划;
  • 计划 3 的状态跟计划 1 相比,它的状态尽管变动了然而减少的不多,而且整体能达到跟计划 1 同样的成果。计划 3 容忍乱序的工夫是 16 分钟,咱们失常更新一个作业的话,10 分钟齐全足够重启,因而最终抉择了计划 3。

3. 经营场景

3.1 背景介绍

经营场景可分为四个局部:

  • 第一个是数据大屏反对,包含单直播间的剖析数据和大盘的剖析数据,须要做到分钟级提早,更新要求比拟高;
  • 第二个是直播看板反对,直播看板的数据会有特定维度的剖析,特定人群反对,对维度丰富性要求比拟高;
  • 第三个是数据策略榜单,这个榜单次要是预测热门作品、爆款,要求的是小时级别的数据,更新要求比拟低;
  • 第四个是 C 端实时指标展现,查问量比拟大,然而查问模式比拟固定。

上面进行剖析这 4 种不同的状态产生的一些不同的场景。

前 3 种根本没有什么差异,只是在查问模式上,有的是特定业务场景,有的是通用业务场景。

针对第 3 种和第 4 种,它对于更新的要求比拟低,对于吞吐的要求比拟高,过程之中的曲线也不要求有一致性。第 4 种查问模式更多的是单实体的一些查问,比方去查问内容,会有哪些指标,而且对 QPS 要求比拟高。

3.2 技术计划

针对上方 4 种不同的场景,咱们是如何去做的?

  • 首先看一下根底明细层 (图中左方),数据源有两条链路,其中一条链路是生产的流,比方直播的生产信息,还有观看 / 点赞 / 评论。通过一轮根底荡涤,而后做维度治理。上游的这些维度信息来源于 Kafka,Kafka 写入了一些内容的维度,放到了 KV 存储里边,包含一些用户的维度。

    这些维度关联了之后,最终写入 Kafka 的 DWD 事实层,这里为了做性能的晋升,咱们做了二级缓存的操作。

  • 如图中上方,咱们读取 DWD 层的数据而后做根底汇总,外围是窗口维度聚合生成 4 种不同粒度的数据,别离是大盘多维汇总 topic、直播间多维汇总 topic、作者多维汇总 topic、用户多维汇总 topic,这些都是通用维度的数据。
  • 如图中下方,基于这些通用维度数据,咱们再去加工个性化维度的数据,也就是 ADS 层。拿到了这些数据之后会有维度扩大,包含内容扩大和经营维度的拓展,而后再去做聚合,比方会有电商实时 topic,机构服务实时 topic 和大 V 直播实时 topic。

    分成这样的两个链路会有一个益处:一个中央解决的是通用维度,另一个中央解决的是个性化的维度。通用维度保障的要求会比拟高一些,个性化维度则会做很多个性化的逻辑。如果这两个耦合在一起的话,会发现工作常常出问题,并且分不清楚哪个工作的职责是什么,构建不出这样的一个稳固层。

  • 如图中右方,最终咱们用到了三种不同的引擎。简略来说就是 Redis 查问用到了 C 端的场景,OLAP 查问用到了大屏、业务看板的场景。

四、将来布局

上文一共讲了三个场景,第一个场景是标准化 PU/UV 的计算,第二个场景是 DAU 整体的解决方案,第三个场景是经营侧如何解决。基于这些内容,咱们有一些将来布局,分为 4 个局部。

  • 第一局部是实时保障体系欠缺:

    • 一方面做一些大型的流动,包含春晚流动以及后续常态化的流动。针对这些流动如何去保障,咱们有一套标准去做平台化的建设;
    • 第二个是分级保障规范制订,哪些作业是什么样的保障级别 / 规范,会有一个标准化的阐明;
    • 第三个是引擎平台能力推动解决,包含 Flink 工作的一些引擎,在这下面咱们会有一个平台,基于这个平台去做标准、标准化的推动。
  • 第二局部是实时数仓内容构建:

    • 一方面是场景化计划的输入,比方针对流动会有一些通用化的计划,而不是每次流动都开发一套新的解决方案;
    • 另一方面是内容数据档次积淀,比方当初的数据内容建设,在厚度方面有一些场景的缺失,包含内容如何更好地服务于上游的场景。
  • 第三局部是 Flink SQL 场景化构建,包含 SQL 继续推广、SQL 工作稳定性和 SQL 工作资源利用率。咱们在预估资源的过程中,会思考比方在什么样 QPS 的场景下,SQL 用什么样的解决方案,能撑持到什么状况。Flink SQL 能够大幅缩小人效,然而在这个过程中,咱们想让业务操作更加简略。
  • 第四局部是批流一体摸索。实时数仓的场景其实就是做离线 ETL 计算减速,咱们会有很多小时级别的工作,针对这些工作,每次批处理的时候有一些逻辑能够放到流解决去解决,这对于离线数仓 SLA 体系的晋升非常微小。
退出移动版