Notes of the book The Definitive Guide of Kafka


第 1 章 初识 Kafka

主题和分区

一个 topic 可以分为若干个分区,一个分区就是一个提交日志。消息以追加的方式写入分区,然后以先入先出的顺序读取。

由于一个 topic 一般包含几个分区,所以无法在整个 topic 范围内保证消息的顺序,但是可以保证消息在单个分区的顺序。

broker 和集群

一个独立的 Kafka 服务器被称为 broker。broker 接手来自生产者的消息,为消息设置偏移量,并提交消息到磁盘保存。broker 为消费者提供服务,对读取分区的请求作出响应,返回已经提交到磁盘上的消息。

第 2 章 安装

如何确定分区数量

需要考虑:

  • topic 想要多大的吞吐
  • 从单个分区读取的最大吞吐量是多少?
  • 生产者向单个分区写入数据的吞吐量
  • 可以用的磁盘和网络带宽
  • 数量不是无限制的,分区越多,内存占用越多,leader 选举的时间也越长

第 3 章 Kafka 生产者 - 写入数据

发送消息有 3 种方式:

  1. 发送并忘记(fire-and-forget)
  2. 同步发送(等待)
  3. 异步发送(回调)

同步

producer.send() 方法先返回一个 future 对象,然后调用 Future 对象的 get() 方法等待 Kafka 响应。成功的话,会得到一个 RecordMetadata 对象,可以用它获取消息的偏移量。

异步

为了在异步发送消息的同时能够对异常情况进行处理,生成者提供了回调支持。

生产者的配置

  • acks
  • buffer.memory
  • compression.type
  • retries
  • batch.size
  • max.block.ms
  • max.request.size

分区

Record 包了 topic, key, value。如果 key 为 null,record 将被随机地发送到 topic 内各个可用的分区上。如果 key 不为空,并使用了默认的分区器,那么 Kafka 会对 key 进行散列,同一个 key 总是被映射到同一个分区上。

第 4 章 消费者 - 从 Kafka 读取数据

KafkaConsumer

消费者和消费者群组的关系:消费者从属于消费者群组,一个群组里的消费者订阅的是同一个 topic,每个消费者接受主题一部分分区的消息。

如果往群组里添加更多的消费者,超过了分区的数量,那么有一部分消费者就会被闲置,不会接受任何消息。

消费者群组和分区的 rebalance

分区的所有权从一个消费者转移到另一个消费者,这样的行为被称为「再均衡」。 消费者通过向被指派为群组协调器的 broker 发送心跳来维持它们和群组的从属关系以及它们对分区的所有权关系。

分配分区过程

当消费者要加入群组的时候,它会向群组协调器发送一个 JoinGroup 请求。第一个加入的消费者将成为「群主」,它负责从协调器那里获取群组的成员列表,并负责给每一个消费者分配分区。

提交和偏移量

我们把更新分区当前位置的操作叫做 提交

  • 自动提交
  • 异步提交
  • 同步和异步组合提交
  • 提交特定的偏移量

从特定偏移量处开始处理记录

使用 seek() 方法定位到某条记录

独立消费者 - 使用没有群组的消费者

  1. 向集群请求 topic 的可用分区
  2. 知道有哪些分区之后,调用 assign() 方法

第 5 章 深入 Kafka

  • Kafka 如何进行复制
  • Kafka 如何处理来自生产者和消费者的请求
  • Kafka 的存储细节,比如文件格式和索引

集群成员关系

Kafka 使用 Zookeeper 来维护集群成员的信息。每个 broker 都有一个唯一标识符,可以在配置文件制定也可以自动生成。每个 broker 启动的时候,它通过创建临时节点把自己的 ID 注册到 Zookeeper。Kaka 组件订阅 Zookeeper 的 /brokers/ids 路径,当有 broker 加入或者退出集群的时候,这些组件就能获得通知。

控制器

控制器其实就是一个 broker,除了具备一般 broker 的功能以外,还负责分区首领的选举。第一个启动的 broker 通过在 Zookeeper 创建一个临时节点让自己成为控制器。

