Kafka权威指南 读书笔记之(七)构建数据管道

使用 Kafka 构建数据管道时,通常有两种使用场景 第一种,把 Kafka 作为数据管道的个端点之,例如,把 Kafka 里的数据移动到 S3 上,或者把 MongoDB 里的数据移动
到 Kafka 里;第种,把 Kafka 作为数据管道两个端点的中间媒介,例如,为了把 Twitter的数据移动到 ElasticSearch 上,需要先把它们移动到 Kafka 里,再将它们从 Kafka 移动到
Elastic Search 上
Kafka 为数据管道带来的主要价值在于,它可以作为数据管道各个数据段之间的大型缓冲区, 有效地解桐管道数据的生产者和消费者。 Kafka 的解藕能力以及在安全和效率方面的
可靠性 ,使它成为构建数据管道的最佳选择。

 

将解释为什么可以使用 Kafka 进行数据集成,以及它是如何解决这些问题的。

讨论 Connect API 与普通的客户端 API (Producer 和Consumer )之间的区别,以及这些客户端 API 分别适合在什么情况下使用

然后会介绍 Connnect。 Connect 的完整手册不在本章的讨论范围之内,不过我们会举几个例子来帮助入门,而且会告诉你可以从哪了解到更多关于 Connect  的信息。

最后介绍其他数据集成系统,以及如何将它们与 Kafka 集成起来

构建数据管道时需要考虑的问题
这里不打算讲解所有有关构建数据管道的细节,会着重讨论在集成多个系统时需要考虑的几个最重要的问题
及时性
  有些系统希望每天次性地接收大量数据,而有些则希望在数据生成几毫秒之内就能拿到它们。大部分数据管道介于这两之间 。一个好的数据集成系统能够很好地支持数据管道
的各种及时性求,而且在业务需求发生变更时,具有不同及时性需求的数据表之间可以方便地进行迁移。 Kafka 作为个基于流的数据平台,提供了可靠且可伸缩的数据存储,
可以支持几近实时的数据管道和基于小时的批处理。生产者可以频繁地向 Kafka 写入数据,也可以按需写入:消费者可以在数据到达的第时间读取它们,也可以每隔段时间
读取一次积压的数据。
Kafka 在这里扮演了 个大型缓冲区的角色,降低了生产者和消费者之间的时间敏感度 实时的生产者和基于批处理的消费者可以同时存在,也可以任意组合。实现回压策略也因
此变得更加容易, Kafka 本身就使用了回压策略(必要时可以延后向生产者发送确),消费速率完全取决于消费者自己。
可靠性
  我们要避免单点故障,并能够自动从各种故障中快速恢复。数据通过数据管道到达业务系统,哪怕出现几秒钟的故障,也会造成灾难性的影响,对于那些要求毫秒级的及时性系统
来说尤为如此。数据传递保证是可靠性的另个重要因素。有些系统允许数据丢失,不过在大多数情况下,它们要求至少一次传递。也就是说,源系统的每个事件都必须到达目
的地,不过有时候需要进行重试,而重试可能造成重复传递。有些系统甚至要求仅一次传一一源系统的每一个事件都必须到达目的地,不允许丢失,也不允许重复
 Kafka 本身就支持“至少次传递”,如果再结合具有务模型或唯键特性的外部存储系统, Kafka 也能实现“仅一次传递”。
因为大部分的端点都是数据存储系统,它们提供了“仅次传递”的原语支持,所以基于 Kafka 的数据管道也能实现“仅次传递”。值一提的是, Connect APl 为集成
外部系统提供了处理偏移的 APl ,连接器因此可以构建仅次传递的端到端数据管道
高吞吐量和动态吞吐量
  为了满足现代数据系统的要求,数据管道需要支持非常的吞吐量。更重要的是,在某些情况下,数据管道还需要能够应对突发的吞吐量增长。
