Kafka整体概述

2020-09-03 15:32:02 浏览数 (1)

Kafka整体概述

一. 设计一个消息系统需要考虑的因素

  1. 消息设计 消息可以采用XML、JSON、二进制等各种格式来表示,Kafka采用了二进制形式。
  2. 传输协议设计 JMS、AMQP、MQTT等消息协议。Kafka自己设计了一套二进制消息传输协议。
  3. 消息传递模型
    1. P2P模型 VS Pub/Sub模型:Kafka对这两种模式都可以支持
    2. Pull模式 VS Push模式:Kafka在消费端采用了Pull模式

二. Kafka概要设计

Kafka在设计之初,就考虑了以下几个方面的问题:

  1. 吞吐量/延时 Kafka主要依靠下列 4 点达到了高吞吐量、低延时的设计目标:
    1. 大量使用操作系统页缓存,内存操作速度快且命中率高。
    2. Kafka 不直接参与物理 I/0 操作,而是交由最擅长此事的操作系统来完成。
    3. 采用追加写入方式(磁盘顺序读/写),摒弃了缓慢的磁盘随机读/写操作。
    4. 使用以 sendfile 为代表的零拷贝技术加强网络间的数据传输效率。
  2. 消息持久化 Kafka将消息以文件的形式持久化到硬盘上,这样做的好处有:
    1. 解辑消息发送与消息消费:本质上来说, Kafka 最核心的功能就是提供了生产者-消费者模式的完整解决方案。通过将消息持久化,使得生产者方不再需要直接和消费者方耦合,它只是简单地把消息生产出来井交由 Kafka 服务器保存即可,因此提升了整体的吞吐量。
    2. 实现灵活的消息处理:很多 Kafka 的下游子系统(接收 Kafka 消息的系统)都有这样 的需求一一对于已经处理过的消息可能在未来的某个时间点重新处理一次,即所谓的消息重演(message replay)。消息持久化便可以很方便地实现这样的需求 。

    另外, Kafka 实现持久化的设计也有新颖之处。普通的系统在实现持久化时可能会先尽量使用内存,当内存资源耗尽时,再一次性地把数据“刷盘”;而 Kafka 则反其道而行之, 所有数据都会立即被写入文件系统的持久化日志中,之后 Kafka 服务器才会返回结果给客户端通知它们消息已被成功写入。这样做既实时保存了数据,又减少了 Kafka 程序对于内存的消耗,从而将节省出的内存留给页缓存使用,更进一步地提升了整体性能 。

  3. 负载均衡和故障转移 Kafka 实现负载均衡实际上是通过智能化的分区领导者选举( Partition Leader Election )来实现的,可以在集群的所有机器上以均等机会分散各个Partition 的 Leader,从而整体上实现了负载均衡 。 除了负载均衡,完备的分布式系统还需要支持故障转移 。Kafka 服务器支持故障转移的方式就是使用会话机制。每台 Kafka 服务器启动后会以会话的形式把自己注册到ZooKeeper 服务器上 。一旦该服务器运转出现问题,与ZooKeeper 的会话便不能维持从而超时失效,此时 Kafka 集群会选举出另一台服务器来完全代替这台服务器继续提供服务,
  4. 伸缩性/扩展性 每台 Kafka 服务器上的状态统一交由 ZooKeeper 保管,而不是自己独立维护,这样就极大地提升了Kafka集群的可扩展性。扩展 Kafka 集群也只需要一步 :启动新的 Kafka 服务器即可 。 当然这里需要言明的是,在Kafka 服务器上并不是所有状态都不保存,它只保存了很轻量级的内部状态,因此在整个集群间维护状态一致性的代价是很低的。

总结一下,上面主要讨论了 Kafka 在吞吐量/延时、消息持久化、负载均衡/故障转移和伸缩性这 4 个方面的设计理念。正是得益于这些设计特性, Kafka 才成为了 一个完备的分布式消息引擎解决方案,赢得了广大用户的赞誉 。

三. Kafka基本概念

  1. 基本架构
  • 生产者发送消息给 Kafka 服务器。
  • 消费者从 Kafka 服务器读取消息。
  • Kafka 服务器依托 ZooKeeper 集群进行服务的协调管理 。
  1. Message Kafka消息由头部、Key和Value三个部分组成。其中最主要的字段包括:
    • Key:消息键,对消息做 Partition 时使用,即决定消息被保存在指定Topic 下的哪个 Partition中。
    • Value:消息体,保存实际的消息数据 。
    • Timestamp:消息发送时间戳,用于流式处理及其他依赖时间的处理语义。如果不指定则取当前时间 。

    Kafka 在消息设计时特意避开了繁重的 Java 堆上内存分配,直接使用紧凑二进制字节数组 ByteBuffer 而不是独立的对象,至少能够访问多一倍的可用内存。

  2. Topic & Partition 从概念上来说, Topic 只是一个逻辑概念,代表了一类消息,也可以认为是消息被发送到的地方。通常我们可以使用 Topic 来区分实际业务,比如业务 A 使用一个 Topic,业务 B 使用另外一个 Topic 。而Partition则是物理上的概念,是消息真正被存储的地方。 Topic 是由多个 Partition 组成的,而 Kafka 的 Partition 是不可修改的有序消息序列,也可以说是有序的消息日志。每个 Partition 有自己专属的 Partition 号,通常是从 0 开始的。用户对Partition 唯一能做的操作就是在消息序列的尾部追加写入消息。 Partition 上的每条消息都会被分配一个唯一的序列号一一按照 Kafka 的术语来讲,该序列号被称为位移( Offset )。该位移值是从 0 开始顺序递增的整数。位移信息可以唯一定位到某 Partition 下的一条消息。Topic和Partition的关系如下图所示:

