消息拥有消息头和消息体,消息具有rounting key,主题交换机和扇形交换机都是发布与订阅的实现方式,主题交换机用于匹配接收的消息的rount key 动态匹配模式匹配到多个符合的队列,扇形fanout交换机则不会使用消息的路由key,即便在绑定队列的时候指定了Routing key,也不会有任何效果,它会向所有绑定到当前交换机的队列广播消息,该交换机绑定队列的时候所有的rounting key为空,这样所有被绑定的队列都能收到交换机的消息,实现广播功能。
当点击交换机绑定队列A的时候设置了routing key,并去队列中找到队列A,点击队列A,就会显示队列A被哪个交换机通过哪个rounting key关联。
直连交换机严格根据消息的rounting key 交给直连交换机,接收消息后应答,交换机将消息严格发送到当前绑定下的队列中的rounting key值匹配,只要匹配到交换机就向该队列投送消息,该消息只允许消费一次。
向直连交换机发送10条消息,启动两个完全相同的消费者在不同的端口上消费,每个消息只能被一个消费者消费。2只有一个消息完全处理完,方法运行结束,我们可以接收下一个消息。
RabbitMQ消息确认机制,可靠抵达,生产者发送消息到broker(可能消息丢失),broker将消息送到交换机,交换机把消息投递到队列(消息可能丢失),对列投递消息给监听的消费者
保证消息不丢失,可靠抵达,可以使用事务消息,性能下降250倍,引入确认机制解决
publisher comfirmCallBack确认模式,publisher returnCallback交换机未投递到queue就退回。
consummer ack机制,消费者只有对消息应答后队列才会正真舍弃该条消息。
可靠性抵达需要从两端入手保证,解决方式1事务(发布提交接收消费是一个完整的流程),影响性能不推荐,2可靠抵达confiemCallback 开启的方式如下:
问题:区分@RabbitListener和@RabbitHandler()的区别,使用前者要求该队列的消息的类型为统一类有多个消费者每个消息只会被一个消费者消费,@RabbitHandler()可以根据多个消费者的接收消息体的类型对象不同,特定的消息给特定的消费者消费,也就是@RabbitHandler()注解可以区分消息的内容到指定的消费者上消费,@RabbitListener在类和方法上并且指定监听的队列,@RabbitHandler()没有指定监听的队列当队列有特定的数据类型的消息时会被通道监听并投递给该消费者,也就是非作用在指定队列,监听各个队列的消息类型消费。
当启动消费者监听队列成功时,队列会将所有消息发送到消费者的通道中,此时队列消息总数是n,待确认也是n,待读取的消息0,当消费者消费一个消息时去消费第二个消息,此时队列消息总数n-1,待确认为n-1,这时消费者突然宕机停止消费,服务端队列所有的读取消息,消息总数,待应答的消息都为0,此时消息丢失。解决问题:如果是监听式消费设置开启手动消费确认机制如下
spring.rabbitmq.listener.simple.acknowledge-mode=manual
开启后启动消费之,即便每个消息都没有应答,或消费者宕机服务器上队列中的消息也不会丢失。
场景:当手动确认时有5个消息,非批量,确认2个,停止消费者,发现服务端的队列的消息全为0,消息但消息并没有丢失,消息消费的日志都打印出来,这是终断程序问题,它也会把所有消费的代码运行完成,要查看就对整除2的消息消费,剩下的消息会回退到服务端的队列中。
使用channel.basicAck(tag,是否批量)签收消息,并让队列删除消息,channel.basicNack(tag,是否批量,requeue=true) requeue=true发回服务器,服务器重新入队
1 rabbitmq的交换机类型,和交换机功能
2 rabbitMq集群模式,非主从,对等模式,生产者生产消息,会随机到一个节点上,当发现当前队列不在此节点,就会查找该队列所在的节点,并转发过去。
3 rabbitMq使用了Amqp协议,redis使用reps协议。
4 rabbitMq应用场景,异步!如传统下订单2s扣库存2s合计4s使用mq做异步主程序降小于4s处理更多请求,把请求给mq让他进行异步投送,可以减轻服务的并发压力,可以控制消费频率,实战消息削峰,解偶等功能
5 rabbitMq可以性能优化,比如从计算机层面上,设置网卡缓冲大小,减少数据包丢失的情况,可以从jvm上优化,设置合计的jvm数据区大小如xms,xmm,xmn,设置合理的垃圾回收收集器