时长:大小13.97M
作者回复: 没毛病,很多底层的方法和技术就是通用的
作者回复: 两个消费者先后去拉消息是否能拉到同一条消息?
首先,消息队列一般都会有协调机制,不会让这种情况出现,但是由于网络不确定性,这种情况还是在极小概率下会出现的。
在同一个消费组内,A消费者拉走了index=10的这条消息,还没返回确认,这时候这个分区的消费位置还是10,B消费者来拉消息,可能有2种情况:
1. 超时前,Broker认为这个分区还被A占用着,会拒绝B的请求。
2. 超时后,Broker认为A已经超时没返回,这次消费失败,当前消费位置还是10,B再来拉消息,会给它返回10这条消息。
作者回复: 是的。
rocketmq为了解决这个问题,增加了一个死信队列,对于这种反复投递都无法成功的消息,会被移动到死信队列中,避免卡住其他消息。
作者回复: Broker不知道ack有没有送达到producer,它也不管是不是送达了。
因为,这个阶段的消息可靠性是由producer来保证的,它发了消息,收到了ack,那消息就一定送达了。如果没收到ack,那消息有可能送达了(ack丢失),也有可能没送达(消息丢失),对于这种情况,producer一般会重发消息,确保消息送达。这也就是为什么消息会有重复的原因之一。
作者回复: 你这个例子中,最终一致性应该是指:“经过一段时间后,订单状态和优惠券状态最终会保持一致。”
但是,你这个场景不太适合使用事务消息来解决,虽然和我们上节课中的例子相比,只是把购物车换成了优惠券。但你有没有考虑到,有人会恶意利用这个短暂的不一致时间来刷优惠券?比如,利用下单成功,但优惠券还没来得及扣减这个时间差,一个优惠券反复下单?
作者回复: 不用加餐,这是教学大纲内的内容,下节课就会讲到滴。
作者回复: 放到私信队列中,人工处理。
作者回复: 不用,Producer发消息的时候带着ProducerId并要指定分区发送,Consumer消费的时候,需要按照每个Producer来检查序号的连续性。
作者回复: 思路是没问题的。
作者回复: 非常好!但你需要考虑一下,在分布式环境中“Consumer接受消息前判断是否有相同标识的消息”该如何实现呢?
作者回复: 这个总结非常到位!
作者回复: 你这结论都是用无数bug换来的呀。
作者回复: 。如果Broker是集群模式,其他的Broker会替代宕机的Broker来继续进行反查。如果Broker是单节点,只能等到Broker恢复后再继续进行反查。无论哪种模式,消息不会丢,是保存在磁盘上的。
作者回复: A1: 关于第一个问题,你可以看一下“08疑难解答”这节课,里面有专门的一个小结来讲如何用消息队列实现严格顺序。
A2:你的理解是正确的。关于参数配置,只要你明白了收发消息的原理,再去看一下配置的说明,应该很容易就理解了。每个消息队列的文档中,都会有专门的一篇文档,列出所有的配置以及每个配置的含义,你可以参考。
A3:自动提交或者手动提交不是关键问题,关键的问题就是“先执行消费逻辑,再提交消费确认”。比如,RocketMQ Consumer的OnMessage方法,它会在成功执行完这个方法后提交消费确认,如果抛出异常就不会提交消费确认。你只要在这个方法中执行你的消费逻辑,消费错误的时候抛出异常,即使自动提交也能保证我们说的“先执行消费逻辑,再提交消费确认”。
作者回复: 一般来说,消费都是采用pull的模式,消费者主动去broker来拉消息,如果消费者返回ack,Broker就会更新消费位置,如果消费者不返回ack,broker就什么都不做,直到下次消费者再来拉消息,因为消费位置没有更新,所以拉到的还是之前的那批消息,这样就实现了“重试”的效果。
在kafka中,消费位置都是用户代码来手动提交消费位置,所以,也就不存在“消费端消费时抛异常后,卡夫卡处理的”的问题,因为这完全取决于你的代码如何来编写了。
作者回复: 且听下回分解。
作者回复: 增加一个服务也不能解决这个问题,如果调用这个服务失败了怎么办?所以理论上,这个问题是无解的。
实际生产中,还是靠发送方检查发消息的响应来确认消息是否发成功了,并且,还要决定发失败的消息该如何处理。
比如,某些监控类应用,可以把发失败的消息直接丢掉。
再比如,重要的订单类的应用,他们会做多重的降级方案,一般建二个topic,第一个发失败了,换第二个发,再发失败了写数据库。