DataPipeline
Data Pipeline | 实时数据集成平台
传统的数据融合通常基于批模式。在批的模式下,我们会通过一些周期性运行的 ETL JOB,将数据从关系型数据库、文件存储向下游的目标数据库进行同步,中间可能有各种类型的转换。
另一种是 Data Pipeline 模式。与批模式相比相比,其最核心的区别是将批量变为实时:输入的数据不再是周期性的去获取,而是源源不断的来自于数据库的日志、消息队列的消息。进而通过一个实时计算引擎,进行各种聚合运算,产生输出结果,并且写入下游。现代的一些处理框架,包括 Flink、Kafka Streams、Spark,或多或少都能够支持批和流两种概念。换言之,流式处理能力是实时数据集成平台必要的组件;结合企业技术栈特点,选用包括 Flink、Spark Streaming、Kafka Streams 等流行的引擎在多数情况下都能够满足要求。端到端数据的 EOS 是数据集成中的一个难题,需要用户根据业务实际需求、数据本身的特性、目的地特点 case by case 去解决。
系统挑战
如果问题简化到一张 MySQL 的表,里面只有几百万行数据,你可能想将其同步到一张 Hive 表中。基于这种情况,大部分问题都不会遇到。因为结构是确定的,数据量很小,且没有所谓的并行化问题。但在一个实际的企业场景下,如果做一个数据融合系统,就不可避免要面临几方面的挑战:
-
动态性: 数据源会不断地发生变化,主要归因于:表结构的变化,表的增减。针对这些情况,你需要有一些相应的策略进行处理。
-
可伸缩性: 任何一个分布式系统,必须要提供可伸缩性。因为你不是只同步一张表,通常会有大量数据同步任务在进行着。如何在一个集群或多个集群中进行统一的调度,保证任务并行执行的效率,这是一个要解决的基本问题。
-
容错性: 在任何环境里你都不能假定服务器是永远在正常运行的,网络、磁盘、内存都有可能发生故障。这种情况下一个 Job 可能会失败,之后如何进行恢复?状态能否延续?是否会产生数据的丢失和重复?这都是要考虑的问题。
-
异构性: 当我们做一个数据融合项目时,由于源和目的地是不一样的,比如,源是 MySQL,目的地是 Oracle,可能它们对于一个字段类型定义的标准是有差别的。在同步时,如果忽略这些差异,就会造成一系列的问题。
-
一致性: 一致性是数据融合中最基本的问题,即使不考虑数据同步的速度,也要保证数据一致。数据一致性的底线为:数据先不丢,如果丢了一部分,通常会导致业务无法使用;在此基础上更好的情况是:源和目的地的数据要完全一致,即所谓的端到端一致性,如何做到呢?
Lambda 架构
Lambda 架构的核心是按需使用批量和流式的处理框架,分别针对批式和流式数据提供相应的处理逻辑。最终通过一个服务层进行对外服务的输出。与之相对,还有一种架构叫 Kappa 架构,即用一个流式处理引擎解决所有问题。我们认为 Lambda 架构是批流一体化的必然要求。
实际上,这在很大程度来自于现实中用户的需求。DataPipeline 在刚刚成立时只有一种模式,只支持实时流同步,在我们看来这是未来的一种趋势。但后来发现,很多客户实际上有批量同步的需求。比如,银行在每天晚上可能会有一些月结、日结,证券公司也有类似的结算服务。基于一些历史原因,或出于对性能、数据库配置的考虑,可能有的数据库本身不能开 change log。所以实际上并不是所有情况下都能从源端获取实时的流数据。考虑到上述问题,我们认为一个产品在支撑数据融合过程中,必须能同时支撑批量和流式两种处理模式,且在产品里面出于性能和稳定性考虑提供不同的处理策略,这才是一个相对来说比较合理的基础架构。
数据融合
数据源变化捕获是数据集成的起点,结合日志的解析、增量条件查询模式和数据源主动 Push 模式,最终构建出一个数据汇集层。在这个阶段,推荐考虑 Kafka Connect 这类面向数据集成的专有框架,可以有效缩短研发周期和成本。数据汇集层建议构建在消息队列之上,为后继的加工处理提供便利。如果需要全量持久化长期保存,建议结合使用消息队列和分布式文件系统分别做实时数据和全量数据的存储。
Ad-Hoc 模式
假如我需要将数据从 MySQL 同步到 Hive,可以直接建立一个 ETL 的 JOB(例如基于 Flink),其中封装所有的处理逻辑,包括从源端读取数据,然后进行变换写入目的地。在将代码编译好以后,就可以放到 Flink 集群上运行,得到想要的结果。这个集群环境可以提供所需要的基础能力,刚才提到的包括分布式,容错等。
ETL Job 封装所有的处理逻辑,从源端读取,注入数据,将结果写入到目的地,并且完成有状态,无状态的转换。批流处理框架提供了可重用的源与目的地连接器,Operator 与 DAG,以及分布式的环境与容错。
MQ 模式
另一种模式是 ETL JOB 本身输入输出实际上都是面对消息队列的,实际上这是现在最常使用的一种模式。在这种模式下,需要通过一些独立的数据源和目的地连接器,来完成数据到消息队列的输入和输出。ETL JOB 可以用多种框架实现,包括 Flink、Kafka Streams 等,ETL JOB 只和消息队列发生数据交换。。DataPipeline 选择 MQ 模式,主要有几点考虑:
- 要做数据的一对多分发。数据要进行一次读取,然后分发到各种不同的目的地,这是一个非常适合消息队列使用的分发模型。详情见:数据融合重磅功能丨一对多实时分发、批量读取模式
- 有时会对一次读取的数据加不同的处理逻辑,我们希望这种处理不要重新对源端产生一次读取。所以在多数情况下,都需将数据先读到消息队列,然后再配置相应的处理逻辑。
- Kafka Connect 就是基于 MQ 模式的,它有大量的开源连接器。基于 Kafka Connect 框架,我们可以重用这些连接器,节省研发的投入。
- 当你把数据抽取跟写入目的地,从处理逻辑中独立出来之后,便可以提供更强大的集成能力。因为你可以在消息队列上集成更多的处理逻辑,而无需考虑重新写整个 Job。
相应而言,如果你选择将 MQ 作为所有 JOB 的传输通道,就必须要克服几个缺点:
- 所有数据的吞吐都经过 MQ,所以 MQ 会成为一个吞吐瓶颈。
- 因为是一个完全的流式架构,所以针对批量同步,你需要引入一些边界消息来实现一些批量控制。
- Kafka 是一个有持久化能力的消息队列,这意味着数据留存是有极限的。比如,你将源端的读到 Kafka Topic 里面,Topic 不会无限的大,有可能会造成数据容量超限,导致一些数据丢失。
- 当批量同步在中间因为某种原因被打断,无法做续传时,你需要进行重传。在重传过程中,首先要将数据进行清理,如果基于消息队列模式,清理过程就会带来额外的工作。你会面临两个困境:要么清空原有的消息队列,要么你创造新的消息队列。这肯定不如像直接使用一些批量同步框架那样来的直接。