由于我们将 Kafka 作为生产者和消费者之间的缓冲区,消费者的吞吐量和生产者的吞吐量就不会辑合在一起了。我们也不再需要实现复杂的回压机制,如果生产者的吞吐量超过了
消费者的吞吐量,可以把数据积压在 Kafka 里,等待消费者追赶上来。通过增加额外的消费者或生产者可以实现 Kafka 的伸缩,因此我们可以在数据管道的任何一边进行动态的伸
缩,以便满足持续变化的需求。
因为 Kafka 是个高吞吐量的分布式系统, 个适当规模的集群每秒钟可以处理数百兆的数据,所以根本无需担心数据管道无法满足伸缩性需求。另外 , Connect API 不仅支持伸
缩,而且擅长并行处理任务。稍后,我们将会介绍数据源和数据池( Data Sink)如何在多个线程间拆分任务,最大限度地利用 CPU 资源,哪怕是运行在单台机器上。
Kafka 支持多种类型的压缩,在增长吞吐量时, Kafka 用户和管理员可以通过压缩来调整网络和存储资源的使用。
数据格式
  数据管道需要协调各种数据格式和数据类型,这是数据管道一个非常重要的因素。数据类型取决于不同的数据库和数据存储系统。你可能会通过 Avro 将 XML 或关系型数据加载
到 Kafka 里,然后将它们转成 JSON 入 ElasticSearch ,或者转成 Parquet 入 HDFS ,或者转成 csv 写入 S3 。
  Kafka 和 Connect API 与数据格式无关。生产者和消费者可以使用各种序列化器来表示任意格式的数据 。 Connect  API 有自己的内存对象模型,包括
数据类型和 schema。 不过,可以使用一些可插拔的转换器将这些对象保存成任意的格式,也就是说,不管数据是什么格式的,都不会限制我们使用连接器。
  很多数据源和数据池都有 schema,我们从数据池读取 schema,把它们保存起来,并用它们验证数据格式的兼容性,甚至用它们更新数据池的 schema从 MySQL 到Hive的数据
管道就是一个很好的例子。如果有人在 MySQL 里增加了字段 ,那么在加载数据时,数据管道可以保证 Hive 里也添加了相应的字段。
  另外,数据池连接器将 Kafka 的数据入外部系统,因此需要负责处理数据格式。有些连接器把数据格式的处理做成可插拔的,比如 HDFS 的连接器就支持 Avro 和 Parquet。
通用的数据集成框架不仅要支持各种不同的数据类型,而且要处理好不同数据源和数据池之间的行为差异。例如,在关系型数据库向 Syslog 发起抓取数据请求时, Syslog 会将数据
推送给它们,而 HDFS 只支持追加写入模式,只能向 HDFS 写入新数据,而对于其他很多系统来说,既可以追加数据, 也可以更新已有的数据
转换
  数据转换比其他需求更具争议性。数据管道的构建可以分为两大阵营,即 ETL 和 ELT
ETL 表示提取一转换一加载( Extract-Transform-Load ),也就是说,当数据流经数据管道时,数据管道会负责处理它们。
这种方式为我们节省了时间和存储空间,因为不需要经过保存数据、修改数据、再保存数据这样的过程。这种方式也有可能给数据管道造成不适当的计算和存储负担。
有一个明显不足,就是数据的转换会给数据管道下游的应用造成一些限制,特别是当下游的应用希望对数据进行进步处理的时候。假设有人在 MongoDB MySQL 之间建立了数据管道,
并且过滤掉了些事件记录,或者移除了 些字段,那么下游应用从 MySQL 中访问到的数据是不完整的。如果它们想要访问被移除的字段, 只能重新构建管道,并重新处理历史数据(如果可能的话)。

ELT 表示提取-加载-转换 ( Extract-Load-Transform )。在这种模式下,数据管道只做少量的转换(主要是数据类型转换),确保到达数据池的数据尽可能地与数据源保持致。 这种
情况也被称为高保真( high fidelity )数据管道或数据湖( data lake )架构。目标系统收集“原始数据”,并负责处理它们。这种方式为目标系统的用户提供了最大的灵活性,因为它
们可以访问到完整的数据。在这些系统里诊断问题也变得更加容易,因为数据被集中在同个系统里进行处理,而不是分散在数据管道和其他应用里。这种方式的不足在于,数据
的转换占用了目标系统太多的 CPU 和存储资源。有时候,目标系统造价高昂 ,如果有能,人们希望能够将计算任务移出这些系统。
安全性
  对于数据管道的安全性来说,人们主要关心如下几个方面。
