乐趣区

关于Flink:腾讯看点基于-Flink-构建万亿数据量下的实时数仓及实时查询系统

本文由社区志愿者路培杰整顿,腾讯看点数据团队高级工程师王展雄在 Flink Forward Asia 2020 分享的议题《腾讯看点基于 Flink 构建万亿数据量下的实时数仓及实时查问零碎》。内容包含:

  1. 背景介绍
  2. 架构设计
  3. 实时数仓
  4. 实时数据查问零碎
  5. 实时零碎利用成绩总结

一、背景介绍

1. 须要解决的业务痛点

举荐零碎

对于举荐同学来说,想晓得一个举荐策略在不同人群中的举荐成果是怎么样的。

经营

对于经营的同学来说,想晓得在广东省的用户中,最火的广东地区内容是哪些?不便做地区 push。

审核

对于审核的同学,想晓得过来 5 分钟游戏类被举报最多的内容和账号是哪些,不便可能及时处理。

内容创作

对于内容的作者,想晓得明天到目前为止,内容被多少个用户观看,收到了多少个点赞和转发,不便可能及时调整他的策略。

老板决策

对于老板来说,想晓得过来 10 分钟有多少用户生产了内容,对生产人群有一个宏观的理解。

以上这几点都是咱们日常工作中常常遇到的业务场景,前面的篇幅中会给出对应的解决方案。

2. 开发前调研

在进行开发之前咱们做了如下这些调研。

2.1 离线数据分析平台是否满足这些需要

调研的论断是不能满足离线数据分析平台,不行的起因如下:

  • 首先用户的消费行为数据上报须要通过 Spark 的多层离线计算,最终后果出库到 MySQL 或者 ES 提供给离线剖析平台查问。这个过程的延时至多是 3-6 个小时,目前比拟常见的都是提供隔天的查问,所以很多实时性要求高的业务场景都不能满足。
  • 另一个问题是腾讯看点的数据量太大,带来的不稳定性也比拟大,常常会有预料不到的提早,所以离线剖析平台是无奈满足这些需要的。

2.2 准实时数据分析平台

在腾讯外部提供了准实时数据查问的性能,底层技术用的是 Kudu + Impala,Impala 尽管是 MPP 架构的大数据计算引擎,并且拜访以列式存储数据的 Kudu。然而对于实时数据的剖析场景来说,它的查问响应速度和数据的提早都还是比拟高的。比如说查问一次实时的 DAU 返回后果的耗时至多是几分钟,无奈提供良好的交互式的用户体验。

所以 Kudu+Impala 这种通用的大数据处理框架的速度劣势,更多的是相比 Spark 加 HDFS 这种离线剖析框架来说的,对于咱们实时性要求更高的场景是无奈满足的。因而须要进行开发,这就波及到了计划选型和架构设计。

3. 腾讯看点信息流的业务流程

在大家介绍一下腾讯看点信息流的业务流程,理解了业务的流程,就可能更好的了解技术架构的计划。

  • 第 1 步,内容创作者公布内容;
  • 第 2 步,内容会通过内容审核零碎启用或者下架;
  • 第 3 步,启用的内容给到举荐零碎和经营零碎,分发给 C 侧用户;
  • 第 4 步,内容分发给 C 侧用户之后,用户会产生各种行为,比如说曝光、点击举报等,这些行为数据通过埋点上报,实时接入到音讯队列中;
  • 第 5 步,构建实时数据仓库;
  • 第 6 步,构建实时数据查问零碎。

咱们做的工作次要就在第 5 步和第 6 步,能够看一下咱们的业务流程图来进一步的理解。

在业务流程图中,咱们次要做的两局部工作,就是图中有色彩的这两局部:

  • 橙色局部,咱们构建了一个腾讯看点的实时数据仓库;
  • 绿色局部,咱们基于了 OLAP 的存储计算引擎,开发了实时数据分析系统。

为什么要构建实时数据仓库?因为原始的数据上报数据量十分大,一天上报的峰值就有上万亿条,而且上报的格局十分凌乱,不足了内容的维度、信息用户的画像信息,上游就基本没有方法间接应用。

而咱们提供的实时数据仓库,是依据腾讯看点信息流的业务场景,进行了内容维度的关联,用户画像的关联和各种粒度的聚合,上游能够十分不便的应用实时数据,而且实时数据仓库能够提供给上游的用户重复的生产应用,能够大量的缩小反复的工作。

