Kafka权威指南

第一章 初识kafka

  1. 数据为企业发展提供动力,从数据中获取信息,对它们进行分析处理,并生成更多的数据
    1. 就比如:在网站上浏览了感兴趣的商品,那么浏览信息就会转化成商品推荐,展示给我们
  2. 如何移动数据几乎变得与数据本身一样重要,数据管道会成为关键组件

相关名词

消息

kafka的数据单元,相当于数据库中的一条“记录”,由字节数组组成

消息中可选的元数据,也就是键,也是字节数组,相当于数据库分区键,用来指定分区的

批次

为提高效率,消息会被分成批次写入kafka,批次包含了一组属于同一个主题和分区的消息。

模式

消息传输模式,比如常见的JSON,XML,Apache Avro—Hadoop开发的一款序列化框架

主题和分区

通过主题进行分类,好比数据库的表,可以被分成若干个分区,一个分区就是一个提交日志,消息会以追加的方式被写入分区,然后按照先入先出的顺序读取。

用流来描述Kafka这类系统中的数据,把一个主题的数据看成一个表,流是一组从生产者移动到消费者的数据。Kafka streams,Apache samza,Storm

生产者

消息键与分区器

消费者

消费者通过检查消息的偏移量来区分已经读过的消息,偏移量是另一种元数据

消费者组

属于同一个消费者组的一个或多个消费者共同读取一个主题,消费者与分区之间的映射通常被称为消费者对分区的所有权关系。

broker和集群

leader,follower,副本,同步,保留消息在broker

Kafka的应用场景

  1. 活动跟踪
  2. 传递消息
  3. 指标和日志记录
  4. 提交日志
  5. 流式计算,真正的流式处理通常是指提供了类似map/reduce(Hadoop)处理功能的应用程序。

深入Kafka

讲解思路

  • Kafka 如何进⾏复制;
  • Kafka 如何处理来⾃⽣产者和消费者的请求;
  • Kafka 的存储细节,⽐如⽂件格式和索引。

集群成员关系

控制器broker

控制器

Kafka 使⽤ Zookeeper 的临时节点来选举控制器,并在节点加⼊集群或退出集群时通知 控制器。控制器负责在节点加⼊或离开集群时进⾏分区⾸领选举。控制器使⽤ epoch 来避免“脑 裂”。“脑裂”是指两个节点同时认为⾃⼰是当前的控制器。

控制器作用

Kafka 控制器组件(Controller) 即 Broker, 是 Kafka 的核心组件。它的主要作用是在 ZooKeeper 的帮助下管理和协调整个 Kafka 集群。集群中任意一台 Broker 都能充当控制器的角色,但是在运行过程中,只能有一个 Broker 成为控制器,来执行管理和协调的职责。换句话说,每个正常运转的 Kafka 集群,在任意时刻都有且只有一个控制器。下面我们就来详细聊聊控制器的原理和内部运行机制。

  1. topic管理
  2. 分区重分配
  3. Leader选举
  4. 集群成员管理
  5. 提供数据服务
    1. 控制器会向其他 Broker 提供数据服务。控制器上保存了最全的集群元数据信息,其他所有 Broker 会定期接收控制器发来的元数据更新请求,从而更新其内存中的缓存数据。

复制

在 Kafka 的⽂档⾥,Kafka 把⾃⼰描述成“⼀个分布式的、可分区 的、可复制的提交⽇志服务”。

⾸领副本

每个分区都有⼀个⾸领副本。为了保证⼀致性,所有⽣产者请求和消费者请求都会经过这个副 本。 跟随者副本 ⾸领以外的副本

跟随者副本

⾸领以外的副本都是跟随者副本。跟随者副本不处理来⾃客户端的请求,它们唯⼀的任务就是从 ⾸领那⾥复制消息,保持与⾸领⼀致的状态。如果⾸领发⽣崩溃,其中的⼀个跟随者会被提升为新⾸ 领。

为了与⾸领保持同步,跟随者向⾸领发送获取数据的请求,这种请求与消费者为了读取消息⽽发送的 请求是⼀样的。⾸领将响应消息发给跟随者。请求消息⾥包含了跟随者想要获取消息的偏移量,⽽且 这些偏移量总是有序的。

同步的副本

持续请求得到的最新消息副本被称为同步的副本。在⾸领发⽣失效时,只有同步副本才有可能被 选为新⾸领。

不同步副本

跟随者的正常不活跃时间或在成为不同步副本之前的时间是通过 replica.lag.time.max.ms 参数 来配置的。

元数据请求

客户端怎么知道该往哪⾥发送请求呢?客户端使⽤了另⼀种请求类型,也就是元数据请求。这种请求包含了客户端感兴趣的主题列表。服务器端的响应消息⾥指明了这些主题所包含的分区、每个分区都有哪些副本,以及哪个副本是⾸领。元数据请求可以发送给任意⼀个 broker,因为所有 broker 都缓存了这些信息。

包含⾸领副本的 broker 在收到⽣产请求时,会对请求做⼀些验证

发送数据的⽤户是否有主题写⼊权限? 请求⾥包含的 acks 值是否有效(只允许出现 0、1 或 all)? 如果 acks=all,是否有⾜够多的同步副本保证消息已经被安全写⼊?(我们可以对 broker 进 ⾏配置,如果同步副本的数量不⾜,broker 可以拒绝处理新消息。在第 6 章介绍 Kafka 持久性 和可靠性保证时,我们会讨论更多这⽅⾯的细节。)

炼狱

在消息被写⼊分区的⾸领之后,broker 开始检查 acks 配置参数——如果 acks 被设为 0 或 1,那 么 broker ⽴即返回响应;如果 acks 被设为 all,那么请求会被保存在⼀个叫作炼狱的缓冲区⾥, 直到⾸领发现所有跟随者副本都复制了消息,响应才会被返回给客户端。

零复制技术

Kafka 使⽤零复制技术向客户端发送消息——也就是说,Kafka 直接把消息从⽂件(或者更确 切地说是 Linux ⽂件系统缓存)⾥发送到⽹络通道,⽽不需要经过任何中间缓冲区。这是 Kafka 与 其他⼤部分数据库系统不⼀样的地⽅,其他数据库在将数据发送给客户端之前会先把它们保存在本地 缓存⾥。这项技术避免了字节复制,也不需要管理内存缓冲区,从⽽获得更好的性能。

Kafka 最为常⻅的⼏种请求类型

元数据请求、⽣产请求和获取请求

kafka的升级

协议在持续演化——随着客户端功能的不断增加,我们需要改进协议来满⾜需求。例如,之前的 Kafka 消费者使⽤ Zookeeper 来跟踪偏移量,在消费者启动的时候,它通过检查保存在 Zookeeper 上的偏移量就可以知道从哪⾥开始处理消息。因为各种原因,我们决定不再使⽤ Zookeeper 来保存偏移量,⽽是把偏移量保存在特定的 Kafka 主题上。

可靠性

可靠性是系统的⼀个属性,⽽不是⼀个独⽴的组件,所以在讨论 Kafka 的可靠性保证时,还是要从系统的整体出发。

有些场景要求很⾼的可靠性,⽽有些则更看重速度和简便性。

Kafka 被设计成⾼度可配置的,⽽且它的客户端 API 可以满⾜不同程度的可靠性需求。

讲解思路

  1. 本章先讨论各种各样的可靠性及其在 Kafka 场景中的含义。
  2. 然后介绍 Kafka 的复制功能,以及 它是如何提⾼系统可靠性的。
  3. 随后探讨如何配置 Kafka 的 broker 和主题来满⾜不同的使⽤场景需求,也会涉及⽣产者和消费者以及如何在各种可靠性场景⾥使⽤它们。
  4. 最后介绍如何验证系统的可靠性,因为系统的可靠性涉及⽅⽅⾯⾯——⼀些前提条件必须先得到满⾜。

