运行环境与引擎

运行环境

无论采用何种数据变化捕获技术,程序必须在一个可靠的平台运行。该平台需要解决分布式系统的一些共性问题,主要包括:水平扩展、容错、进度管理等。

水平扩展

程序必须能够以分布式job的形式在集群中运行,从而允许在业务增长时通过增加运行时节点的方式实现扩展。

因为在一个规模化的企业中,通常要同时运行成百上千的job。随着业务的增长,job的数量以及job的负载还有可能持续增长。

容错

分布式运行环境的执行节点可能因为过载、网络连通性等原因无法正常工作。

当节点出现问题时,运行环境需要能够及时监测到,并将问题节点上的job分配给健康的节点继续运行。

进度管理

job需要记录自身处理的进度,避免重复处理数据。另外,job会因为上下游系统的问题、网络连通性、程序bug等各种原因异常中止,当job重启后,必须能够从上次记录的正常进度位置开始处理后继的数据。

有许多优秀的开源框架都可以满足上述要求,包括Kafka Connect、Spark、Flink等。

Kafka Connect是一个专注数据进出Kafka的数据集成框架。SparkFlink则更为通用,既可以用于数据集成,也适用于更加复杂的应用场景,例如机器学习的模型训练和流式计算。

就数据集成这一应用场景而言,不同框架的概念是非常类似的。

首先,框架提供Source Connector接口封装对数据源的访问。应用开发者基于这一接口开发适配特定数据源的Connector,实现数据抽取逻辑和进度(offset)更新逻辑。

其次,框架提供一个分布式的Connector运行环境,处理任务的分发、容错和进度更新等问题。

不同之处在于,Kafka Connect总是将数据抽取到Kafka,而对于SparkFlinkSource Connector是将数据抽取到内存中构建对象,写入目的地是由程序逻辑定义的,包括但不限于消息队列。

但无论采用何种框架,都建议首先将数据写入一个汇集层,通常是Kafka这样的消息队列。单就数据源采集而言,Kafka Connect这样专注于数据集成的框架是有一定优势的,这主要体现在两方面:

  • 首先是Connector的丰富程度,几乎所有较为流行的数据库、对象存储、文件系统都有开源的Connector实现。尤其在数据库的CDC方面,有Debezium这样优秀的开源项目存在,降低了应用的成本。

  • 其次是开发的便捷性,专有框架的设计相较于通用框架更为简洁,开发新的Connector门槛较低。Kafka Connectruntime实现也较为轻量,出现框架级别问题时debug也比较便捷。

引擎对比

数据流服务的构建则是基于流式计算引擎,对汇集层的数据进一步加工计算,并将结果实时输出给下游应用系统。这涉及到流式计算引擎的选择:Spark Streaming、Flink、还是Kafka Streams

延迟性

Spark对流的支持是MicroBatch,提供的是亚秒级的延迟,相较于FlinkKafka Streams在实时性上要差一些。

应用模式

SparkFlink都是将作业提交到计算集群上运行,需要搭建专属的运行环境。Kafka Streams的作业是以普通Java程序方式运行,本质上是一个调用Kafka Streaming APIKafka Consumer,可以方便地嵌入各种应用。

但相应的,用户需要自己解决作业程序在不同服务器上的分发问题,例如通过K8s集群方案进行应用的容器化部署。如果使用KSQL,还需要部署KSQL的集群。

SQL支持

三者都提供Streaming SQL,但FlinkSQL支持要更为强大些,可以运行更加复杂的分组聚合操作。

EOS

Flink对于数据进出计算集群提供了框架级别的支持,这是通过结合CheckPoint机制和Sink Connector接口封装的二阶段提交协议实现的。

Kafka Streams利用Kafka事务性消息,可以实现“消费-计算-写入Kafka“的EOS,但当结果需要输出到Kafka以外的目的地时,还需要利用Kafka ConnectSink Connector。遗憾的是,Kafka Connect不提供Kafka到其它类型SinkEOS保证,需要用户自己实现。

Spark StreamingKafka Streams类似,在读取和计算过程中可以保证EOS,但将结果输出到外部时,依然需要额外做一些工作来确保数据一致性。常见的方式包括:利用数据库的事务写入机制将Offset持久化到外部、利用主键保证幂等写入、参考二阶段提交协议做分布式事务等。

上一页