绿色局部的多维实时数据分析系统,生产了咱们提供的实时数据仓库,利用了 OLAP 存储计算引擎,将海量的数据进行高效的存储,再提供高性能的多维实时剖析性能。

二、架构设计

1. 设计的指标与难点

首先来看一下数据分析系统的设计指标与难点。咱们的实时数据分析系统分为四大模块:

  • 实时计算引擎;
  • 实时存储引擎;
  • 后盾服务层;
  • 前端展现层。

难点次要在于前两个模块,实时计算引擎和实时存储引擎。

  • 千万级每秒的海量数据如何实时的接入,并且进行极低提早的维表关联是有难度的;
  • 实时存储引擎如何反对高并发的写入。高可用分布式和高性能的索引查问是比拟难的,能够看一下咱们的零碎架构设计来理解这几个模块的具体实现。

2. 零碎架构设计

对于零碎架构的设计,次要从以下几方面来讲。

2.1 实时计算

  • 接入层次要是从千万级每秒的原始音讯队列中拆分出不同业务不同行为数据的微队列。拿 QQ 看点的视频内容来说,拆分过后的数据就只有百万级每秒了。
  • 实时计算层次要是负责多行行为流水数据进行 “ 行转列 ” 的操作,实时关联用户画像数据和内容维度数据。
  • 实时数仓存储层次要就是设计出合乎看点的业务,上游好用的实时音讯队列。

咱们临时提供了两个音讯队列,作为实时数仓的两层:

  • 第一层是 DWM 层,它是内容 ID 和用户 ID 粒度聚合的,就是说一条数据蕴含了内容 ID 和用户 ID,而后还有 B 侧的内容维度数据,C 侧的用户行为数据,还有用户画像数据。
  • 第二层是 DWS 层,这一层是内容 ID 粒度聚合的,就是一条数据蕴含了内容 ID、B 侧数据和 C 侧数据。能够看到内容 ID 和用户 ID 粒度的音讯,队列流量进一步减小到了 10 万级每秒,内容 ID 粒度更是减小到了万级每秒,并且格局更加清晰,维度信息更加丰盛。

2.2 实时存储

  • 实时写入层次要是负责 Hash 路由,将数据写入;
  • OLAP 存储层是利用 MPP 的存储引擎,设计出合乎业务的索引和物化视图,高效存储海量数据;
  • 后盾接口层是提供了高效的多维实时查问接口。

2.3 后盾服务

后盾服务是基于腾讯自研的 RPC 后盾服务框架写的,并且会进行一些二级缓存。

2.4 前端服务

前端采纳的是开源组件 Ant Design,利用了 Nginx,反向代理了浏览器的申请到后盾服务器上。

3. 计划选型

对于架构设计的计划选型,咱们比照了业内的当先计划,最终抉择了最合乎咱们业务场景的计划。

3.1 实时数仓的选型

咱们抉择的是业内比拟成熟的 Lambda 架构,它的长处是成熟度高,灵活性高,迁徙成本低等等。然而它有一个毛病,实时和离线用了两套代码,可能会存在一个口径批改了数据,但另一个没有批改从而造成数据不统一的问题。咱们的解决方案每天都有做数据对账的工作,如果有异样会进行告警。

3.2 实时计算引擎的选型

咱们抉择了 Flink 作为实时计算引擎,是因为 Flink 在设计之初就是为了流解决来设计的,Sparks Streaming 严格来说还是微批处理,storm 当初用的曾经不是很多了。并且,Flink 还有 exactly-once 的准确性,轻量级的容错机制,低提早高吞吐,应用性高的特点,所以咱们抉择了 Flink 作为实时计算引擎。

3.3 实时存储引擎

咱们的要求是须要有维度索引,反对高并发的写入和高性能的多维实时 OLAP 查问。能够看到 HBase,TiDB 和 ES 都不能满足要求。Druid 有一个缺点,它是依照时序划分 Segment,也就阐明无奈将同一个内容全副寄存在同一个 Segment 上,所以在计算全局的 Top N 的时候就只可能计算近似值。于是咱们抉择了最近两年大火的 MPP 数据库引擎 Clickhouse,前面我会联合咱们的具体应用场景和 Clickhouse 的内核原理,介绍一下 Clickhouse 的劣势。

三、实时数仓