能否保证流经数据管道的数据是经过加密的?这是跨数据中心数据管道通常需要虑的个主要方面。
• 谁能够修改数据管道?
如果数据管道需要从个不受信任的位置读取或入数据,是否有适当的认证机制?
Kafka 支持加密传输数据,从数据源到 Kafka ,再从 Kafka 到数据池。它还支持认证(通过SASL 来实现)和授权,所以你可以确信,如果个主题包含了敏感信息,在不经授权的
情况下,数据是不会流到不安全的系统里的。 Kafka 还提供了审计日志用于跟踪访问记录。通过编写额外的代码,还可能跟踪到每个事件的来源和事件的修改者,从而在每个记录之
间建立起整体的联系。

故障处理能力
  因为 Kafka 会长时间地保留数据,所以我们可以在适当 的时候回过头来重新处理出错的数据

耦合性和灵活性
  数据管道最重要的作用之是解耦数据源和数据池。它们在很多情况下可能发生耦合。

临时数据管道
  为每对应用程序建立单独的数据管道。例如, 他们使用 Logstash 向El asticSearch 导入日志,使用 Flume 向 HDFS 导人日志,使用 GoldenGate 将 Oracle 的
数据导到 HDFS ,使用 Informatica 将 MySQL 的数据或 XML 导到 Oracle ,等等。 他们将数据管道与特定的端点辑合起来,并创建了大量的集成点,需要额外的部署、维护和
监控。当有新的系统加入肘,他们需要构建额外的数据管道,从而增加了采用新技术的成本,同时遏制了创新。

元数据丢失
  如果数据管道没有保留 schema 元数据,而且不允许 schema 发生变更,那么最终会导致生产者和消费者之间发生紧密的捐合。没有了 schema ,生产者和消费者需要额外的
信息来解析数据。假设数据从 Oracle 流向 HDFS ,如DBA 在 Oracle 里添加了字段,而且没有保留 schema 信息,也不允许修改 schema ,那么从 HDFS 读取数据时可能
会发生错误,因此需要双方的开发人员同时升级应用程序才能解决这个问题。不管是哪种情况,它们的解决方案都不具备灵活性。如果数据管道允许 schema 发生变更,应
用程序各方就可以修改自己的代码,无需担心对整个系统造成破坏。

未端处理
  数据管道难免要做一些数据处理。在不同的系统之间移动数据肯定会碰到不同的数据格式和不同的应用场景。如果数据管道过地处
理数据,那么就会给下游的系统造成些限制。在构建数据管道时所做的设计决定都会对下游的系统造成束缚,比如应该保留哪些字段或应该如何聚合数据,等等。如果下游
的系统有新的需求,那么数据管道就要作出相应的变更,这种方式不仅不灵活,而且低效、不安全。更为灵活的方式是尽量保留原始数据的完整性,让下游的应用自己决定如
何处理和聚合数据。

如何在Connect API和客户端API之间作出选择
  在向 Kafka 写入数据或从 Kafka 读取数据时,要么使用传统的生产者和消费者客户端,要么使用后面即将介绍的 Connect API 和连接器。在具
体介绍 Connect API 之前,我们不妨先问自己个问题:“什么时候适合用哪个?”我们知道, Kafka 客户端是要被内嵌到应用程序里的,应用程序使用它们向 Kafka 写入数
据或从 Kafka 读取数据。如果你是开发人员,你会使用 Kafka 客户端将应用程序连接到Kafka ,并修改应用程序的代码,将数据推送到 Kafka 或者从 Kafka 读取数据。
  如果要将 Kafka 连接到数据存储系统,可以使用 Connect,因为这些系统不是你开发的,
你不能或者也不想修改它们的代码。 Connect 可以用于从外部数据存储系统读取数据,
者将数据推送到外部存储系统。如果数据存储系统提供了相应的连接器,那么非开发人就可以通过配置连接器的方式来使用 Connect。

  如果你要连接的数据存储系统没有相应的连接器,那么可以考虑使用客户端 API 或ConnecAP开发一个应用程序。我们建议首选 Connect,因为它提供了些开箱即用的特性,
比如配置管理、偏移量存储、并行处理、错误处理,而且支持多种数据类型和标准的 REST 管理 API。开发个连接 Kafka 和外部数据存储系统的小应用程序看起来很简单,
但其实还有很多细节需要处理,比如数据类型和配置选项,这些无疑加大了开发的复杂性一一Connect 处理了大部分细节,让你可以专注于数据的传输。

Kafka Connect
  Connect Kafka 的部分,它为在 Kafka 和外部数据存储系统之间移动数据提供了 可靠且可伸缩的方式。它为连接器插件提供了组 API 个运行时Connect 负责运
行这些插件 们则 负责移动数据。 Connect WO「ke「 进程集群的方式运行,我们基WO 「 ke 「 进程安装连接器插件,然后使用 REST API 来管理和配置 con nee to「,这些 WO 「 ke 「
进程都是长时间持续运行的作业。连接器启动额外的 task ,有效地利用工作节点的资源,以并行的方式移动大量的数据。数据源连接器负责从源系统读取数据,井把数据对
提供给 WO「ke「 进程。数据的连接器负责从 WO「ker 进程获取数据,井把它们写入目 系统。 Connect 通过 connecto 「 Kafka 里存储不同格式的数据。 Kafka 支持 JSON ,而
Confluent Schema Registry 提供了 Avro 转换器。开发人员可以选择数据的存储格式,这完全独立于们所使用的连接器。

运行Connect
  Connect 随着 Kafka 一起发布,所以无需单独安装。如果你打算在生产环境使用 Connect 移动大量的数据,或者打算运行多个连接器,那么最好把 Connect 部署在独立于 broker 的
服务器上。在所有的机器上安装 Kafka,并在部分服务器上启动 broker,然后在其他服器上启动 Connect启动 Connect 进程与启动 broker 差不多 在调用脚本时传入个属性文件即可

Connect 进程有以下几个重要的配置参数。
bootstrap.servers :该参数列出了将要与 Connect 协同工作的 broker 服务器,连接器将会向这些 broker 写入数据或者从它们那里读取数据。你不需要指定集群所有的 broker ,
不过建议至少指定 3 个。

group.id :具有相同 group.id 的 worker 属于同Connect 集群。集群的连接器和它的任务可以运行在任意个 worker 上。

key. convertervalue.converter: Connect 可以处理存储在 Kafka 里的不同格式的这两个参数分别指定了消息的键和值所使用的转换器。默认使用 Kafka 提供的
JSONConverter ,当然也可以配置成 Confluent Schema Registry 提供的 AvroConverter 。

有些转换器还包了特定的配置参数。例如,通过将 key.converter.schema.enable 设置成true 或者 false 来指定 JSON 消息是否可以包含 schema。值转换器有类似的配置,不过
数名是 value.converter.schema.enable 。 
  我般通过 Connect 的REST API 来配置和监控rest.host.name 和rest.port 连接器 。你可以为REST API 指定特定的端口。
在启动 worker 集群之后,可以通过REST API 来验证它们是否运行正常。

这个 REST URL应该要返回当前 Connect 的版本号
我们还可以检查已经安装好的连接器插件:



连接器示例一一文件数据源和文件数据池  (略)

连接器示例一一从MySQL到 ElasticSearch (略)

 

深入理解Connect
  要理解 Connect 的工作原理,需要先知道 3 个基本概念,以及它们之间是如何进行交互的。

1 . 连接器和任务
连接器插件实现了 Connector API, API 包含了两部分内容。

连接器
连接器负责以下 3 件事情。
•  决定需要运行多少个任务。
•  按照任务来拆分数据复制。
•  从 worker 进程获取任务配置并将其传递下去。例如, JDBC 连接器会连接到数据库,统计需要复制的数据表,并确定需要执行多少个任务,然后在配置参数 max.tasks
 和实际数据量之间选择数值较小的那个作为任务数。在确定了任务数之后,连接会为每个任务生成一个配置,配置里包含了连接器的配置项(比如 connection .url)
 和该任务需要复制的数据表。 taskConfigs() 方也返回个映射列表,这些映射包了任务的相关配置。 worker 进程负责启动和配置任务,每个任务只复制配置项里指
    定的数据表。如果通过REST API 启动连接器,有可能会启动任意节点上的连接器,那么连接器的任务就会在该节点上执行。
任务
任务负责将数据移入或移出 Kafka。任务在初始化时会得到由 worker 进程分配的上下文 源系统上下文( Source Context)包含了个对象,可以将源系统记录的偏移
量保存在上下文里(例如,文件连接器的偏移量就是文件里的字节位置, JDBC 连接器
的偏移量可以是数据表的主键 ID ) 。目标系统连接器的上下文提供了一些方法,连接器
可以用它们操作从 Kafka 接收到的数据,比如进行数据清理、错误重试,或者将偏移量保存到外部系统以便实现仅一次传递。任务在完成初始化之后,就开始按照连接器指定
的配置(包含在个 Properties 对象里)启动工作。 源系统任务对外部系统进行轮询,并返回一些记录 , worker 进程将这些记录发送到 Kafka。数据池任务通过 worker 进程
接收来自 Kafka 的记,并将它们写入外部系统。

2. worker 进程
  worker 进程是连接器 和任务的“容器”。它们负责处理 HTTP 请求,这些请求用于定义连接器和连接器的配置。它们还负责保存连接器的配置、启动连接器和连接器任务,并把配
置信息传递给任务。 如果个 worker 进程停止工作或者发生崩溃,集群里的其他 worker进程会感知到( Kafka 的消费者协议提供了心跳检测机制),并将崩溃进程的连接器和任务
重新分配给其他进程。如果有新的进程加入集群,其他进程也会感知到,并将自己的连接器和任务分配给新的进程,确保工作负载的均衡。进程还负责提交偏移量,如果任务抛出
异常,可以基于这些偏移量进行重试。
  为了更好地理解 worker 进程,我们可以将其与连接器和任务进行简单的比较。连接器和任务负责“数据的移动”, 而 worker 进程负责 REST API、配置管理、可靠性、高可用性、伸
缩性和负载均衡
  这种关注点分离是 Connect API 给我们带来的最大好处,而这种好处是普通客户端 API 所不具备。有经验的开发人员都知道,编写代码从 Kafka 读取数据并将其插入数据库只需
到两天的时间,但是如果要处理好配置、异常、 REST API、监控、部署、伸缩、失效等问题,可需要几个月 如果你使用连接器来实现数据复制,连接器插件会为你处理掉
大堆复杂的问题

3. 转化器和 Connect 的数据模型
  数据模型和转化器是 Connect API 需要讨论的最后部分内容。 Connect 提供了组数据API它们包含了数据对象和用于描述数据的 schema。例如, JDBC 连接器从数据库读
取了一字段,并基于这个字段的数据类型创建了个 Connect Schema 对象。然后使用这些 Schema 对象创建个包含了所有数据库字段的 Struct一一我们保存了每个字段的名
字和它们的值。源连接器所做的事情都很相似一一从源系统读事件,并为每个事件生成schema 和值(值就是数据对象本身) 目标连接器正好相反,它们获取 schema 和值,并使
用 schema 来解析值,然后入到目标系统。
  源连接器只责基于 Data API 生成数据对象,那么 worker 进程是如何将这些数据对象保存到 Kafka 的?这个时候,转换器就派上用场了。用户在配置 worker 进程(或连接器)时
可以选择使用合适的转化器,用于将数据保存到 Kafka。目前可用的转化器有 Avro 、 JSON和 String。 JSON 转化器可以在转换结果里附带上 schema,当然也可以不使用 schema,这
个是可配Kafka 系统因此可以支持结构化的数据和半结构化的数据。连接器通过 DataAPI 将数据返回给 worker 进程, worker 进程使用指定的转化器将数据转换成 Avro 对象、
JSON 对象或者字符串,然后将它们写入 Kafka
  对于目标连接器来说,过程刚好相反一一在从 Kafka 读取数据时, worker 进程使用指定的
转换器将各种格式( Avro 、 JSON 或 String)的数据转换成 Data API 格式的对象,然后将
它们传给目标连接器,目标连接器再将它们插入到目标系统。Connect API 因此可以支持多种类型的数据,数据类型与连接器的实现是相互独立的一一只要有可用的转换器,连接器和数据类型可以自由组合。

4. 偏移量管理
  worker 进程的 REST API 提供了部署和配置管理服务,除此之外, worker 进程还提供了偏移量管理服务。连接器只要知道哪些数据是已经被处理过的,就可以通过 Kafka 提供的
