消息队列 kafaka | 青训营笔记

42 阅读7分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 12 天

今日学习消息队列的原理与实战。主要针对零基础小白做的知识点梳理。

消息队列前世今生

消息队列(MQ)

指保存消息的一个容器,本质是个队列。但这个队列,需要支持高吞吐,高并发,并且高可用。

消息队列发展历程

  • TIB
  • IBM MQ/WebSphere
  • MSMQ
  • JMS
  • AMQP/RabbitMQ
  • Kafka
  • RocketMQ
  • Pulsar

常见消息队列对比

  • Kafka: 分布式的、分区的、多副本的日志提交服务,在高吞吐场景下发挥较为出色;
  • RocketMQ:低延迟、强一致、高性能、高可靠、万亿级容量和灵活的可扩展性,在一些实时场景中运用较广。
  • Pulsar: 是下一代云原生分布式消息流平台,集消息、存储、轻量化函数式计算为一体、采用存算分离的架构设计
  • BMQ: 和 Pulsar 架构类似存算分离,初期定位是承接高吞吐的离线业务场景,逐步替换掉对应的 Kafka 集群。

消息队列 kafka

从 kafka 使用场景,业务日志、用户行为数据、Metrics 数据展开,介绍一条消息从生产到消费的处理流程。

如何使用 Kafka

    1. 创建集群

首先需要创建一个Kafka集群。

    1. 新增 Topic

需要在这个集群中创建一个 Topic,并且设置好分片数量。

    1. 编写生产者逻辑

引入对应语言的 SDK,配置好集群和 Topic 等参数,初始化一个生产者,调用 Send 方法,将你的Hello World 发送出去。

    1. 编写消费者逻辑

引入对应语言的 SDK,配置好集群和 Topic 等参数,初始化一个消费者,调用 Poll 方法,你将收到你刚刚发送的 Hello World。

基本概念

  • Topic:

逻辑队列,不同 Topic 可以建立不同的 Topic。

可以理解成每一个不同的业务场景就是一个不同的 topic,对于这个业务来说,所有的数据都存储在这个 topic。

  • Cluster:

物理集群,每个集群中可以建立多个不同的 Topic。

每个集群中可以新建多个不同的topic。

  • Producer:

生产者,即消息的生产端。负责将业务消息发送到 Topic 中。

  • Consumer:

消费者,负责消费 Topic 中的消息。

消息的消费端,负责消费已经发送到topic中的消息。

  • ConsumerGroup:

消费者组,不同组 Consumer 消费进度互不干涉

通常 topic 会有多个分片,不同分片之间的消息是可以并发来处理的,这样提高单个 Topic 的吞吐。

image.png

Offset

Offset: 消息在 partition 内的相对位置信息,可以理解为唯一 ID,在 partition 内部严格递增。

image.png

对于每一个 Partition 来说,每一条消息都有一个唯一的 Offset,消息在 Partition内的相对位置信息,并且严格递增。

Replica

每个分片有多个 Replica,Leader Replica 将会从 ISR 中选出。

50e6d76902efce11f42f5a5bc51dbb7.png

Replica: 分片的副本,分布在不同的机器上,可用来容灾,Leader 对外服务,Fllower 异步去拉取 leader 的数据进行一个同步,如果 leader 挂掉了,可以将 Follower 提升成 leader 再对外进行服务

ISR(In-Sync-Replicas):意思是同步中的副本,对于 Follower 来说,始终和 leader 是有一定差距的,但当这个差距比较小的时候,我们就可以将这个 follower 副本加入到 ISR 中,不在 ISR 中的副本是不允许提升成 Leader 的。

数据复制

下图为 Kafka 副本的分布图。

0f276183d09d5c2140f50d2eb6b806d.png

图中,每个 Broker 代表每一个 Kafka 的节点,所有的 Broker 节点最终组成了一个集群。

