基于Flink PipeLine模式的腾讯新闻实践
基于云计算俄刻阿诺斯和PipeLine的实时数据仓库构想
摘要 :随着社会消费模式以及经济形态的发展变化,将催生新的商业模式。腾讯新闻作为一款集游戏、教育、电商等一体的新闻资讯平台、服务亿万用户,业务应用多、数据量大。加之业务增长、场景更加复杂,业务对实时计算高可靠、可监控、低延时、数据可回溯的要求也越来越迫切。比如新闻广告投放、停单、在线推荐、电商搜索中,更快的响应用户需求、精准计费停单,意味着着更好的用户体验和更多的收入。
接下来,我们将介绍基于云计算平台俄刻阿诺斯Flink和PipeLine设计模式的实时数据仓库的思想。该方案已经落地实时广告停播、实时报道、实时特征计算、游戏联运行为分析、数据异常检测等场景内容的商业新闻。
一、设计背景
目前,商业数据主要承担腾讯新闻客户端、体育、新闻插件、创新等业务的收入、收集、处理、计算和分析广告数据。在数据报告的标准化、数据的准确性、数据的高质量、系统的高可用性、开发成本和效率等方面做了大量的工作。
随着腾讯新闻的商业业务增长,原本采用自建的Storm集群,导致运维成本高,扩展不方便,往往性能不足。再加上业务的实时性要求和逻辑复杂度的提升,Storm在开发灵活性、低时延和可扩展性等方面都难以满足现有的应用场景。
在此背景下,决定将原有的实时计算迁移到公司流计算俄刻阿诺斯Flink平台,重构代码,构建灵活通用的实时数据仓库,支持团队在多业务场景下的快速发展。
0-1构建新闻商业化的实时数据仓库面临以下挑战:
1、迁移复杂:,几乎没有代码重用,新系统与原数据的核对需要保证在线业务逻辑不变的情况下,新数据仓库的顺利切换;
腾讯新闻在2、需求多复杂:的商业数据只有几百亿/天的广告请求事件数据,需求方包括背景、搜索/推荐算法组和运营决策者等。这需要快速访问流媒体引擎来参与实时分析。
3、数据质量:业务的重要性决定了系统需要高可用性、稳定的数据质量、抗风险、灵活的代码重用和低耦合等。
4、数仓数据利用率:需要设计一个能够支持下游需求的中间仓储层。如果在下游构建一个新任务,它需要消耗一段与原始数据量相同的数据,导致计算资源消耗巨大。因此,对多个仓库的数据进行分级管理就显得尤为迫切。
二、调研技术选型
为了解决上述问题,我们在开发前对数据仓库的相关技术进行了调研和比较,并围绕Flink生态总结了近年来的生产和应用实践。
数据仓库架构对比:
在大数据处理中,有两种常见的数据仓库架构:Lambda架构和Kappa架构。如上表所示,lambda和Kappa在多维度上各有优劣。在架构的选择上,结合Lambda架构的灵活性、成熟度、迁移成本的优秀特性,以及腾讯新闻商业化数据的现有业务特点,选择了Lambda架构。
消息中间件对比:
Tube MQ和Hippo MQ为腾讯大数据平台(Tdbank)开发高吞吐量、高性能的分布式消息中间件。TubeMQ具有低数据延迟、高请求TPS、更好的外部服务能力和对客户端过滤消耗的支持。目前,Tdbank是公司的统一传输通道,所以这里我们选择TubeMQ作为访问/退出的消息队列组件。
实时计算引擎对比:
在选择实时计算引擎时,比较几种开放源代码。Spark Streaming使用微批处理来模拟实时处理,在低延迟、复杂的状态管理和流处理方面性能较差。暴风的各大公司都相继被淘汰。Flink是为流计算而生的,具有低延迟、状态管理和高灵活性的特点。我们决定使用Flink作为实时计算引擎。此外,依托公司流计算俄刻阿诺斯团队提供的Flink平台服务,可实现应用部署、集群管理等快速接入,提供稳定的运维服务。
在实时数据仓库建设过程中,计算引擎的选择极其重要,关系到后期能满足多少业务需求,实现哪些复杂功能。为了进一步了解Flink在行业内各大公司的应用情况,我们对电商做了研究:淘宝天猫、JD.COM、Shopee、Vipshop内容:字节跳动、腾讯、微博、网飞、小红书;短视频/直播:总结了Tik Tok、亚图快手、比莉的应用场景。
总结其实践的六大场景,即实时数据仓库、实时大屏、实时报表、实时监控、实时风险控制、在线学习。可见,Flink已经成为未来批量计算引擎的趋势。
三、商业化数据仓库整体业务架构
如第二章所述,我们面临许多问题和困难,需要
一套行之有效的数据组织、管理和处理方法来让我们的数据体系更加有序,使得下游接入使用成本最低、开发效率最高。下图是整个商业化数据仓库业务架构:
采集层使用大同、Boss 是数据采集上报服务,其中大同以成为集团数据治理力推的客户端上报平台,具备统一事件管理、统一参数规范上报,告别了以往上报需求散乱、上报不规范、数据难校验。当一个用户请求一个业务时,采集 SDK 会根据定义的上报规范将数据分发送到 Tube 供下游实时消费。
计算层提供实时和离线数仓两部分,离线数仓是基于 TDW、HDFS 建立的各个业务请求、曝光、点击等维度的数仓表,利用欧拉平台的数据分层、数据分类、数据血缘等能力完成数据资产的管理。实时数仓,正如第一章节所述设计的目的是解决需求多变、代码复用、系统高可用、海量数据低延时接入、数据高复用等问题,在 ODS 层(原始数据层)、DWD 层(数据明细层)、DWS 层(主题轻度数据汇总层)我们采用 TubeMQ 作为数据分发与缓存,TubeMQ 解决了海量数据的即时接入问题。
在数据利用率上我们采用:
1、不同业务差异大的需求开发申请新的 Tube 消费节点;
2、功能差异不大且数据源相同则通过 Flink 侧流方式复制流。
数据在各层由流式计算引擎进行业务清洗和转化的结果写回至消息队列中,供下游使用。对于 ODS 层的实时数据每隔1小时同步一份至 TDW 存储周期约3天,这份数据既能用于离线计算又能作为数据的备份链路异常时的问题排查和数据恢复。
存储层使用的组件比较丰富,有 Impala、Clickhouse 秒级响应多维 OLAP 数据分析查询的灯塔、人群投放系统,以及 MySQL 应用 OLTP 联机事务处理的应用场景。值得注意是 Flink 直接写 Redis 无法保障数据原子性,为此在写入 Redis 之前通过 Hash 对 key 分组、引入重试队列保障 Redis 读写稳定性。
监控、测试、管理模块,设计目的:
1、以往只能事后看日志定位问题,计算引擎代码运行异常存在监控盲区,引入一套自定义错误码和异常等级机制,一旦代码运行异常 StackTrace、错误码、异常位置等通过企业微信及时通知负责人;
2、任务参数分优先级管理,使得计算资源、系统参数等能够灵活配置,抽象模块代码复用性更强;
3、为了提高开发进度及时验证代码逻辑,巧妙搭建了一套抓取/解析 Tube 流数据字节码本地调试工具,使得本地调试代码逻辑与线上运行环境高度一致性。
总之,数仓的建设就是需要对 ODS 层数据进行 ETL,生成向 DWD 明细层(明细数据)及 DWS 服务层(主题轻度汇总数据)数据,DWD 及 DWS 两层数据也很好地解决了中间表的复用问题。接下来我们对解决方案、实时数仓详细设计进行介绍。
四、详细设计方案技术挑战介绍
众所周知实时数仓建设的难点在于如何设计一条高性能、高可用、低成本以及灵活度高的数仓链路。如下图所示为我们的实时数仓架构:
存储与接入层负责将客户端、后台、实时计算中间数据上报至消息中间件 TubeMQ。TubeMQ 一方面负责实时数据的存储,一方面承担数据分发给离线/在线处理平台的功能,同时构建数据源与数据处理系统之间的桥梁。其中 DWD 层的设计目的是减少下游频繁重复消费 ODS 层原始数据,对于新需求的开发,我们只需要申请 DWD 层的 TubeMQ 新消费节点即可,极大的节省计算资源。计算层主要负责数据的 ETL、维表关联、特征抽取等业务逻辑的计算。数据仓库存储采用 TDW、HDFS 和 Impala,ODS 层的原始数据默认保存在 HDFS 上,保存周期一般3天,目的是方便问题排查及数据备份回滚;DWD 和 DWS 层数据支持写入 TDW、HDFS 用于离线计算,同时支持写入 Impala 供应用层直接使用。
正如文章开篇所提,新闻商业化数据开发面临业务需求复杂、开发周期短,系统要求高可用、低延时等问题。提出的主要解决方案有以下几点:
- 采用 Pipeline 模式管道式编程,组件模块化封装;
- 任务及系统参数按优先级配置输入,使得代码与配置高度解耦;
- 在代码层面的监控我们自定义了一套错误码,利用 Try{}Catch{} 捕获代码异常,报警至企业微信群实现异常实时告警;
- 广播流方式实现配置数据动态更新,无需重启任务;
- 通过侧流等方式支持多种流计算模式: 单流、多流混合, 流复制,流切分分流;
- 利用 Hash 分组、异常队列重试、Batch 写入重试机制等保证数据原子性、数据存储不丢失;
接下来我们将一一介绍。
五、实时数仓之计算引擎 PipeLine 模式管道设计
PipeLine 为自定义管道流水线,可以将任务的处理分解为若干个处理阶段,即前一个处理单元的结果也是第二个模块的输入,实现计算作业流水线化。引入 PipeLine 设计模式思想可以充分利用 Flink 资源提高计算效率,使得代码结构层次更加清晰、代码解耦、模块高复用成为可能。
介绍项目中使用比较多的一个 PipeLine 模型。
从时序图可以看出,该 PipeLine 完整的执行流程:Conf-Init-Process-Sideout-Monitor-Sink,六步组成一个闭环;Conf 负责对任务参数按优先级解析;Init 初始化当前处理任务,完成 Flink 启动前环境准备流数据的接入;Process 为核心的功能处理接口,接收前一个处理阶段的输入流,并按业务逻辑完成计算将结果输入到下一个阶段;Sideout 基于 Flink 侧输出功能,可实现流的复制、筛选、过滤等操作;Monitor 为任务监控接口,开发时可选择实现;Sink 完成流的输出,如写入 Redis、Clickhouse、Tube 等。最后通过 pipeline.execute() 启动流的计算。
我们再来看该 PipeLine 类图,BaseProcedure 为全局接口,所有 PipeLine 流程上的类或接口都需要继承,BaseProcedure 完成两部分工作即 setConfig() 全局任务参数设置和 checkConfig() 在启动任务之前完成所有参数校验。这种设计的好处是参数全局化,避免参数配置错误或遗漏造成实时任务上线后异常。
结合管道示意图,执行流程可以拆封若干管道,每个管道为互相隔离的功能模块,管道与管道之间做了数据类型探测,支持“无缝连接”。我们通过侧流输出的方式实现流的复制,使得在一个计算任务中可以满足多个需求开发。另外对于复杂需求无法通过一个主处理逻辑一步实现,我们支持将主处理逻辑数据接入到用户自定制化处理逻辑模块进行处理。
Flink PipeLine 最大的价值在于为开发者统一了实时计算输入输出格式,使用者只需要关心 Process 中的逻辑即可。此外,PipeLine 将整个流计算步骤化,使得复杂任务添加、移除、替换模块变的非常轻松,而且本地调试只需要替换 Init、Sink 逻辑,确保了线上与线下代码 Process 中逻辑一致。
另外日常常用的功能我们也进行了封装,有基础的流数据读写、流的操作、监控告警、日期处理、文件处理等。
最后通过一个应用案例来感受下 PipeLine 编程模式,如何提高代码的可读性和复用性。左图代码功能包括:输入源相关参数的配置;参数全局化,获取输入数据源,流的复制,以及业务逻辑四个计算步骤。可以看到理解该伪代码功能非常依赖代码注释,如果需要新增一条复制流,则深入源码中进行修改,极容易动一发而牵全身引发线上事故。对比右图 PipeLIne 代码,可以发现,任务步骤清晰、模块解耦强、功能增删简单。
总结概括 Flink + PipeLine 模式有四个主要特点:
1、模块复用率极大提高,不同同学在使用项目代码时,无需关心代码中的逻辑,只需要知道模块输入输出是什么,完成了什么功能;
2、通过 PipeLine 模式将数据处理过程固化为若干步骤,使得编程灵活,代码可读性增强;
3、利用侧流技术极大的流的复用性,一个计算任务可以完成不同业务需求,无需重复申请新的消息中间件消费节点和新建 Flink 任务;
4、测试中只需要替换 PipeLine 的输入输出,即 Init 和 Sink 为本地测试模块。
六、高可用及稳定性设计
实时数仓设计最重要的是保证系统的高可用,一旦发生故障,即使是很短时间的中断,都会影响业务运营。
众所周知,业界在提高系统可靠性和稳定性常用方法比如有,冗余备份、流量熔断机制、容错机制、故障自动恢复、监控等。对于我们设计的系统,一方面依托流计算 Oceanus 平台提供的指标告警、指标监控以及 SLA 保障等强大能力。另一方在设计上通过捕获代码异常,分级告警;参数分层管理、参数广播动态更新;重试机制;以及高效的本地测试等方法提高系统可靠性。
6.1 代码异常捕获、分级告警
实时计算模块众多,会因为上游数据格式上报出错、代码 Bug、数据库连接异常等引起计算出错甚至造成任务中断,设计的系统必须具备监控上报和告警的能力。监控报警任务为独立任务,而各个业务的任务通过 Try{}Catch(Exception e){} 方式捕获 Task 中代码异常,将报警信息统一发送到同一个消息中间件,监控报警任务将接收的数据进行 Hash(level,project name,type) 编码,通过 TimeWindow、Aggregate 聚合使得相同错误的数据聚合在一起,减少报警疲劳。
另外我们将错误分为三个等级:ERROR(错误)、WARN(警告)、INFO(提示信息),并总结了49种常见的报警错误码,比如:数据库连接异常、流量抖动异常等。实践证明一旦系统出现问题,这种代码层的监控设计能够及时发现告警,从而缩短系统的故障时间,解决原 Strom 系统代码监控盲区。
6.2任务参数优先级管理
一个实时计算任务少则有几十个外部配置参数,有任务私有参数,有项目功能参数,也有涉密参数。为此我们定义了4层任务参数配置优先级:流计算 Oceanus平台配置七彩石各模块下的.properties base.properties。参数优先级管理给整个项目。这种设计总结有以下几点好处:
1、配置灵活度高;
2、代码与参数解耦;
3、保密性强;
6.3 参数配置动态更新
在使用 Flink 流式计算时,代码功能实现重要的同时,后期的可维护性一样很重要。任务中运行过程中,经常需要更新参数重启任务,比如实时计算过程中,源表突然增加一个字段。为此我们把配置信息广播流化,将生成广播状态流和数据流进行 Connect。广播流的是否需要发送通过定时任务检查配置版本有无变动。该方法减少了系统因频繁重启造成的数据延迟。
6.4高效的本地测试
本地测试通过根据消息主题,从线上获取真实的字节码数据,替换 Init 接口的输入源, Process 主逻辑无需为本地调试做任何改动,使得线上、测试代码和环境高度一致,本地打印输出,结果数据直观展示。极大的提高了开发效率,缩短了问题定位时间。
6.5 重试机制
数据与存储介质之间交互常常会由于连接、网络抖动等问题造成数据的读写失败,对于一些较为苛刻的场景,如交易数据分析、实时推荐特征、负反馈计算,需要数据读写零的丢失。为此我们为 Redis、Mysql 等写数据设计一套重试机制。
上游 Operator 传输的数据首先缓存在 Flink 分布式阻塞队列缓存池中,等待检查重试机制中的缓存 Queue 是否有待重试数据,我们的策略是优先输出 Queue 中数据,待所有数据重试完才操作写本次 Operator 发送来的数据。如果数据超过重试次数上限或者重试 Queue 容量上限将出发告警,本条数据将会丢弃。同时通过引入 Java8函数式编程方式完成自定义的输出函数,从而提高编码效率,以实现重试机制代码的高复用性。
最后以实时特征计算写 Redis 为例,展示重试机制的应用如何保障数据0丢失。该应用由四部分组成:各个业务输入数据源模块。Flink实时特征计算模块,各个业务单独实现数据解析和特征抽取 Flink 任务,通过重试机制模块写入同一个消息中间件;下游为同一个 Flink 特征构造任务主要完成 Protobuf 数据构造,利用业务标识字段区分接收消息中间中的混合业务特征数据,从而发到不同的 Redis 中。这个思想使用很多,比如 Mysql、Clickhouse、Http 等的 Sink。
七、总结展望
经过此次实时数仓改造及计算任务迁移,系统达到了 SLA 标准。利用 PipeLine 模式、流复制、参数分层管理等手段提升数据采集的可靠性和及时性,提高了代码数据质量,开发效率得到了极大提升,计算和存储资源得到充分利用。未来我们将基于流计算 Oceanus 平台强大能力在在线学习、搜索、人群画像等进行探索和应用。
流计算 Oceanus限量秒杀专享活动火爆进行中↓↓
关注“腾讯云大数据”公众号,技术交流、最新活动、服务专享一站Get~
内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/147927.html