Skip to main content

为什么选择Kafka作为消息队列?

作者:程序员马丁

在线博客:https://open8gu.com

note

大话面试,技术同学面试必备的八股文小册,以精彩回答应对深度问题,助力你在面试中拿个offer。

回答话术

目前市面上比较主流的开源消息队列包括 Kafka、RocketMQ、RabbtiMQ 等,要从中选择出一个最合适的消息队列,则需要根据公司的业务,并结合功能、性能、可靠性、可用性以及社区和生态等方面进行综合考量。

从这些角度来说,Kafka 很好的满足了这些需求:

  • 功能丰富:Kafka 提供了丰富的功能,其特性包括消息堆积、可靠性、消息顺序性、幂等性和消息回溯等,可以很好的满足各种业务场景的需求。
  • 高性能:作为为大数据而生的消息队列,Kafka 在处理高吞吐量和大规模数据传输方面表现非凡,具有很高的性能表现。
  • 可靠性:Kafka 通过多副本机制保证消息的可靠性,包括生产者端、Broker 和消费者端,确保消息不丢失并提供高度的数据一致性。
  • 高可用性:Kafka 通过分区多副本机制提升容灾能力,即使集群中的某个 Broker 失效,系统仍然能够保持高可用性。
  • 社区和生态:Kafka 拥有活跃的社区和丰富的生态系统,用户可以及时获取支持和反馈,同时有大量开源运维工具和其他大数据组件对 Kafka 提供支持和集成。

image.png

问题详解

1. 功能

消息队列通常用于两个业务场景:

  • 应用解耦:在许多情况下,多个系统可能需要同一份数据。如果由发送方直接调用所有依赖系统,随着系统数量的增加,发送方代码需要频繁修改。而使用消息队列可以将发送方和接收方解耦。发送方将数据放入消息队列,依赖方根据实际需求按需进行订阅消费即可。
  • 流量削峰:传统的跨服务调用通常是实时的,即上游发起请求,下游需要立即处理并响应。然而,在某些特殊的业务场景中 —— 例如秒杀或抢购 —— 可能会出现流量激增的情况,此时下游服务可能无法承受如此大的请求量,导致大量请求失败。此时,消息队列就可以作为缓冲区来协调生产和消费速度。当下游的消费能力跟不上时,上游的消息可以暂存在消息队列中,避免直接导致下游服务崩溃。

而作为一个老牌的消息队列,Kafka 的很多特性都可以很好的支持这两种场景:

  • 消息堆积:Kafka 可以处理大量的消息堆积,适用于流量削峰场景。
  • 可靠性:Kafka 支持消息的持久化存储,并且还有着多副本机制来保证消息的可靠性,即使在节点故障的情况下也不会丢失消息。
  • 单分区消息顺序性:Kafka 保证在单个分区内消息的顺序性,适用于需要顺序处理的场景。
  • 单分区单会话的幂等:Kafka 支持生产者的幂等性,即在同一会话中,同一分区的消息即使重复发送也只会被处理一次,确保消息处理的准确性。
  • 消息回溯:Kafka 允许消费端根据需求回溯到任意时间点重新消费消息,适用于数据恢复和重新处理的场景。

2. 性能

作为一款为大数据而生的消息队列,Kafka 在处理高吞吐量和大规模数据传输方面表现非凡,它的单机 TPS 在几十万级别,而集群环境可以轻易达到百万级别。

不过,与 RabbitMQ 或 RocketMQ 相比,Kafka 其实在某些功能方面是有所欠缺的,例如 Kafka 没有死信队列和延迟消息,因此在使用时一些功能无法做到开箱即用。然而 Kafka 的性能优势可以在一定程度上弥补这些不足,毕竟虽然我们总会希望有一款消息队列功能与性能兼顾,但是有时候二者确实不可兼得,这种情况下我们还是会以性能优先。

关于 Kafka 是如何做到高性能的,具体人可参见:✅ Kafka 为什么这么快?

3. 可靠性

消息队列的可靠性通常指的是对消息不丢失的保障程度,这是消息队列最重要的指标之一。Kafka 则从生产者、Broker 和消费者三个方面一起保证了其可靠性。

3.1. 生产者

Kafka 在生产者端提供了可选的三种 ACK 策略,每种策略都对应着不同的可靠级别,我们可以根据自己的业务需要进行选择:

  • 0:生产者发送过来的数据,不需要等数据落盘应答。该方式可靠性差,效率高
  • 1(默认):生产者发送过来的数据,Leader 副本收到数据后应答(不包含 ISR 集合中的其他副本)。该方式可靠性中等,效率中等
  • -1:生产者发送过来的数据,Leader 和 ISR 集合里面的所有节点收齐数据后应答。该方式可靠性高,效率低
  • 在生产环境中,0 方式基本不用; 1 方式一般用于传输普通日志,允许丢个别数据;-1 方式一般用于对可靠性要求比较高的场景。
  • 关于 ISR 集合,你可以先简单的认为它是一个由 Leader 副本和有效 Follower 副本共同组成一个集合,具体内容可以参见:✅ Kafka 如何保证数据不丢失?

3.2. Broker

当消息到达 Broker 时,首先会存储到 Page Cache,然后通过操作系统的刷盘机制将数据持久化到硬盘上。此外,在集群环境中,Kafka 还会通过数据同步机制,将数据同步到分布在多个节点的副本中,并保证它们的一致性。这些措施都提高了消息的可靠性。

3.3. 消费者

消费者端的可靠性通过消息的 Commit 机制来保证。与生产者端一样,Kafka 也提供了两种 Commit 策略供我们根据业务场景进行选择:

  • 手动 Commit:消费者在处理完消息后再提交,从而确保消息处理的可靠性。
  • 自动 Commit 则可以简化操作,但可能在某些情况下导致消息的重复处理或丢失。

这里需要强调一下,对于 Broker 端来说,两者其实是没有区别的,这只是我们在代码里面引入的客户端提供的可选配置。

4. 高可用

可用性是指系统无故障运行的时间百分比,通常用几个 "9" 来衡量(如 99.9%、99.99%)。Kafka 通过引入分区多副本(Replica)机制提升容灾能力,从而实现高可用性。

简单来说,在集群环境下,Kafka 会为同一个分区内创建多个副本,并将这些副本分布在不同的 Broker 节点上。其中,这些副本又会分为处理所有的读写请求 Leader 副本和从 Leader 副本同步消息 Follower 副本,它们最终会在集群中形成一主多从的关系。

image.png

这种机制结合副本的故障自动转移机制,最终使得 Kafka 具有极高的容错率,即使集群中的某个 Broker 失效,系统仍然能够保持高可用性。

关于 Kafka 是如何保证高可用的,这部分内容可以参见:✅ Kafka 如何保证数据不丢失?

5. 社区和生态

良好的社区生态是选择 Kafka 的一个重要理由。一方面,Kafka 社区至今保持着比较高的活跃度,我们可以及时从社区获得支持和反馈;另一方面,作为一个老牌的开源项目,Kafka 拥有非常丰富的生态系统。

以运维工具为例,GitHub 上随便一搜就有非常多开源的 Kafka 运维或管理工具,既有 Kafka Offset Monitor 这种既轻量级的客户端,又有诸如 KafkaManager 或 KnowStreaming 这类有大厂背书的管理平台。

除了管理工具外,各种大数据组件和中间件也广泛支持 Kafka,只要它们提供了对接消息队列的功能,那基本都提供了与 Kafka 集成的解决方案。