一:如何防⽌消息丢失
防⽌消息丢失就是为了:生产者生产的消息,希望消息能够被消费者消费到
从两种角度解释:
- 消息的生产者如何保证消息尽可能的百分之百发送到kafka
- 消息的消费者如何尽可能的消费到这条消息
解决方案:
3. 生产者方:ack是1或者-1/all可以防止消息丢失,如果要做到99.9999%,ack设成all,把min.insync.replicas配置成分区备份数
>设置为1,说明leader是可以保证接收到消息了
>设置为all的话,保证leader和flower已经完成同步了
- 消费者方:把⾃动提交改成⼿动提交
总结:
-
⽣产者:
第一步:使⽤同步发送
第二步:把ack设成1或者all,并且设置同步的分区数>=2 -
消费者:把⾃动提交改成⼿动提交
二:如何防⽌重复消费
重复消费出现:生产者生产的消息同步发送到消费者,已经被leader收到了,但是由于网络问题导致生产者没有收到ACK。这时候就会重试,这时候会导致消费者拿到两条消息。不能将重试关闭,所以只能在消费者端解决幂等性问题
一条消息被消费者消费多次。如果为了消息的不重复消费,而把生产端的重试机制关闭、消费端的手动提交改成自动提交,这样反而会出现消息丢失,那么可以直接在防治消息丢失的手段上再加上消费消息时的幂等性保证,就能解决消息的重复消费问题。
幂等性如何保证
:
- mysql插入业务id作为主键,主键是唯一的,所以一次只能插入一条
- 使用redis或zk的分布式锁(主流的方案)
总结:
-
在防⽌消息丢失的⽅案中,如果⽣产者发送完消息后,因为⽹络抖动,没有收到ack,但实际上broker已经收到了。
-
此时⽣产者会进⾏重试,于是broker就会收到多条相同的消息,⽽造成消费者的重复消费。
-
解决方法:
-
⽣产者关闭重试:会造成丢消息(不建议)
-
消费者解决⾮幂等性消费问题:
所谓的幂等性:多次访问的结果是⼀样的。对于rest的请求(get(幂等)、post(⾮幂 等)、put(幂等)、delete(幂等))
-
解决⽅案:
1)在数据库中创建联合主键,防⽌相同的主键
2)创建出多条记录使⽤分布式锁,以业务id为锁。保证只有⼀条记录能够创建成功
-
三:如何做到消息的顺序消费
⽣产者:保证消息按顺序消费,且消息不丢失——使⽤同步的发送,ack设置成⾮0的值。
消费者:主题只能设置⼀个分区,消费组中只能有⼀个消费者
kafka的顺序消费使⽤场景不多,因为牺牲掉了性能,但是⽐如rocketmq在这⼀块有专⻔的 功能已设计好。
四:如何解决消息积压问题
消息积压会导致很多问题,比如磁盘被打满、生产端发消息导致kafka性能过慢,就容易出现服务雪崩,就需要有相应的手段:
- 方案一︰在一个消费者中启动多个线程,让多个线程同时消费。—―提升一个消费者的消费能力。
- 方案二︰如果方案一还不够的话,这个时候可以启动多个消费者,多个消费者部署在不同的服务器上。其实多个消费者部署在同一服务器上也可以提高消费能力——充分利用服务器的cpu资源。
- 方案三:让一个消费者去把收到的消息往另外一个topic上发.另一个topici设置多个分区和多个消费者,讲行具体的业务消费
4.1 问题出现的原因
消息的消费者的消费速度远赶不上⽣产者的⽣产消息的速度,导致kafka中有⼤量的数据没有被消费。
随着没有被消费的数据堆积越多,消费者寻址的性能会越来越差,最后导致整个kafka对外提供的服务的性能很差,从⽽造成其他服务也访问速度变慢,造成服务雪崩。
4.2 解决方法说明
1.在这个消费者中,使⽤多线程
,充分利⽤机器的性能进⾏消费消息。
2.通过业务的架构设计,提升业务层⾯消费的性能
。
3.创建多个消费组
,多个消费者,部署到其他机器上,⼀起消费,提⾼消费者的消费速度
4.创建⼀个消费者,该消费者在kafka另建⼀个主题,配上多个分区,多个分区再配上多个消费者。该消费者将poll下来的消息,不进⾏消费,直接转发到新建的主题上
。此时,新的主题的多个分区的多个消费者就开始⼀起消费了。——不常⽤
五:实现延时队列
5.1 场景
订单创建后,超过30分钟没有⽀付,则需要取消订单,这种场景可以通过延时队列来实现
5.2 方案
图例说明:
- kafka中创建创建相应的主题
- 消费者消费该主题的消息(轮询)
- 消费者消费消息时判断消息的创建时间和当前时间是否超过30分钟(前提是订单没⽀付)
- 如果是:去数据库中修改订单状态为已取消
- 如果否:记录当前消息的offset,并不再继续消费之后的消息。等待1分钟后,再次向kafka拉取该offset及之后的消息,继续进⾏判断,以此反复。