可靠性保证

只有当消息被写⼊分区的所有同步副本时(但不⼀定要写⼊磁盘),它才被认为是“已提交”的。

复制

Kafka 的主题被分为多个分区,分区是基本的数据块。分区存储在单个磁盘上,Kafka 可以保证分区 ⾥的事件是有序的,分区可以在线(可⽤),也可以离线(不可⽤)。每个分区可以有多个副本,其 中⼀个副本是⾸领。所有的事件都直接发送给⾸领副本,或者直接从⾸领副本读取事件。其他副本只 需要与⾸领保持同步,并及时复制最新的事件。当⾸领副本不可⽤时,其中⼀个同步副本将成为新⾸ 领。

分区⾸领是同步副本,⽽对于跟随者副本来说,它需要满⾜以下条件才能被认为是同步的。

  1. 与 Zookeeper 之间有⼀个活跃的会话,也就是说,它在过去的 6s(可配置)内向 Zookeeper 发送过⼼跳。
  2. 在过去的 10s 内(可配置)从⾸领那⾥获取过消息。 在过去的 10s 内从⾸领那⾥获取过最新的消息。
  3. 光从⾸领那⾥获取消息是不够的,它还必须是⼏ 乎零延迟的。

如果跟随者副本不能满⾜以上任何⼀点,⽐如与 Zookeeper 断开连接,或者不再获取新消息,或者 获取消息滞后了 10s 以上,那么它就被认为是不同步的。

broker配置

broker 有 3 个配置参数会影响 Kafka 消息存储的可靠性。

复制系数

replication.factor,主题级别的配置参数,因为 Kafka 的默认复制系数就是 3——不过⽤户可以修改它。即使是在 主题创建之后,也可以通过新增或移除副本来改变复制系数。

如果复制系数为 N,那么在 N-1 个 broker 失效的情况下,仍然能够从主题读取数据或向主题写⼊数 据。所以,更⾼的复制系数会带来更⾼的可⽤性、可靠性和更少的故障。另⼀⽅⾯,复制系数 N 需要 ⾄少 N 个 broker,⽽且会有 N 个数据副本,也就是说它们会占⽤ N 倍的磁盘空间。我们⼀般会在 可⽤性和存储硬件之间作出权衡。

副本的分布也很重要。默认情况下,Kafka 会确保分区的每个副本被放在不同的 broker 上。

为了避免机架级别的故障,我们建议把 broker 分布在多个不同的机架上,并使⽤ broker.rack 参数来为每个 broker 配置所在机架的名字。如果 配置了机架名字,Kafka 会保证分区的副本被分布在多个机架上,从⽽获得更⾼的可⽤性。

不完全的⾸领选举

unclean.leader.election.enable只能在 broker 级别(实际上是在集群范围内)进⾏配置,它的默认 值是 true。

我们之前提到过,当分区⾸领不可⽤时,⼀个同步副本会被选为新⾸领。如果在选举过程中没有丢失 数据,也就是说提交的数据同时存在于所有的同步副本上,那么这个选举就是“完全”的。 但如果在⾸领不可⽤时其他副本都是不同步的,我们该怎么办呢?

简⽽⾔之,如果我们允许不同步的副本成为⾸领,那么就要承担丢失数据和出现数据不⼀致的⻛险。 如果不允许它们成为⾸领,那么就要接受较低的可⽤性,因为我们必须等待原先的⾸领恢复到可⽤状 态。

如果把 unclean.leader.election.enable 设为 true,就是允许不同步的副本成为⾸领(也就 是“不完全的选举”),那么我们将⾯临丢失消息的⻛险。如果把这个参数设为 false,就要等待原先 的⾸领重新上线,从⽽降低了可⽤性。

银行系统,信用卡支付事务/实时点击流分析系统

最少同步副本

在主题级别和 broker 级别上,这个参数都叫 min.insync.replicas。

根据 Kafka 对可 靠性保证的定义,消息只有在被写⼊到所有同步副本之后才被认为是已提交的。