即,图中整个集群,包含了 4 个 Broker 机器节点,集群有两个 Topic,分别是 Topic 1 和 Topic 2,Topic 1 有两个分片,Topic2 有 1 个分片,每个分片都是三副本的状态。

这里中间有一个 Broker 同时也扮演了 Controller 的角色,Controller 是整个集群的大脑,负责对副本和 Broker 进行分配。

数据复制问题

对于 Kafka 来说,每一个 Broker 上都有不同 topic 分区的不同副本,而每一个副本会将其数据存储到该 Kafka 节点上面。

对于不同的节点之间,通过副本直接的数据复制,来保证数据的最终一致性,与集群的高可用。

Kafka 架构

990428f2f74efc4b4c4bb8f239aa64a.png

ZooKeeper:

负责存储集群元信息,包括分区分配信息、Controller 计算好的方案等。

从一条消息视角看Kafka为啥可以支撑如此高的吞吐

Producer—生产—Broker—消费—Consumer

  • Producer: 批量发送、数据压缩;
  • Broker:顺序写,消息索引,零拷贝;
  • Consumer: Rebalance。

重启操作

如果我们对一个机器进行重启。

首先,我们会关闭一个 Broker ,此时如果该 Broker 上存在副本的 Leader,那么该副本将发生 Leader 切换,切换到其他节点上面并且在 ISR 中的 Follower 副本。

图中切换到了第二个 Broker 上面,而此时,因为数据在不断的写入,对于刚刚关闭重启的 Broker 来说,和新 Leader 之间一定会存在数据的滞后,此时这个 Broker 会追赶数据,重新加入到 ISR 当中当。

数据追赶完成之后,我们需要回切 leader,这一步叫做 prefer leader,这一步的目的是为了避免,在一个集群长期运行后,所有的leader都分布在少数节点上,导致数据的不均衡。

通过上面的一个流程分析,我们可以发现对于一个 Broker 的重启来说,需要进行数据复制,所以时间成本会比较大,比如一个节点重启需要 10 分钟,一个集群有 1000 个节点,如果该集群需要重启升级,则需要 10000 分钟,那差不多就是一个星期,这样的时间成本是非常大的。

但是可以不可以并发多台重启呀?

不可以。在一个两副本的集群中,重启了两台机器,对某一分片来进,可能两个分片都在这台机器上面,则会导致该集群处于不可用的状态。这是更不能接受的。

替换、扩容、缩容

  • 替换,和重启有什么区别?

替换,本质上来讲,就是一个需要追更多数据的重启操作,因为正常重启只需要追一小部分,而替换,则是需要复制整个 leader 的数据,时间会更长

  • 扩容

当分片分配到新的机器上以后,也是相当于要从 0 开始复制一些新的副本

  • 缩容

缩容节点上面的分片也会分片到集群中剩余节点上面,分配过去的副本也会从 0 开始去复制数 据

替换、扩容、缩容三个操作均有数据复制所带来的时间成本问题,所以对于 Kafka 来说,运维操作所带来的时间成本不容忽视。

Kafka 问题总结

  • 1. 运维成本高

    • 因为有数据复制的问题,所以 Kafka 运维的时间成本和人力成本都不低。
  • 2. 对于负载不均衡的场景,解决方案复杂

    • 对于负载不均衡的场景,我们需要有一个较为复杂的解决方案进行数据迁移,从而来权衡 IO 升高的问题。
  • 3. 没有自己的缓存,完全依赖 Page Cache

    • 除了以上两个问题以外,Kafka 自身还存在其他的问题。

    • 比如,Kafka 没有自己的缓存,在进行数据读取的时候,只有 Page Cache 可以用,所以不是很灵活

  • 4. Controller 和 Coordinator 和 Broker 在同一进程中,大量 IO 会造成其性能下降

    • Kafka 的 Controler 和 Coordinator 都是和 Broker 部署在一起的,Broker因为承载大量 IO 的原因,会导致 Controller 和 Coordinator 的性能下降,如果到一定程度,可能会影响整个集群的可用性。

拓展阅读: