作者回复: A1: 不是,消费者组和队列数没有关系,你这个例子中消费者组的数量是2个。队列数量可以根据数据量和消费速度来合理配置。RocketMQ和Kafka都可以支持水平扩容队列数量,但是都需要手动操作。
A2:producer会往所有队列发消息,但不是“同一条消息每个队列都发一次”,每条消息只会往某个队列里面发送一次。
对于一个消费组,每个队列上只能串行消费,多个队列加一起就是并行消费了,并行度就是队列数量,队列数量越多并行度越大,所以水平扩展可以提升消费性能。
A3:每队列每消费组维护一个消费位置(offset),记录这个消费组在这个队列上消费到哪儿了。
作者回复: 总结的非常到位!
课后作业也完成的非常好!
小红花走起!
作者回复: A1:按照订单ID或者用户ID,用一致性哈希算法,计算出队列ID,指定队列ID发送,这样可以保证相同的订单/用户的消息总被发送到同一个队列上,就可以确保严格顺序了。
A2:会有一个超时,超时之前会阻塞,超时之后就解除锁定,允许其他消费者来拉消息,由于消费位置没变,下次再有消费者来这个队列拉消息,返回的还是上一条消息。
A3:这个问题我在后面的课中会专门来讲。
作者回复: 现代的消息队列大多就是这么实现的。
作者回复: 没错!具体可以看一下RocketMQ的并行消费的实现。
作者回复: 非常正确!
作者回复: A1:这个我没有测试过,你可以自己测试一下。
A2:有意义,比如我们通过一个主题来传输一个多库MySQL实例的binlog,这个是必须严格有序的。但是,不用真的全局有序,只要更新同一个库的操作保证有序就行了。一条更新B库和一条更新A库的Binlog,就不需要严格有序。这样我们可以以库名为key进行hash,确保同一个库的消息都路由上同一个队列上就可以了。
3. 正常情况下,多个消费组,他们的消费速度的上限就是生产速度(你消费再快也得等着消息生产出来),下限也是生产速度(否则就会出现消息积压),所以正常情况下,所有消费组的消费速度都应该和生产速度差不多。
异常情况就是有的消费组会出现消息积压,如何解决积压的问题,我们后面会专门讲到。
作者回复: A1:队列只有一份,无论有多少订阅,所以不存在你说的问题。
A2:目前的这种设计也是没办法的办法,还没有什么完美的解决方案既在topic上保证严格顺序,又要保证高性能和数据可靠性。但是目前这种实现也可以解决很多对顺序有要求的场景的问题。
A3:实际上并不是一条一条确认的,而是一批一批确认的。一般consumer取一批消息,然后确认的时候直接提交这批消息中最后一条消息的位置来确认这批消息。
作者回复: 谢谢
作者回复: 就是记录哪些消息消费了,哪些没消费。由于消费者是不记录消费位置的,它消费的时候只管去找Broker要消息,Broker必须知道消费到哪儿了,好找出下一条或下一批消息给客户端。
作者回复: consumer在某个时刻对应的是某个queue(图中的实线),consumer group 对应 topic(同样是虚线方框),我理解这张图和你的描述是一致的。
作者回复: A1:可以。
A2:有消费策略的,当然随机也是一种消费策略。
A3:不是。首先,不同的消费组,消费位置是完全独立的,互不干扰。同一个消费组内:消息队列为每个队列维护一个消费位置(而不是给消费者实例)。因为,我们关心的是整个消费组能消费到全部队列的消息就可以了,不关系组内每个消费者消费多少消息,同一条消息,给A消费消费,还是给B消费者消费,是无所谓的。
作者回复: 不是这样的,无论有多少个消费组,队列只有一份,他们(消费组)都去这个队列上读取消息,由于消费快慢不同,每个消费组都会自己维护在这个队列上的消费位置。
消费组之间是完全互不影响的。
作者回复: 第一个问题,consumer和queue不是强关联的,但是在任何一个时刻,某个queue在同一个consumer group中最多只能有一个consumer占用。
第二个问题,producer和queue不需要关联,简单点儿说,就是发到哪个queue都可以。RocketMQ的默认策略是轮询选择每个queue。
作者回复: ✅
作者回复: 不会,这部分只能慢慢消费了。
针对这种情况,RocketMQ支持开启单个队列的并行消费,可以解决你的问题。
作者回复: 消费组中某个消费者在消费一个队列的时候,其他同组的消费者是不能消费这个队列的,但是他们可以去消费同主题的其它队列,所以并不是空闲的。并且,即使是这些消费者并行消费不同的队列,在每个队列上,还是可以保证严格顺序的。
作者回复: A1:是的。
A2:我在08答疑中会详细解释这个问题,你可以看一下。
A3:这个取决于生产者的业务代码是如何编写的。
A4:有些消息队列会把这种“坏消息”放到一个特殊死信队列中,避免卡主整个队列消费。