如果控制器被关闭或者与 Zookeeper 断开连接,Zookeeper 上的临时节点就会消失。其他 broker 就会尝试新的控制器,但是只会有一个 broker 成为控制器。

当控制器发现一个 broker 离开集群,那么失去 leader 的分区就需要新 leader。控制器会遍历这些分区,并确定谁会成为新的 leader。控制器会通知大家,随后新 leader 开始处理来自生产者和消费者的请求,而 follower 开始从新 leader 那么复制消息。

控制器负责在节点加入和离开集群时进行分区 leader 选举。控制器使用 epoch 来避免「大脑分裂」。

复制

副本有以下两种类型:

  1. leader 副本:为了保证一致性,所有生产者和消费者请求都会经过这个副本
  2. follower 副本:

leader 的另一个任务是搞清楚哪个 follower 的状态是跟自己一致的。为了保持同步,follower 向 leader 发送获取数据的请求。

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

produce 请求

之前提到 acks 这个配置参数,就是指定了需要多少个 broker 确认才可以认为一个消息是写入成功的。

获取请求

客户端发送请求,向 broker 请求 topic 的分区具有特定偏移量的消息。

Kafka 使用了零复制技术向客户端发送消息,避免了字节复制,也不需要管理内存缓冲区,从而获得更好的性能。

客户端可以设置数据返回的上限和下限,还可以设置超时时间。

分区分配

假设有 6 个 broker,打算创建一个包含 10 个分区的 topic,并且复制系数为 3。那么 Kafka 就会有 30 个分区副本,它们可以被分配给 6 个 broker。

文件管理

Kafka 不会一直保留数据,也不会等到所有消费者都读取了消息之后才删除消息。Kafka 为每个 topic 配置了数据保留期限,规定数据被删之前可以保留多久。

第 6 章 可靠的数据传递

可靠性保证

Kafka 可以保证:

  • 分区消息的顺序
  • 当消息被写入分区的所有同步副本,才被认为是「已提交」
  • 只要还有一个副本是活跃的,那么已经提交的消息就不会丢失
  • 消费者只能读取已经提交的消息

复制

Kafka 的 topic 被分为多个分区,分区是基本的数据块。

leader 是同步副本。follower 要满足以下条件才是同步的:

  • 与 ZK 之间有活跃的会话
  • 过去的 10s 内从首领那里获取(最新)消息

在可靠系统里使用生产者

3 种确认模式:

  • acks=0
  • acks=1
  • acks=all

在可靠系统里使用消费者

一些配置说明:

  1. group.id 如果两个消费者具有相同的 group id,并且订阅了同一个 topic,那么消费者会分到该 topic 的一个子集。
  2. auto.offset.reset
  3. enable.auto.commit
  4. auto.commit.interval.ms

验证系统可靠性

配置验证:

  • leader 选举
  • 控制器选举
  • 依次重启

应用程序验证:

  • 客户端从服务器断开
  • leader 选举
  • 依次重启 broker
  • 依次重启消费者
  • 依次重启生产者

总结

可靠性并不只是 Kafka 单方面的事情。我们应该从整个系统层面来考虑可靠性问题,包括应用程序的架构、生产者和消费者 API 的使用方式、topic 和 broker 的配置。

第 7 章 构建数据管道

构建数据管道需要考虑的问题

  • 及时性
  • 可靠性
  • 高吞吐量和动态吞吐量
  • 数据格式
  • 转换
  • 安全性
  • 故障处理能力
  • 耦合性和灵活性

第 8 章 跨集群数据镜像

跨数据中心的问题:

  • 高延迟
  • 有限的带宽
  • 高成本

跨集群架构包括:

  1. Hub 和 Spoke 架构
  2. 双活架构
  3. 主备架构

MirrorMaker

Kafka 提供了一个简单的工具用于在两个数据中心之间镜像(mirror)数据。

过程很简单,MirrorMaker 为每个消费者分配一个线程,消费者从源集群的 topic 和分区上读取数据,然后通过公共生产者将数据发送到目标集群上。

YOU MIGTH ENJOY

  • System design 4 - How to design a rate limiter
  • How I brought my cat to Canada 如何把猫咪带去加拿大
  • System Design 3 - 知乎匿名系统设计