实时数仓也分为三块来介绍:

  • 第一是如何构建实时数仓;
  • 第二是实时数仓的长处;
  • 第三是基于实时数仓,利用 Flink 开发实时利用时候遇到的一些问题。

实时数仓这一部分的难度在于它处于一个比拟新的畛域,并且各个公司各个业务的差距都比拟大,怎么样可能设计出不便好用,合乎看点信息流业务场景的实时数仓是有难度的。

1. 如何构建实时数仓

先看一下实时数仓要做什么。实时数仓对外来说就是几个音讯队列,不同的音讯队列外面寄存的是不同聚合粒度的实时数据,包含了内容 ID、用户 ID、C 侧用户行为数据,B 侧内容维度数据和用户画像数据等。搭建实时数仓能够分为三步。

1.1 数据荡涤

首先从海量的原始音讯队列中进行简单的数据荡涤操作,能够取得格局清晰的实时数据。它的具体操作其实就是在 Flink 的实时计算环节,先依照一分钟的粒度进行了窗口的聚合,在窗口内本来多行的行为数据被转成了一行多列的数据格式。

1.2 高性能维表关联

第二步是进行高性能的实时维表关联,补充用户画像数据和内容维度数据等。然而海量的用户画像数据是存在于 HDFS 上的,内容维度数据又是存在于 HBase 上的,所以想要极低提早的维表关联是有技术挑战的。这一块在后文会独自介绍。

1.3 不同粒度聚合

第三步是将算好的实时数据依照不同的粒度进行聚合,而后放到对应的音讯队列中进行保留,能够提供给上游多用户复用,到这里实时数仓就搭建实现了。

接下来具体介绍一下第二步中高性能实时维表关联是怎么解决的。

几十亿的用户画像数据寄存在 HDFS 上,必定是无奈进行高性能的维表关联的,所以须要进行缓存。因为数据量太大,本地缓存的代价不合理,咱们采纳的是 Redis 进行缓存,具体实现是通过 Spark 批量读取 HDFS 上的画像数据,每天更新 Redis 缓存,内容维度数据寄存在 HBase 中。

为了不影响线上的业务,咱们拜访的是 HBase 的备库,而且因为内容维度变动的频率远高于用户画像,所以维度关联的时候,咱们须要尽量的关联到实时的 HBase 数据。

一分钟窗口的数据,如果间接关联 HBase 的话,耗时是十几分钟,这样会导致工作提早。咱们发现 1000 条数据拜访 HBase 是秒级的,而拜访 Redis 的话只是毫秒级的,拜访 Redis 的速度基本上是拜访 HBase 的 1000 倍,所以咱们在拜访 HBase 的内容之前设置了一层 Redis 缓存,而后通过了监听 HBase-proxy 写流水,通过这样来保障缓存的一致性。

这样一分钟的窗口数据,本来关联内容维度数据耗时须要十几分钟,当初就变成了秒级。咱们为了避免过期的数据节约缓存,缓存的过期工夫咱们设置成了 24 个小时。

最初还有一些小的优化,比如说内容数据上报过程中会上报不少非常规的内容 ID,这些内容 ID 在 HBase 中是不存储的,会造成缓存穿透的问题。所以在实时计算的时候,咱们间接过滤掉这些内容 ID,避免缓存穿透,又缩小了一些工夫。另外,因为设置了定时缓存,会引入一个缓存雪崩的问题,所以咱们在实时计算的过程中进行了削峰填谷的操作,错开了设置缓存的工夫,来缓解缓存雪崩的问题。

2. 实时数仓的长处

咱们能够看一下,在咱们建设实时数仓的前后,开发一个实时利用的区别。

没有数仓的时候,咱们须要生产千万级每秒的原始队列,进行简单的数据荡涤,而后再进行用户画像关联、内容维度关联,才可能拿到符合要求格局的实时数据。开发和扩大的老本都会比拟高。如果想开发一个新的利用,又要走一遍流程。当初有了实时数仓之后,如果再想开发一个内容 ID 粒度的实时利用,就间接申请 TPS 万级每秒的 DWS 层音讯对列即可,开发成本变低很多,资源耗费小了很多,可扩展性也强了很多。

