Kafka源码分析
,还剩很多没肝完。之前还存着RocketMQ源码分析
还没整理。今儿暂时先跳出来盘一盘大方向上的消息队列有哪些核心注意点。-
如何保证消息不丢失? -
如何处理重复消息? -
如何保证消息的有序性? -
如何处理消息堆积?
什么是消息队列
In computer science, message queues and mailboxes are software-engineering components typically used for inter-process communication (IPC), or for inter-thread communication within the same process. They use a queue for messaging – the passing of control or of content. Group communication systems provide similar kinds of functionality.
为什么需要消息队列
异步处理
服务解耦
流量控制
注意
消息队列基本概念
队列模型
发布/订阅模型
Topic
即主题中,所有订阅了这个 Topic
的订阅者都能消费这条消息。RabbitMQ
就是采用队列模型,通过 Exchange
模块来将消息发送至多个队列,解决一条消息需要被多个消费者消费问题。小结一下
RabbitMQ
采用队列模型,RocketMQ
和Kafka
采用发布/订阅模型。常用术语
Producer
,接受消费消息方为消费者Consumer
,消息队列服务端为Broker
。Producer
发往Broker
,Broker
将消息存储至本地,然后Consumer
从Broker
拉取消息,或者Broker
推送消息至Consumer
,最后消费。RocketMQ
中叫队列,Kafka
叫分区,本质一样。key hash
取余等策略来将同一个主题的消息分配到不同的队列中。Consumer Group
, 即消费者都是属于某个消费组的。一条消息会发往多个订阅了这个主题的消费组。Group 1
和 Group 2
,它们都订阅了Topic-a
。此时有一条消息发往Topic-a
,那么这两个消费组都能接收到这条消息。Topic
某个队列中,消费组中的某个消费者对应消费一个队列的消息。Broker
中只会有一份,每个消费组会有自己的offset
即消费点位来标识消费到的位置。在消费点位之前的消息表明已经消费过了。当然这个offset
是队列级别的。每个消费组都会维护订阅的Topic
下的每个队列的offset
。如何保证消息不丢失
生产消息
Broker
,需要处理Broker
的响应,不论是同步还是异步发送消息,同步和异步回调都需要做好try-catch
,妥善的处理响应,如果Broker
返回写入失败等错误消息,需要重试发送。当多次发送失败需要作报警,日志记录等。存储消息
Broker
是集群部署,有多副本机制,即消息不仅仅要写入当前Broker
,还需要写入副本机中。那配置成至少写入两台机子后再给生产者响应。这样基本上就能保证存储的可靠了。一台挂了还有一台还在呢(假如怕两台都挂了..那就再多些)。消费消息
Broker
消费成功,这是不对的。Broker
消费成功,这才是真正的消费了。Broker
响应,那么消费阶段消息就不会丢失。小结一下
生产者
需要处理好Broker
的响应,出错情况下利用重试、报警等手段。Broker
需要控制响应的时机,单机情况下是消息刷盘后返回响应,集群多副本情况下,即发送至两个副本及以上的情况下再返回响应。消费者
需要在执行完真正的业务逻辑之后再返回响应给Broker
。如果处理重复消息
Broker
的响应,那么我们发往Broker
是不会重复的。Broker
上,那就得等Broker
的响应,那么就可能存在Broker
已经写入了,当时响应由于网络原因生产者没有收到,然后生产者又重发了一次,此时消息就重复了。Consumer offset
了,然后这个消费者挂了,另一个消费者顶上,此时Consumer offset
还没更新,于是又拿到刚才那条消息,业务又被执行了一遍。于是消息又重复了。幂等处理重复消息
update t1 set money = 150 where id = 1 and money = 100;
执行多少遍money
都是150,这就叫幂等。money = 100
情况,并且直接修改,更通用的是做个version
即版本号控制,对比消息中的版本号和数据库中的版本号。insert into update on duplicate key...
。如何保证消息的有序性
全局有序
Topic
发送消息,并且一个Topic
内部只能有一个队列(分区)。消费者也必须是单线程消费这个队列。这样的消息就是全局有序的!MySQL Binlog
也只需要保证单表消息有序即可。部分有序
Topic
内部划分成我们需要的队列数,把消息通过特定的策略发往固定的队列中,然后每个队列对应一个单线程处理的消费者。这样即完成了部分有序的需求,又可以通过队列数量的并发来提高消息处理效率。如果处理消息堆积
bug
则处理 bug
,如果是因为本身消费能力较弱,我们可以优化下消费逻辑,比如之前是一条一条消息消费处理的,这次我们批量处理,比如数据库的插入,一条一条插和批量插效率是不一样的。Topic
的队列数和消费者数量,注意队列数一定要增加,不然新增加的消费者是没东西消费的。一个Topic中,一个队列只会分配给一个消费者。Broker
,然后多线程向内存队列消费消息,假设此时消费者宕机了,内存队列里面还未消费的消息也就丢了。最后
Kafka
的源码分析文章,有兴趣的小伙伴请耐心等待。如果看到这里,说明你喜欢这篇文章,请 转发、点赞。同时 标星(置顶)本公众号可以第一时间接受到博文推送。
文末福利:我准备了一份 166 页的 Java 面试题库,高清 PDF 版本,涵盖了 7 大模块,涵盖常见、重点的面试题目。图文并茂,源码解释,喜欢的文末下载。
下载方式
1. 首先扫描下方二维码
2. 关注后,自动推送下载链接
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论