kafka 生产者消费者设计思考

生产者

负载均衡

生产者直接发送消息给分区leader,而不需要通过中间者进行转发。

这意味着生产者需要知道哪些服务器是存活的,以及主题分区leader在哪里的元数据请求。同时这也意味着生产者可以根据情况决定发给哪个broker,那么既可以随机负载,也可以进行散列

批量发送

生产者会尝试收集数据,然后在单次请求中发送大量数据,以牺牲少量额外延迟来换取更好的吞吐量。

消费者

push or pull?

kafka选择了pull。这是因为基于push的系统由broker控制着数据传输的速率,尽可能使消费者更快消费,但是如果消费者消费速度远低于生产速度,那这就成为一种拒绝服务攻击了。而消费者pull则能很好根据实际情况去pull消费,消费快就快pull,消费慢就慢pull

不过pull也会陷入轮询的陷阱。为了解决这种问题,kafka在pull request中设置参数使允许堵塞在长轮询中,直到数据到达

消费到哪里了?

确定消费到哪里了,并不是一个简单的问题。如果broker在发送消息后,立刻认为消息已经被消费了,那么在传输未到达等原因引发的消费未处理情况会使得这样的认为并不正确

如果采用消费者ack的模式,也就是消费者消费完成之后发送确定消息,那么如果消费者在发送ack的时候也失败了,这就会导致重复消费问题。此外,对每个消息进行状态维护也会对性能造成影响

为了避免这些问题,kafka将消息划分到有序的分区中,那么只要记录每个分区被每个消费者组消费数据即可。并且还可以支持回退到之前被消费的消息,以允许重复消费

那么kafka是如何解决重复消费的问题的呢?很可惜,kafka最多只能支撑生产者不发送重复的消息,如果是上述场景中消费者没有ack成功导致的重复消费,还是要进行额外幂等处理的

消息传递机制

  • 至多一次:消息可能会丢失,并永远不会重新传递
  • 至少一次:消息不会丢失,但可能被重新传递
  • 只有一次:每个消息仅传递一次,既不会丢失,也不会重复

kafka支持生产者若没有收到ack,能重新发送消息,这样能保证至少一次的传递机制。并且还添加了(0.11.0.0之后)幂等,也就保证重发不会出现重复条目。

此外还提供了一个"事务",也就是支持发送消息到多个topic partitions的能力,要么都写入成功,要么都不成功

实现幂等的方法是为每个生产者分配id,并采用生产者发送的序列号去去重

从消费者角度来说,当消费者控制消息处理位置

  • 读取消息后,更新已处理,最后处理消息。

    这保证了至多一次。但如果消费者在消费失败后,反馈消费失败之前宕机,那么就会导致存在消息没有被消费

  • 读取消息后,处理消息,最后更新已处理。

    保证了至少一次。如果在消费成功之后宕机,那么将会重复收到已经处理过的消息

为了达成只有一次的情况,我们可以利用kafka事务功能,在事务被中止之后将消费者处理位置恢复到之前

Ref

  1. https://kafka.apache.org/documentation/#theproducer
相关推荐
Albert Edison6 分钟前
【RabbitMQ】RPC 通信(使用案例)
分布式·rpc·rabbitmq
天下财经热25 分钟前
2026年4月分布式工商业光伏建设企业技术解析!
分布式
梵得儿SHI35 分钟前
SpringCloud 进阶拓展:分布式事务终极解决方案 Seata AT/TCC 模式全栈实战(含生产级避坑指南)
分布式·spring·spring cloud·seata·分布式事务·tcc·tc集群部署
XMYX-044 分钟前
从一次 Kafka 启动失败,深挖本地服务间通信的“隐形陷阱”
kafka
喜欢流萤吖~2 小时前
分布式事务:微服务的数据一致性之困
分布式·微服务·架构
面向Google编程17 小时前
从零学习Kafka:生产者分区机制
大数据·kafka
Jackeyzhe17 小时前
从零学习Kafka:生产者分区机制
kafka
大G的笔记本19 小时前
分布式事务
分布式
weixin_4196583119 小时前
RabbitMQ 的高级特性
java·分布式·rabbitmq
_F_y20 小时前
仿RabbitMQ实现消息队列-服务端核心模块实现(1)
分布式·rabbitmq