咱们看一个理论的例子,开发咱们零碎的实时数据大屏,本来须要进行如上的所有操作才可能拿到数据,当初只须要生产 DWS 层音讯队列写一条 Flink SQL 即可,仅仅会耗费 2 个 CPU 外围和 1GB 的内存。以 50 个消费者为例,建设实时数仓的前后,上游开发一个实时利用,能够缩小 98% 的资源耗费,包含了计算资源、存储资源、人力老本和开发人员的学习接入老本等等,并且随着消费者越多节俭的就越多,就拿 Redis 存储这一部分来说,一个月就可能省下上百万的人民币。

3. Flink 开发过程中遇到的问题总结

在利用 Flink 开发实时利用的过程中遇到过不少问题,这里抉择几个比拟有代表性的给大家分享一下。

3.1 实时数据大屏

第一个是开发实时数据大屏的时候,开始是通过 Flink SQL 来实现的,性能非常简单,就是计算当天截止到以后累计的点击数,实现的形式也非常简单,输出的 source table 是实时数据仓库的音讯队列。输入的 sink table 就是 Redis。SQL 就是:select sum(click) from sourceTable Group by day time。

这个工作看起来是没有问题的,然而理论跑起来数据却无奈实时更新,是因为 source table 每达到一条点击数据,累计值都会加一,而后就会往 Redis 中写一条最新的数据。所以当数据量太大的时候,它就会频繁的写 Redis,所以这样就会导致写 Redis 的网络提早会显得十分高,从而会导致背压数据无奈实时更新。

咱们做了一个简略的优化,用 table API 执行完 SQL 之后,转化成 DataStream,而后通过一个一秒钟的数据窗口,每秒钟仅仅会输入最新的累计值到 Redis 中,这样的数据就能够实时更新了。

3.2 Flink state 的 TTL

Flink 的 1.6 版本开始引入了 state TTL,开启了 state TTL 之后,Flink 就会为每一个 keyed state 减少一个工夫戳字段,通过工夫戳字段就能够判断 state 是不是过期,是否须要进行清理。然而如果仅仅从字面意思上了解就会遇到一些问题,在 1.10 版本之前,尽管开启了 state TTL,然而 Flink 默认是不会主动清理过期的 state 的。所以如果是 heap memory backend,就会导致 OOM 的问题;如果是 rocksDB backend,就会导致 state 的状态越来越大,最终会导致重启的时候消耗的工夫过长。前面通过调研,咱们发现有两种形式能够清理 Flink 的过期的 state。

第一种是手动清理,第二种的话是主动清理。咱们最终抉择的是以手动触发的形式来清理过期的 state。每天在深夜,也就是业务低谷期的时候,咱们会对 state 中的数据进行遍历的拜访,拜访到过期的数据,就会进行清理。

为什么咱们没有抉择 Flink 的主动清理策略,是因为 Flink 在 1.8 版本之前,只有一种主动清理策略,clean up in full snapshot。这种清理策略从名字上来看就晓得他是在做全量 snapshot 的时候会进行清理,然而有一个致命的缺点,它并不会缩小自身 state 的大小,而是仅仅把清理过后的 state 做到 snapshot 外面,最终还是会 OOM。并且,它重启之后才可能加载到之前清理过的 state,会导致它频繁的重启。

尽管在 1.8 版本之后,减少了两种主动清理的策略,然而因为它是异步清理,所以他的清理机会和应用形式都不如手动清理那么灵便,所以最终咱们还是抉择了手动触发的形式进行清理。在 1.10 版本之后,默认是抉择了主动清理的策略,然而这就要求用户对主动清理策略的机会和策略 有比拟好的理解,这样才可能更好的满足业务的需要。

3.3 应用 Flink valueState 和 mapState 经验总结

尽管通过 valueState 也能够存储 map 构造的数据,然而可能应用 mapState 的中央尽量应用 mapState,最好不要通过 valueState 来存储 map 构造的数据,因为 Flink 对 mapState 是进行了优化的,效率会比 valuState 中存储 map 构造的数据更加高效。

比方咱们遇到过的一个问题就是应用 valueState 存储了 map 构造的数据,抉择的是 rocksDB backend。咱们发现磁盘的 IO 变得越来越高,提早也相应的减少。前面发现是因为 valueState 中批改 map 中的任意一个 key 都会把整个 map 的数据给读出来,而后再写回去,这样会导致 IO 过高。然而 mapState,它每一个 key 在 rocksDB 中都是一条独自的 key,磁盘 IO 的代价就会小很多。

3.4 Checkpoint 超时问题

