文章目录

  • 发布-订阅模型、Kafka 消息模型
  • Kafka 架构和名词概念
  • Kafka 的多分区(Partition)以及多副本(Replica)机制有什么好处呢
  • Zookeeper 在 Kafka 中的作用
  • Kafka 如何保证消息的消费顺序
  • Kafka 如何保证消息不丢失
  • Kafka 如何保证消息不重复消费
  • Kafka 中的 ISR(InSyncRepli)、OSR(OutSyncRepli)、AR(AllRepli)代表什么
  • Kafka 中的 HW、LEO 等分别代表什么
  • Kafka 消息重复的场景及解决方案


发布-订阅模型、Kafka 消息模型

kafka多个消费者不同topic kafka 消费者组多个topic_重启

Kafka 架构和名词概念

Kafka 将⽣产者发布的消息发送到 Topic(主题) 中,需要这些消息的消费者可以订阅这些

Topic(主题)。

kafka多个消费者不同topic kafka 消费者组多个topic_重启_02

  • Producer (生产者): 向 kafka broker 发消息的客户端。
  • Consumer(消费者) : 向 kafka broker 取消息的客户端。
  • Consumer Group (消费者组): 消费者组,由多个 consumer 组成。消费者组内每个消费者负
    责消费不同分区的数据,一个分区只能由一个组内消费者消费;消费者组之间互不影响。所
    有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。
  • Broker : 一台 kafka 服务器就是一个 broker。一个集群由多个 broker 组成。一个 broker
    可以容纳多个 topic。
  • Topic(主题): Producer 将消息发送到特定的主题,Consumer 通过订阅特定的 Topic(主题) 来消费消息。
  • Partition(分区): Partition 属于 Topic 的⼀部分。⼀个 Topic 可以有多个 Partition ,并且
    同⼀ Topic 下的 Partition 可以分布在不同的 Broker 上。每个 partition 是一个有序的队列。
  • Replica(副本): 为保证集群中的某个节点发生故障时,该节点上的 partition 数据不丢失,且 kafka 仍然能够继续工作,kafka 提供了副本机制,一个 topic 的每个分区都有若干个副本,
    一个 leader 和若干个 follower。
  • leader(主): 每个分区多个副本的主,生产者发送数据的对象,以及消费者消费数据的对
    象都是 leader。
  • follower(从): 每个分区多个副本中的从,实时从 leader 中同步数据,保持和 leader 数据
    的同步。leader 发生故障时,某个 follower 会成为新的 follower。

Kafka 的多分区(Partition)以及多副本(Replica)机制有什么好处呢

分区的好处: 1、方便在集群中扩展,2、可以提高并发

  • Kafka 通过给特定 Topic 指定多个 Partition,⽽各个 Partition 可以分布在不同的 Broker 上,通过增加消费者个数来负责消费不同分区的数据,这样便能提供比较好的并发能力(负载均衡)。
  • Partition 可以指定对应的 Replica 数,这也极⼤地提⾼了消息存储的安全性,提⾼了容灾能力,不过也相应的增加了所需要的存储空间。

Zookeeper 在 Kafka 中的作用

ZooKeeper 维护了一个类似文件系统的数据结构,主要是用来解决分布式应用中经常遇到的一些数据管理问题,进行管理集群和协调分布式服务。
ZooKeeper 主要为 Kafka 提供元数据的管理的功能。
比如:Broker 注册信息;Topic 注册信息,Topic 分区信息及与 Broker 的对应关系也都是由 Zookeeper 在维护。

Kafka 如何保证消息的消费顺序

Kafka 中 Partition(分区)是真正保存消息的地⽅,发送的消息都被放在了这⾥。
Kafka 通过偏移量(offset)可以保证消息在分区内的顺序性。
而我们的 Partition(分区) 又存在于 Topic(主题) 这个概念中,并且我们可以给特定 Topic 指定多个Partition。
每次添加消息到 Partition(分区) 的时候都会采⽤尾加法,消息在被追加到 Partition(分区)的时候都会分配⼀个特定的偏移量(offset),Kafka 通过偏移量(offset)来保证消息在分区内的顺序性。
所以 Kafka 只能为我们保证Partition(分区) 中的消息有序,而不能保证 Topic(主题) 中的 Partition(分区) 的有序。

Kafka 中发送 1 条消息的时候,可以指定 topic,partition,key,data(数据) 4 个参数。
如果你发送消息的时候指定了 Partition 的话,所有消息都会被发送到指定的 Partition。并且,同⼀个 key 的消息可以保证只发送到同⼀个 partition,这个我们可以采⽤表/对象的 id 来作为 key 。

对于如何保证 Kafka 中消息消费的顺序,有了下⾯两种⽅法:

  • 1 个 Topic 只对应⼀个 Partition。
  • (推荐)发送消息的时候指定 key/Partition。

Kafka 如何保证消息不丢失

生产端怎么保证:
Kafka 为分区引入了多副本机制。分区中的多个副本之间会有一个叫做leader,其他副本称为follower。
发送的消息是被leader接收的,然后同步到follower,副本的存在是为了保证消息不丢失。
有一种情况:假如 leader 副本所在的 broker 突然挂掉,那么就要从 follower 副本重新选出一个 leader,但是 leader 的数据还有一些没有被 follower 副本同步的话,就会造成消息的丢失。
解决办法就是设置 acks = all ,acks 默认值为 1 ,代表消息被 leader 副本接收之后就算被成功发送。acks = all 代表所有副本都要接收到该消息之后才算真正成功发送。