值得一提的是, Kafka 的 Partition 实际上并没有太多的业务含义,它的引入就是单纯地为了提升系统的吞吐量,因此在创建 Kafka Topic 的时候可以根据集群实际配置设置具体的Partition 数,实现整体性能的最大化。

  1. Offset 前面说过, Topic Partition 下的每条消息都被分配一个位移值。实际上 , Kafka 消费者端也有位移(Offset)的概念,但一定要注意这两个 Offset 属于不同的概念,如下图所示:

显然,每条消息在某个 Partition 的位移是固定的,但消费该 Partition 的消费者的位移会随着消费进度不断前移,但终究不可能超过该分区最新一条消息的位移 。

综合之前说的 Topic、Partition 和 Offset,我们可以断言 Kafka 中的一条消息其实就是一个<Topic,Partition,Offset>三元组,通过该元组值我们可以在 Kafka 集群中找到唯一对应的那条消息。

  1. Replica 既然我们己知 Partition 是有序消息日志,那么一定不能只保存这一份日志,否则一旦保存 Partition 的 Kafka服务器挂掉了,其上保存的消息也就都丢失了。分布式系统必然要实现高可靠性,而目前实现的主要途径还是依靠冗余机制一一简单地说,就是备份多份日志 。 这些备份日志在 Kafka 中被称为副本( Replica ),它们存在的唯一目的就是防止数据丢失,这一点一定要记住 ! 副本分为两类 : 领导者副本( Leader Replica )和追随者副本( Follower Replica ) 。 Follower Replica 是不能提供服务给客户端的,也就是说不负责响应客户端发来的消息写入和消息消费请求。它只是被动地向领导者副本( Leader Replica )获取数据,而一旦 Leader Replica 所在的broker 宕机, Kafka 会从剩余的 Replica 中选举出新的 Leader 继续提供服务。下面我们就来看看什么是 Leader 和 Follower。
  2. Leader & Follower 如前所述, Kafka 的 Replica 分为两个角色:领导者( Leader)和追随者( Follower ) 。 如今这种角色设定几乎完全取代了过去的主备的提法( Master-Slave )。和传统主备系统(比如MySQL )不同的是,在这类 Leader-Follower 系统中通常只有 Leader 对外提供服务, Follower 只是被动地追随 Leader 的状态,保持与 Leader 的同步。 Follower 存在的唯一价值就是充当 Leader的候补:一旦 Leader 挂掉立即就会有一个Follower被选举成为新的 Leader 接替它的工作。 Kafka就是这样的设计,如下图所示:

Kafka 保证同 一个 Partition 的多个 Replica 一定不会分配在同一台 broker 上 。毕竟如果同一个 broker 上有同一个 Partition 的多个 Replica,那么将无法实现备份冗余的效果。

  1. ISR ISR 的全称是 In-Sync Replica,翻译过来就是与 Leader Replica 保持同步的 Replica 集合 。这是一个特别重要的概念。前面讲了很多关于 Kafka 的副本机制,比如一个 Partition 可以配置N个 Replica,那么这是否就意味着该 Partition 可以容忍 N-l 个 Replica 失效而不丢失数据呢?答案是“否”! Kafka 为 Partition 动态维护 一个 Replica 集合。该集合中的所有 Replica 保存的消息日志都与Leader Replica 保持同步状态。只有这个集合中的 Replica 才能被选举为 Leader,也只有该集合中所有 Replica 都接收到了同一条消息, Kafka 才会将该消息置于“己提交”状态,即认为这条消息发送成功。回到刚才的问题, Kafka 承诺只要这个集合中至少存在一个 Replica,那些“己提交”状态的消息就不会丢失一一记住这句话的两个关键点:①ISR 中至少存在一个“活着的”Replica : ② “己提交 ”消息 。有些 Kafka 用户经常抱怨:我向 Kafka 发送消息失败,然后造成数据丢失。其实这是混淆了 Kafka 的消息交付承诺( message delivery semantic) : Kafka 对于没有提交成功的消息不做任何交付保证,它只保证在 ISR 存活的情况下“己提交”的消息不会丢失。 正常情况下, Partition 的所有 Replica (含 Leader Replica )都应该与 Leader Replica 保持同 步,即所有 Replica 都在 ISR 中。因为各种各样的原因,一小部分 Replica 开始落后于 Leader Replica 的进度 。当滞后到一定程度时, Kafka 会将这些 Replica “踢”出 ISR 。相反地,当这些 Replica 重新“追上”了 Leader 的进度时 , 那么 Kafka 会将它们加回到 ISR 中。这一切都是自动维护的,不需要用户进行人工干预,因而在保证了消息交付语义的同时还简化了用户的操作成本。

四. Kafka使用场景

  1. 消息传输
  2. 网站行为日志追踪
  3. 审计数据收集
  4. 日志收集
  5. Event Sourcing
  6. 流式处理

0 人点赞