咱们还遇到过一些问题,比如说 Checkpoint 超时了,过后咱们第一个想法就是计算资源有余,并行度不够导致的超时,所以咱们间接减少了计算资源,增大了并行度,然而超时的状况并没有失去缓解。前面通过钻研才发现是数据歪斜,导致某个节点的 barrier 下发不及时导致的,通过 rebalance 之后才可能解决。

总的来说 Flink 性能还是很强的,它文档比较完善,网上材料十分丰盛,社区也很沉闷,个别遇到问题都可能比拟快的找到解决方案。

四、实时数据查问零碎

咱们的实时查问零碎,多维实时查问零碎用的是 Clickhouse 来实现的,这块分为三个局部来介绍。第一是分布式高可用,第二是海量数据的写入,第三是高性能的查问。

Click house 有很多表引擎,表引擎决定了数据以什么形式存储,以什么形式加载,以及数据表领有什么样的个性?目前 Clickhouse 领有 merge tree、replaceingMerge Tree、AggregatingMergeTree、外存、内存、IO 等 20 多种表引擎,其中最体现 Clickhouse 性能特点的是 merge tree 及其家族表引擎,并且以后 Clickhouse 也只有 merge 及其家族表引擎反对了主键索引、数据分区、数据正本等优良的个性。咱们以后应用的也是 Clickhouse 的 merge tree 及其家族表引擎,接下来的介绍都是基于引擎开展的。

1. 分布式高可用

先看分布式高可用,不论单节点的性能多强,随着业务的增长,早晚都会有遇到瓶颈的一天,而且意外的宕机在计算机的运行中是无奈防止的。Clickhouse 通过分片来程度扩大集群,将总的数据程度分成 m 分,而后每个分片中保留一份数据,避开了单节点的性能瓶颈,而后通过正本即每个分片领有若干个数据一样的副原本保障集群的高可用。

再看看 Clickhouse 默认的高可用计划,数据写入是通过分布式表写入,而后分布式表会将数据同时写入到同一个分片的所有正本外面。这里会有一个问题,如果正本 0 写入胜利,正本 1 写入失败,那么就会造成同一个分片的不同正本数据不统一的问题,所以默认的高可用计划是不可能用于生产环境的。

咱们这里听取的是 Clickhouse 官网的倡议,借助了 Zookeeper 实现高可用的计划,数据写入一个分片的时候,仅仅写入一个正本,而后再写 Zookeeper,通过 Zookeeper 通知同一个分片的其余正本,再过去拉取数据,保证数据的一致性。

接下来看一下 Clickhouse 实现这种高可用计划的底层原理,这种高可用的计划须要通过 Clickhouse 的 replicated merge tree 表引擎来实现,其中在 replicated merge tree 表引擎的外围代码中,有大量跟 Zookeeper 进行交互的逻辑,从而实现了多个正本的协同,包含主正本的选举写入工作队列的变更和正本状态的变动等等。能够看到内部数据写入 Clickhouse 的一个分片,会先写入一个正本的内存中,在内存中依照指定的条件排好序,再写入磁盘的一个长期目录。最初将长期目录重命名为最终目录的名字,写完之后通过 Zookeeper 进行一系列的交互,实现数据的复制。

这里没有选用音讯队列进行数据的同步,是因为 Zookeeper 更加轻量级,而且写的时候任意写一个正本,其余的正本都可能通过读 Zookeeper 取得一致性的数据,而且就算其余节点第一次来获取数据失败了,前面只有发现它跟 Zookeeper 上的数据记录不统一,就会再次尝试获取数据,保证数据的一致性。

2. 海量数据的写入

2.1 Append + Merge

数据写入遇到的第一个问题是海量数据间接写 Clickhouse 是会失败的。Clickhouse 的 merge tree 家族表引擎的底层原理相似于 LSM tree,数据是通过 append 的形式写入,后续再启动 merge 线程,将小的数据文件进行合并。理解了 Clickhouse merge tree 家族表引擎的写入过程,咱们就会发现以下两个问题。

  • 如果一次写入的数据太少,比方一条数据只写一次,就会产生大量的文件目录。当后盾合并线程来不及合并的时候,文件目录的数量就会越来越多,这会导致 Clickhouse 抛出 too many parts 的异样,写入失败。
  • 另外,之前介绍的每一次写入除了数据自身,Clickhouse 还会须要跟 Zookeeper 进行 10 来次的数据交互,而咱们晓得 Zookeeper 自身是不可能接受很高的并发的,所以能够看到写入 Clickhouse QPS 过高,导致 zookeeper 的解体。