对于 ⼀个包含 3 个副本的主题,如果 min.insync.replicas 被设为 2,那么⾄少要存在两个同步副本 才能向分区写⼊数据。 如果 3 个副本都是同步的,或者其中⼀个副本变为不可⽤,都不会有什么问题。不过,如果有两个副 本变为不可⽤,那么 broker 就会停⽌接受⽣产者的请求。尝试发送数据的⽣产者会收到 NotEnoughReplicasException 异常。消费者仍然可以继续读取已有的数据。实际上,如果使⽤ 这样的配置,那么当只剩下⼀个同步副本时,它就变成只读了,这是为了避免在发⽣不完全选举时数 据的写⼊和读取出现⾮预期的⾏为。为了从只读状态中恢复,必须让两个不可⽤分区中的⼀个重新变 为可⽤的(⽐如重启 broker),并等待它变为同步的

在可靠的系统⾥使⽤⽣产者

  1. 根据可靠性需求配置恰当的 acks 值。
  2. 在参数配置和代码⾥正确处理错误。

acks(0,1,all)

⼀般情况下,如果你的⽬标是不丢失任何消息,那么最好让⽣产者在遇到可重试错误时能够保持重 试。

重试发送⼀个已经失败的消息会带来⼀些⻛险,如果两个消息都写⼊成功,会导致消息重 复。重试和恰当的错误处理可以保证每个消息“⾄少被保存⼀次”,但当前 的 Kafka 版本(0.10.0)⽆法保证每个消息“只被保存⼀次”。

在 0.11 之后,指定 Producer 幂等性的方法很简单,仅需要设置一个参数即可,即 props.put(“enable.idempotence”, ture)或 props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true)。

所谓的消息交付可靠性保障,是指 Kafka 对 Producer 和 Consumer 要处理的消息提供什么样的承诺。常见的承诺有以下三种:

  1. 最多一次(at most once):消息可能会丢失,但绝不会被重复发送。
  2. 至少一次(at least once):消息不会丢失,但有可能被重复发送。
  3. 精确一次(exactly once):消息不会丢失,也不会被重复发送。

使⽤⽣产者内置的重试机制可以在不造成消息丢失的情况下轻松地处理⼤部分错误,不过对于开发⼈ 员来说,仍然需要处理其他类型的错误,包括:

  • 不可重试的 broker 错误,例如消息⼤⼩错误、认证错误等;
  • 在消息发送之前发⽣的错误,例如序列化错误;
  • 在⽣产者达到重试次数上限时或者在消息占⽤的内存达到上限时发⽣的错误
  1. 丢弃“不合法的消息”?
  2. 把错误记录下来?
  3. 把这些消息保存在本地 磁盘上?
  4. 回调另⼀个应⽤程序?

具体使⽤哪⼀种逻辑要根据具体的架构来决定。只要记住,如果错误处理只是为了重试发送消息,那么最好还是使⽤⽣产者内置的重试机制。

在可靠的系统⾥使⽤消费者

消费者的可靠性配置

  1. group.id
  2. auto.offset.reset
  3. enable.auto.commit
  4. auto.commit.interval.ms

精准一次、幂等性写⼊

总结

正如我们在本章开头所说的,可靠性并不只是 Kafka 单⽅⾯的事情。我们应该从整个系统层⾯来考虑 可靠性问题,包括应⽤程序的架构、⽣产者和消费者 API 的使⽤⽅式、⽣产者和消费者的配置、主题 的配置以及 broker 的配置。系统的可靠性需要在许多⽅⾯作出权衡,⽐如复杂性、性能、可⽤性和 磁盘空间的使⽤。掌握 Kafka 的各种配置和常⽤模式,对使⽤场景的需求做到⼼中有数,你就可以在 应⽤程序和 Kafka 的可靠性程度以及各种权衡之间作出更好的选择。

Asks=-1,会导致程序阻塞,

讲解思路

  1. AKF
  2. 可靠性保证
  3. kafka的使用场景