理解 Kafka

文记录笔者在学习 Kafka 过程中,对 Kafka 概念理解和问题整理。

假设我们需要一个任务队列,用于处理异步任务,它大概长这样。

queue.jpg

典型的先进先出(FIFO)队列,一个生产者,一个消费者,数据消费完即移除队列。

理想情况下,生产和消费能力相当,这样一个队列就满足需求了。但是现实往往不那么理想。

这样的设计有几个问题:

  1. 消费能力跟不上生产,队列会不会变得很庞大。
  2. 第一次消费失败,没有尝试机制。
  3. 单消费者。
  4. 数据持久性问题。

实际业务处理时,以上问题都需要解决,这里还没有考虑到分布式,数据副本等情形。

基于以上的思考,我们看下 Kafka 怎么解决了这些问题。

Kafka 架构图:

kafka.png

如图所示,Kafka 支持多生产者,多Topic(主题,相当于一个独立队列),多消费者。

一些基本概念:

  • Producer 即生产者
  • Topic 主题,可以理解为消息队列
  • Partition 为 Topic 的分区,Kafka 消息的存储是按 Partion 为单位的。一个 Topic 可以指定一个或多个分区,当指定一个时就变成我们最上面设想的队列。
  • Broker 代理,消费者所消费的实例。

Kafka 数据时序性问题

Kafka Topic 数据存储时会(平均)存储在 Partition上。如图所示:

partition.png

在实际应用中,我们需要消费 Topic 时能保定时序性。而 Kafka 只能保证在分区内时序性。

至于 Topic 层面,则是不保证的。在严格要求时序的场景下,怎么办呢?

有些同学肯定想到了,一个 Topic 只设置一个 Partition 不就可以了?答案是确实可以。但是这样牺牲了可扩展性,消费者也只能一个,性能也大大折扣。

哪还有其他方法么?自然是有的。 Kafka 允许生产消息的时候指定 Key ,Kafka 会将 Key hash,同一个 Key 分配在同一个分区中。比如订单号,只要保证一个订单号都分配在同一个分区,就可以保证数据时序性。

消息重复和消费幂等

消息队列Kafka版消费的语义是at least once, 也就是至少投递一次,保证消息不丢失,但是无法保证消息不重复。在出现网络问题、客户端重启时均有可能造成少量重复消息,此时应用消费端如果对消息重复比较敏感(例如订单交易类),则应该做消息幂等。

以数据库类应用为例,常用做法是:

  • 发送消息时,传入key作为唯一流水号ID。
  • 消费消息时,判断key是否已经消费过,如果已经消费过了,则忽略,如果没消费过,则消费一次。 当然,如果应用本身对少量消息重复不敏感,则不需要做此类幂等检查。

先整理这么多,To Be Continued…

参考:

updatedupdated2021-01-212021-01-21
Load Comments?