咱们采纳的解决方案是改用 batch 的形式写入,写入 zookeeper 一个 batch 的数据,产生一个数据目录,而后再与 Zookeeper 进行一次数据交互。那么 batch 设置多大?如果 batch 太小的话,就缓解不了 Zookeeper 的压力;然而 batch 也不能设置的太大,要不然上游的内存压力以及数据的提早都会比拟大。所以通过试验,最终咱们抉择了大小几十万的 batch,这样能够防止了 QPS 太高带来的问题。

其实以后的计划还是有优化空间的,比如说 Zookeeper 无奈线性扩大,我有理解到业内有些团队就把 Mark 和 date part 相干的信息不写入 Zookeeper。这样可能缩小 Zookeeper 的压力。不过这样波及到了对源代码的批改,对于个别的业务团队来说,实现的老本就会比拟高。

2.2 分布式表写入

如果数据写入通过分布式表写入会遇到单点的磁盘问题,先介绍一下分布式表,分布式表实际上是一张逻辑表,它自身并不存储实在的数据,能够了解为一张代理表,比方用户查问分布式表,分布式表会将查问申请下发到每一个分片的本地表上进行查问,而后再收集每一个本地表的查问后果,汇总之后再返回给用户。那么用户写入分布式表的场景,是用户将一个大的 batch 的数据写入分布式表,而后分布式示意依照肯定的规定,将大的 batch 的数据划分为若干个 mini batch 的数据,存储到不同的分片上。

这里有一个很容易误会的中央,咱们最开始也是认为分布式表只是依照肯定的规定做一个网络的转发,认为万兆网卡的带宽就足够,不会呈现单点的性能瓶颈。然而实际上 Clickhouse 是这样做的,咱们看一个例子,有三个分片 shard1,shard2 和 shard3,其中分布式表建设在 shard2 的节点上。

  • 第一步,咱们给分布式表写入 300 条数据,分布式表会依据路由规定把数据进行分组,假如 shard1 分到 50 条,shard2 分到 150 条,shard3 分到 100 条。
  • 第二步,因为分布式表跟 shard2 是在同一台机器上,所以 shard2 的 150 条就间接写入磁盘了。而后 shard1 的 50 条和 shard3 的 100 条,并不是间接转发给他们的,而是也会在分布式表的机器上先写入磁盘的长期目录。
  • 第三步,分布式表节点 shard2 会向 shard1 节点和 shard3 节点别离发动近程连贯的申请,将对应长期目录的数据发送给 shard1 和 shard3。

这里能够看到分布式表所在的节点 shard2 全量数据都会先落在磁盘上,咱们晓得磁盘的读写速度都是不够快的,很容易就会呈现单点的磁盘性能瓶颈。比方单 QQ 看点的视频内容,每天可能写入百亿级的数据,如果写一张分布式表,很容易就会造成单台机器呈现磁盘的瓶颈,尤其是 Clickhouse 的底层使用的是 merge tree,它在合并的过程中会存在写放大的问题,这样会减轻磁盘的压力。

咱们做的两个优化计划:

  • 第一个就是对磁盘做了 RAID 晋升了磁盘的 IO;
  • 第二就是在写入之前,上游进行了数据的划分分表操作,间接离开写入到不同的分片上,磁盘的压力间接变为了原来的 n 分之一,这样就很好的防止了磁盘的单点的瓶颈。

2.3 部分 Top 并非全局 Top

尽管咱们的写入是依照分片进行了划分,然而这里引入了一个分布式系统常见的问题,就是部分的 Top 并非全局 Top。比如说同一个内容 x 的数据落在了不同的分片上,计算全局 Top100 点击内容的时候,之前说到分布式表会将查问申请下发到各个分片上,计算部分的 Top100 点击的内容,而后将后果进行汇总。

举个例子,内容 x 在分片一和分片二上不是 Top100,所以在汇总数据的时候就会失落掉分片一和分片二上的内容 x 的点击数据。

第二是会造成数据谬误,咱们做的优化就是在写入之前加上了一层路由,咱们将同一个内容 ID 的数据全副路由到了同一个分片上,解决了该问题。这里须要多说一下,当初最新版的 Clickhouse 都是不存在这样这个问题的,对于有 group by 和 limit 的 SQL 命令,只把 group by 语句下发到本地表进行执行,而后各个本地表执行完的全量后果都会传到分布式表,在分布式表再进行一次全局的 group by,最初再做 limit 的操作。