消费端怎么保证:
如果设置了消费者拿到数据就自动提交 offset ,此时提交完成后,重启了,消费者还没来得及处理,消息就丢失了,因为重启后从新的 offset 消费了;可以设置手动提交 offset,在处理完数据后提交 offset,可能出现重复数据,处理完数据,提交 offset 之前重启了,重启后会从旧的 offset 消费,导致消费了重复的数据,这时需要在消费端处理下重复数据的。

Kafka 如何保证消息不重复消费

kafka自带的消费机制:
kafka有个offset的概念,当每个消息被写进去后,都有一个offset,代表他的序号,然后consumer消费该数据之后,隔一段时间,会把自己消费过的消息的offset提交一下,代表我已经消费过了。下次我要是重启,就会继续从上次消费到的offset来继续消费。
但是当我们直接kill进程了,再重启。这会导致consumer有些消息处理了,但是没来得及提交offset。等重启之后,少数消息就会再次消费一次。
其他MQ也会有这种重复消费的问题,那么针对这种问题,我们需要从业务角度,考虑它的幂等性。

通过保证消息队列消费的幂等性来保证:
举个例子,当消费一条消息时就往数据库插入一条数据。如何保证重复消费也插入一条数据呢?
那么我们就需要从幂等性角度考虑了。幂等性,我通俗点说,就一个数据,或者一个请求,无论来多次,对应的数据都不会改变的,不能出错。

怎么保证消息队列消费的幂等性?
我们需要结合业务来思考,比如下面的例子:
1、比如某个数据要写库,你先根据主键查一下,如果数据有了,就别插入了,update一下好吧
2、比如你是写redis,那没问题了,反正每次都是set,天然幂等性
3、对于消息,我们可以建个表(专门存储消息消费记录)

生产者,发送消息前判断库中是否有记录(有记录说明已发送),没有记录,先入库,状态为待消费,然后发送消息并把主键id带上。
消费者,接收消息,通过主键ID查询记录表,判断消息状态是否已消费。若没消费过,则处理消息,处理完后,更新消息记录的状态为已消费。

https://zhuanlan.zhihu.com/p/141720058

Kafka 中的 ISR(InSyncRepli)、OSR(OutSyncRepli)、AR(AllRepli)代表什么

为了保证消息可靠性。

在Kafka中维护了一个AR列表,包括所有的分区的副本。AR又分为ISR和OSR。

最开始所有的副本都在ISR中,在kafka工作的过程中,如果某个副本同步速度慢 replica.lag.time.max.ms指定的阈值,则被踢出ISR存入OSR,如果后续速度恢复可以回到ISR中。

kafka多个消费者不同topic kafka 消费者组多个topic_kafka多个消费者不同topic_03


ISR: Leader 维护了一个动态的 in-sync replica set (ISR),和 leader 保持同步的 follower 集合。当 ISR 中的 follower 完成数据的同步之后,leader 就会给 follower 发送 ack。如果 follower长时间未向 leader 同步数据, 则该 follower 将被踢出 ISR,Leader 发生故障之后,就会从 ISR 中选举新的 leader。

ack 应答机制:

  • 0:producer 不等待 broker 的 ack,延迟最低,broker 接收到消息还没有写入磁盘就返回ack确认收到,broker 故障时会丢失数据。
  • 1:partition 的 leader 落盘成功后返回 ack,如果在 follower 同步成功之前 leader 故障,那么将会丢失数据。
  • -1(all):partition 的 leader 和 follower 全部落盘成功后才返回 ack。但是如果在 follower 同步完成后,broker 发送 ack 之前,leader 发生故障,那么会造成数据重复。

Kafka 中的 HW、LEO 等分别代表什么

Kafka 消息重复的场景及解决方案

生产者阶段:
生产发送的消息没有收到正确的 broke 响应,导致生产者重试。
如果 acks 参数设置为-1或all,表示需要等所有副本落盘后 broker 成功才返回 ack,如果在 follower 同步成功完成后,broker 发送 ack 之前, leader 故障了,会导致生产者重试发送消息,造成重复数据。
消费者阶段:
消费者处理完消息后,因为 Kafka 消费者还没来得及提交 offset 就重启了,等消费者重新启动后,会拿之前记录的offset开始消费,导致重复消费。
解决思路:
1、如果消息数据要写库,首先根据主键查一下,如果这个数据已经有了,那就别插入了,执行update即可。
2、如果用的是 Redis,那就没问题了,因为每次都是set操作,天然的幂等性。
3、让生产者发送每条消息的时候,加一个全局唯一的 ID,然后你这里消费到了之后,先根据这个 ID 去 Redis 中查找,之前消费过了么,如果没有消费过,那就进行处理,然后把这个 ID 写入到 Redis中,如果消费过了,那就别处理了,保证别重复消费相同的消息即可。
4、基于数据库唯一键来保证重复数据不会重复插入多条,将 ID 字段在数据库中设置为唯一索引,进行插入的时候,因为有了唯一键约束了,所以重复数据只会插入报错,不会导致数据库中出现脏数据。

方案一: 保存并查询
给每个消息都设置一个独一无二的 key,消费的时候把 key 记录下来。
然后每次消费新的消息的时候都查询一下,看当前消息的这个 key 是否消费过,如果没有消费过才进行消费。

方案二: 利用幂等
接收到消息后,首先通过唯一值查询数据,是否存在消息,如果存在,不作消费。
如果不存在,将消息保存到数据库,消息中的唯一值单独作为一个唯一值字段,然后进行消费消息。

如果是是消费消息进行数据入库的。
比如保单入库,生成保单号根据消息的唯一值规则生成一个保单号,不要根据当前时间,因为同一个唯一值生成的结果是一样的,这样的话,就可以先生成保单号,通过保单号查询是否存在数据,如果存在的话,把数据返回,不存在就进行入库操作。