什么是 Kafka?
- Kafka 适合哪些场景?
- Kafka 体系结构和概念
- Kafka 架构
- Kafka 基本术语和概念
- 消息
- 主题 Topic 和分区 Partition
- 副本 Replica, Leader 和 Flower
- Offset 偏移量
- 消费者中的偏移量 Offset
- 消费者和消费者组
- 小结
Apache Kafka 是开源的分布式事件流处理平台,广泛应用于构建高性能的数据管道、流处理、数据集成等应用程序。
Apache Kafka 最初是由 LinkedIn 公司使用 Scala 开发的分布式消息引擎系统,在 2011 年的时候开源和成为了 Apache 基金会的孵化器项目,并于 2012 年 10 月毕业成为 Apache 的顶级项目。
Kafka 作为开源的高性能流处理平台,被诸多国内外的公司用于消息中间件或大数据平台。尤其是在大数据实时分析领域,一些分布式处理系统像 Spark、Flink 都与 Kafka 有着非常良好的支持,是构建大数据实时分析平台的重要组件。
学习 Kafka 是否需要学 Scala? Kafka 提供 Java、GO、Python、C++ 等多种客户端的 API,因此使用 Kafka 并不需要学习 Scala,直接使用你熟悉的语言的类库即可。
现在 Kafka 的源码是 Scala + Java(客户端) 开发的,如果想深入学习像阅读 Kafka 源码,那么建议你还是花个一两天的时间学习和了解 Scala 的语法特性以及跟 Java 8 Lambda & Stream 很像的函数式编程。
Kafka 适合哪些场景?
Kafka 是一个高吞吐量、高可用、易扩展、可持久存储、低时延的开源流处理平台,其支持如下的三个大方面的应用:
- 消息队列 MQ:实现发布/订阅的功能,解耦消息的生产者和消费者
- 流处理:Kafka Stream 是一个用来处理流式数据的类库,提供了像 join、filter 等实时流处理的功能。
- 永久存储:配置一下 Kafka 消息保存的参数后,Kafka 可以永久存储这些消息,但意义不大,应该也没有公司在实际业务中是这么使用的
消息队列 MQ
这也是 Kafka 最为人所熟知的功能,对比一些像 ActiveMQ、RabbitMQ 等一些比较老牌的消息系统,Kafka 有着更好的吞吐量、更低的时延,使用了分区、副本机制,使 Kafka 更加方便扩展和更具有容错能力。可以将 Kafka 用以构建大规模的消息处理应用。
网站用户行为分析
这是 Kafka 最早的使用案例,LinkedIn 开发 Kafka 的目的就是为了其网站用户行为的分析。用在网站上的行为(例如点击、搜索)发送到 Kafka 对应的 Topic 上,而后使用离线或者实时的处理框架对用户行为日志进行分析或者存储,用以挖掘这些数据所蕴含的商业价值。
日志收集
这可能是 Kafka 最常见的使用场景了,公司内部的诸多应用产生了许多的日志,但这些日志分布在不同的应用模块、不同的机器上,而使用 Kafka 可以方便的对日志进行低时延的全量收集。日志产生的应用只需要将一条条日志作为一个个消息发送到 Kafka 对应的 Topic,而日志处理框架像 Spark、Flink 则订阅相应的 Topic 进行实时分析或者进行存储。是构建日志生产者(业务应用)和日志消费者(日志处理应用)的数据管道的解决方案。
流处理
可以用来实时的处理像股票、银行、保险等金融交易的场景,使用 Kafka Stream 对数据进行聚合、转换、连接等操作后转换为新的 Topic 的消息供进一步处理。
Kafka 体系结构和概念
这里简要介绍 Kafka 的体系结构和主题等一些的基本术语概念。
Kafka 架构
Kafka 虽然已经发展到 2.7 版本,但其核心的架构流程却没有发生太大的变化,下图所示的就是 Kafka 的典型的架构图,也是 Kafka 消息处理流程图。
从图中可以看到 Kafka 的三个重要角色:Producer、Broker、Consumer。
- Producer 生产者:是 Kafka 消息处理的源头,生产者最重要的功能是将消息发送到 Kafka 的 Broker 服务器。Producer 此外还需要根据消息的 Topic 等确定需要发往 Broker 集群中的那个服务器。
- Consumer 消费者:是 Kafka 消息处理流程的末端,消费者的功能是从 Kafka 服务器读取消息。
- Broker 服务端:Kafka 的服务端可以一个或者若干组成的集群,负责管理接收 Producer 发来的消息和响应 Consumer 的请求等。
- Zookeeper:Zookeeper 用以存储集群的一些元数据信息,例如主题 Topic 等,还负责 Broker 集群的协调。在 0.8 之前,Zookeeper 还用于记录 Consumer Offset (也就是消费者消费到那里了),0.8 之后,则改为使用 Kafka 内置的主题 __consumer_offsets。另外,社区也在准备移除 Zookeeper 依赖。
Kafka 基本术语和概念
消息
一笔订单、一次点击或者搜索操作的日志等都可以认为是一条消息,消息是 Kafka 进行处理或者存储最小单元,其由两个主要的组成部分:
- 消息键 key:可选,如果指定了 Key,则可以通过默认或者自定义的规则将消息发到特定的分区。例如同一笔订单产生的多个消息使用 key 来发送到同一分区
- 消息体 Value:消息的主体,例如订单的详细信息、用户点击的详情信息
Kafka 消息的格式有三次的改变,分别是 V0、V1、V2,不过通常我们只需要指定 key 和 value 就够了。下图所示的是 Kafka V2 版本的消息格式的内容:
主题 Topic 和分区 Partition
主题 Topic 是 Kafka 的逻辑概念,表示一类的消息,例如业务 A 产生的消息要发到 TopicA 的主题中,业务 B 产生的发到 TopicB 中,Consumer 只需要订阅对应的 Topic 即可。简而言之,就是将各种类型的消息进行分类,给消息打个标签,像区分订单的消息还是日志的消息,不同类消息也由不同的消费者订阅消费。
既然有了 Topic 对消息进行分类,那为什么还要分区 Partition 呢?我觉得更重要的是为了扩展性和更高的吞吐量。单台机器的性能和吞吐量是有上限的,假设没有 Partition 机制,也就是只有一个 Partition,但业务系统产生的消息已经超过了单台机器的吞吐量上限,这时候就不能通过加多个机器解决问题了,因为你的 Topic 的吞吐只能通过一个机器来完成。而引入 Partition 机制,一个 Topic 可以有一个或者多个 Partition,一台机器搞不定,那就一些分区,由多台机器共同完成此 Topic 消息的处理。
实际业务中,需要根据业务吞吐量等实际情况,合理的设置 Topic 的分区数。Topic 和 Partition 也常常称为 TopicPartition 主题分区。
如下图所示,可以看到根据不同 Topic 分类信息,每个分区单独维护一个消息自增的系列,也就下文要介绍的 Offset 偏移量:(实际中 Kafka 分区的编号是从 0 开始的,这里图示从 1 开始)
副本 Replica, Leader 和 Flower
前面提到到,Kafka 使用了副本机制提升系统的容错性、稳定性等,任何一台机器都无法保障 100% 绝对可靠的运行,一旦机器发生故障,那么这台机器上的 TopicPartition 就变得不可用甚至数据完全丢失,为了避免这种情况,一个 TopicPartition 往往是设置了多个副本的,一旦某个机器发生了故障,就由另外的副本顶上继续提供服务。
一个 Partition 设置了多个副本,这些副本有两个角色 Leader 和 Flower:
- Leader 分区副本:Kafka 写入 Producer 发来消息和读取消息给 Consumer。
- Flower 分区副本:同步 Leader 分区副本的消息,并不直接对 Producer 或者 Consumer 直接提供服务,只有当 Leader 分区挂了(Rebalance 也会)之后,才有机会选举成为新 Leader 。
AR (Assigned Replicas)、ISR (In Sync Replicas):
AR 是 Kafka 一个 Partition 的所有副本的集合,包含 Leader 分区和所有的 Flower 分区。
ISR 是基本和 Leader 保持一定程度同步的副本集合,包含所有的 Leader 和基本和 Leader 保持的一定程度同步的 Flower。
一定程度同步:虽然不是跟 Leader 保持 100% 同步,但滞后的范围也在配置参数所配置的值以内。假设配置为 超过 2 条消息就认为没有保持一定程度同步,此刻 Leader 副本有 10 条,而 Flower1 同步了 8 条,Flower2 同步了 6 条,那么 Flower2 就是没有保持一定程度同步副本,是不会出现在 ISR 集合中的。
OSR (Out Sync Replicas):所有像 Flower2 没有保持一定程度同步的分区副本的集合,AR = ISR + OSR。
Offset 偏移量
Offset 偏移量是 Kafka 中一个非常重要的概念,它指的是一个分区上的自增系列,例如 0、1、2、3、4… 根据 <Topic 主题,Partition 分区号,Offset 偏移量> 三个信息可以唯一确定一个消息,也就是说每个写入 TopicPartition 的消息都有对应的 Offset。
LEO(Log End Offset) 也就是一个分区副本下一消息写入的 Offset,每个分区每个副本都单独维护一个 Offset,如下图虚框所示;
Log Start Offset:不能简称为 LSO,LSO 在 Kafka 中指的是(Log Stable Offset)一个分区副本的 Offset 的开始值,由于 Kafka 可以配置对消息进行过期删除,所以 Log Start Offset 的值也是会增大的,Log Start Offset 到 LEO 之间的值是 Kafka 一个分区副本所记录的所有消息的 Offset。
LW(Low Watermark):低水位,AR 所有分区副本中的 Log Start Offset 的最大值,也就是消费者可以消费的消息的 Offset 最小值
HW(Hight Watermark):高水位,所有 ISR 副本的 LEO 的最小值,跟 LW 类似,是消费者可以消费消息的 Offset 的最大值,即 LW 到 HW 的消息才可以被消费。
LSO(Log Stable Offset):跟 Kafka 的事务相关,是未完成事务的 Offset 的最小值,当所有的事务都已经完成后,这个值就等于 HW。
消费者中的偏移量 Offset
上文提到过,在 Kafka 0.8 之前,消费者消费到那条消息的 Offset 记录在 Zookeeper,0.8 之后的版本更改为记录在 Kafka 内部 Topic __consumer_offsets 中,消费者的便宜量的功能就是记录这个消费者消费到哪里了,当消费者宕机重启就根据这个 Offset 继续消费,不同消费者互不影响。
消费者和消费者组
消费者 Consumer 就是消费 Kafka 中的消息,那么消费者组 Consumer Group 的作用是什么呢?
上面提到过的 Kafka 的分区机制,一个 Topic 可以对应多个 Partition,那么是否可以同时使用多个消费者消费这多个消费者提高消息的处理能力呢?多个消费者同时消费某个 Topic 的多个分区时候,怎么管理各自消费到那个 Offset 了而不会发生混乱呢?
Kafka 通过消费者组来支持和管理多个消费者一起同时消费某个 Topic:
- 消费者组的成员可以新增或退出,Kafka 带有机制将分区尽量平分给消费者组的每个成员
- 一个消费者组的消费者所有成员只有一个分区的消费者进度的偏移量 Offset。
- 一个分区只能被一个消费者组的成员消费,也就是不能被两个及以上的消费者同时消费一个分区,这样子会造成消费者的 Offset 混乱;因此消费者组的成员不是越多越好。
小结
这一小节主要介绍了 Kafka 起源、一些基本术语及其概念和 Kafka 的特点与使用场景,方便大家能够快速了解 Kafka,并对 Kafka 有个初步的印象。下一小节将围绕 Kafka 的安装和使用展开,使用 Kafka 自带的命令行工具进行生产和消费“Hello World”消息,介绍一些服务端的几个常用的配置。