这样尽管可能保障全局 top N 的正确性,但代价就是就义了一部分的执行性能。如果想要复原到更高的执行性能,咱们能够通过 Clickhouse 提供的 distributed_group_by_no_merge 参数来抉择执行的形式。而后再将同一个内容 ID 的记录全副路由到同一个分片上,这样在本地表也可能执行 limit 操作。

3. 高性能的存储和查问

Clickhouse 高性能查问的一个关键点,就是稠密索引。稠密索引这个设计很有考究,设计的好能够减速查问,设计的不好反而会影响查问效率。因为咱们的查问大部分都是工夫和内容 ID 相干的,比如说某个内容过来 n 分钟在各个人群的体现如何,我依照日期分钟粒度工夫和内容 ID 建设了稠密索引,针对某个内容的查问,建设稠密索引之后,能够缩小 99% 的文件扫描。

Clickhouse 高性能查问的第二点,就是咱们当初的数据量太大,维度太多,拿 QQ 看点的视频内容来说,一天入库的流水就有上百亿条,有些维度有几百个类别,如果一次性把所有的维度进行预聚合查问反而会变慢,并且索引会占用大量的存储空间。咱们的优化就是针对不同的维度建设对应的预聚合和物化视图,用空间换工夫,这样能够缩短查问的工夫。

举个例子,通过 summary merge tree 建设一个内容 ID 粒度聚合的累积,累加 pv 的物化视图,这样相当于提前进行了 group by 的计算,等真正须要查问聚合后果的时候,就间接查问物化视图,数据都是曾经聚合计算过的,且数据的扫描量只是原始流水的千分之一。

分布式表查问还会有一个问题,就是查问单个内容 ID 的时候,分布式表会将查问申请下发到所有的分片上,而后再返回给查问后果进行汇总。实际上因为做过路由,一个内容 ID 只存在于一个分片上,剩下的分片其实都是在空跑。针对这类的查问,咱们的优化就是后盾依照同样的规定先进行路由,而后再查问指标分片,这样缩小了 n 分之 n -1 的负载,能够大量的缩短查问工夫。而且因为咱们提供的是 OLAP 的查问,数据满足最终的一致性即可。所以通过主从正本的读写拆散,也能够进一步的晋升性能。咱们在后盾还做了一个一分钟的数据缓存,这样针对雷同条件的查问,后盾就能够间接返回。

4. Clickhouse 扩容计划

咱们调研了业内一些常见的计划:

  • 比如说 HBase 原始数据是寄存在 HDFS 上的,扩容只是 region server 的扩容,并不波及到原始数据的迁徙。
  • 然而 Clickhouse 的每个分片数据都是在本地,更像是 RocksDB 的底层存储引擎,不能像 HBase 那样不便的扩容。
  • 而后是 Redis,Redis 是 Hash 槽这一种,相似于一致性 Hash 的形式,是比拟经典的分布式缓存计划。

Redis slot 在 Hash 的过程中,尽管会存在短暂的 ASK 不可用,然而总体上来说迁徙还是比拟不便的。就从原来的 h0 迁徙迁徙到 h1,最初再删除 h0,然而 Clickhouse 大部分都是 OLAP 的批量查问,而且因为列式存储不反对删除的个性,一致性 hash 的计划也不是很适合。

咱们目前的扩容计划就是从实时数仓另外生产一份数据写入新的 Clickhouse 集群,两个集群一起跑一段时间,因为实时数据咱们当初就保留了三天,等三天之后,后盾服务就间接拜访新的 Clickhouse 集群。

五、实时零碎利用成绩总结

咱们输入了腾讯看点的实时数据仓库,DWM 层和 DWS 层两个音讯队列,上线了腾讯看点的实时数据分析系统,该零碎可能亚秒级的响应多维条件查问申请。在未命中缓存的状况下:

  • 过来 30 分钟的内容查问,99% 的申请耗时在一秒内;
  • 过来 24 小时的内容查问 90% 的申请耗时在 5 秒内,99% 的申请耗时在 10 秒内。


更多 Flink 相干技术问题,可扫码退出社区钉钉交换群;

第一工夫获取最新技术文章和社区动静,请关注公众号~

退出移动版