API 来维护偏移量。
  源连接器返回给 worker 进程的记录里包含了一个逻辑分区和个逻辑偏移量。它们并非Kafka 的分区和偏移量,而是源系统的分 区和偏移量。例如,对于文件源来说,分区可以
个文件,偏移量可以是文件里的一个行号或者字符号:而对于 JDBC 据来说,分区可以是一个数据表,偏移量可以是条记录的主键。在设计个据连接器时,要着重考虑如
何对源系统的数据进行分区以及如何跟踪偏移量,这将影响连接器的并行能力,也决定了连接器是否能够实现至少次传递或者仅次传递。
  源连接器返回的记录里包含了源系统的分区和偏移量, worker 进程将这些记录发送给Kafka 。如果 Kafka 确认记录保存成功, worker 进程就把偏移量保存下来。偏移量的存储
机制是可插拔的, 一般会使用 Kafka 主题来保存。如果连接器发生崩溃并重启,它可以从最近的偏移量继续处理数据。
  目标连接器的处理过程恰好相反,不过也很相似。它们从 Kafka 上读取包含了主题、分区和偏移量信息的记录,然后调用连接器的 put () 方法,该方告会将记录保存到目标系统里
如果保存成功,连接器会通过消费者客户端将偏移量提交到 Kafka 上。框架提供的偏移量跟踪机制简化了连接器的开发工作,并在使用多个连接器时保证了程度的行为一致性。

Connect之外的选择
        对 Connect API 有了更加深入的了解,不仅知道如何使用它们,还知道它们的一些工作原理。虽然 Connect API 为我们提供了便利和可靠性,但它并非唯的选择。
面看看还有哪些可用的框架,以及在什么时候可以使用它们。

用于其他数据存储的摄入框架
  虽然我们很想说 Kafka 是至高无上的明星,但肯定会有人不同意这种说法。有些人将 Hadoop 或 ElasticSearch 作为他们数据架构的基础,这些系统都有自己的数据摄入
具。 Hadoop 使用了 Flume, ElasticSearch 使用了 Logstash 或 Fluentd。如果架构里包含了Kafka ,并且需要连接大的源系统和目标系统,那么建议使用 Connect API 作为摄入
具。如果构建的系统是以 Hadoop 或 ElasticSearch 为中心的, Kafka 只是数据的来惊之那么使用 Flume 或 Logstash 会更合适。

基于图形界面的 ETL工具
  从保守的 Informatica 到些开源的替代方案,比如 Talend Pentaho , 或者更新的 ApacheNiFi 和 StreamSets一一这些 ETL 解决方案都支持将 Kafka 作为数据源和数据。如果你已
经使用了这些系统,比如 Pentaho , 那么就可能不会为了 Kafka 而在系统里增加另一种集成工具。如果你已经习惯了基于图形界面的 ETL 数据管道解决方案,那就继续使用它们。
不过, 这些系统有一些不足的地方,那就是它们的工作流较复杂,如果你只是希望Kafka 里获取数据或者将数据写入 Kafka ,那么它们就显得有点笨重。我们在始的部
分已经说过,在进行数据集成时,应该将注意力集中在消息的传输上。因此,对于我说,大部分 ETL 工具都太过复杂了。
我们极力建议将 Kafka 当成是一个支持数据集成(使用 Connect)、应用集成(使用生产者和消费者)和流式处理的平台。 Kafka 完全可以成为 ETL 工具的替代品。

流式处理框架
  几乎所有的流式处理框架都具备从 Kafka 读取数据并将数据写入外部系统的能力。如果你的目标系统支持流式处理,并且你已经打算使用流式框架处理来自 Kafka 的数据,那么使
用相同的框架进行数据集成看起来是很合理的。这样可以省掉个处理步骤(不需要保存来自 Kafka 的数据,而是直接从 Kafka 读取数据然后写到其系统) 不过在发生数据丢失
或者出现脏数据时,诊断问题会变得很困难,因为这些框架并不知道数据是什么时候丢失的,或者什么时候出现了脏数据。


 




posted @ 2018-10-09 18:41  青青子衿J  阅读(704)  评论(0编辑  收藏  举报