为什么要使用消息队列?
1.解耦
2.异步
3.削峰
怎么提高系统性能的?
在不使用消息队列的时候,用户的请求直接写入数据库,在高并发的情况下数据库压力剧增,使得响应速度变慢。但是在使用消息队列后,用户的请求数据发送给消息队列之后立即返回,再由消息队列的消费者进程从消息队列中获取数据,异步写入数据库。由于消息队列服务器处理速度快于数据库(消息队列也比数据库有更好的伸缩性),因此响应速度得到大幅度改善。所以,消息队列具有很好的削峰作用的功能——通过异步处理,将短时间高并发产生的事务消息存储在消息队列中,从而削平高峰期的并发事务
怎么降低系统耦合性?
模块间不存在直接调用,那么新增模块或者修改模块就对其他模块影响较小,这样系统的可扩展性无疑会更好一些。生产者发送消息到消息队列中去,接受者处理消息,需要消费的系统直接去消息队列去消息进行消费即可不需要和其他系统有耦合,显然提高了系统的扩展性
消息队列使用发布——订阅模式工作,消息发送者发布消息,一个或多个消费者订阅消息,这样消费者和发送者就没有直接耦合,对于新增业务,只要对该类消息感兴趣,即可订阅该消息,对原油系统没有任何影响,从而实现业务的可扩展性设计
消息队列的可靠性?
1.发送端的可靠性: 生产者开启confirm模式,这样的话每次写的消息都会分配唯一的id,如果写入了rabbitmq中就会回传一个ack信息,如果写入失败,那么会回调nack接口告诉生产者消息接收失败。
2.rabbitmq的可靠性: rabbitmq开启持久化,将消息写入后会持久化到磁盘,这样的话即使rabbitmq自己挂掉,恢复之后也能够重建队列和交换机,再将持久化日志文件中的消息发送给对应的队列。但是可能会出现没来得及持久化rabbitmq就挂掉的情况,为了解决这个问题我们可以将rabbitmq的持久化和生产者的confirm机制配合起来,只有消息被rabbitmq持久化到磁盘上时才回传给生产者一个ack信号。这样就算出现了刚才的问题生产者收不到ack就可以自己在重新发送
3.接收端的可靠性:关闭rabbitmq的自动ack。当接收端处理完成后再返回一个ack。这样的话如果rabbitmq没有收到ack,那么久可以将消息交给其他消费者去处理
消息队列的问题:
1)系统可用性降低:在引入消息队列之前,不用考虑消息丢失,引入之后要考虑
2)系统复杂性提高: 需要保证消息没有被重复消费,处理,消息丢失的情况
3)一致性问题: 如果真正消费者没有正确消费信息,这样就会导致数据不一致
AMQP
一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计,兼容JMS
为什么使用rabbitMQ?
1)在分布式系统下具备异步,削峰,负载均衡等一系列高级功能
2)具有持久化的机制,进程消息,队列中的消息也可以保存下来
3)实现消费者和生产者之间的解耦
4)对于高并发场景下,利用消息队列可以使得同步访问变为串行访问达到一定量的限流,利于数据库的操作
5)可以使用消息队列达到异步下单的效果
rabbitMQ的使用场景
1)服务间异步通信
2)顺序消费
3)定时任务
4)请求削峰
怎么确保消息正确地发送至rabbitMQ如何确保消息接收方消费了消息?
1)发送发确认模式
将信道设置成confirm模式,一旦消息被投递到目的队列后,信道会发送一个确认给生产者,如果消息丢失,则会发送nack消息
2)接收方确认机制
消费者接受每一条消息后都必须进行确认,只有消费者确认了后,rabbitMQ才能安全地把消息从队列中删除
如何避免消息重复投递或重复消费?
1)消息生产时,MQ内部对每条消息生成一个inner-msg-id,作为去重的依据,避免重复的消息进入队列
2)在消息消费时,要求消息体中必须要有一个唯一id作为去重的依据,避免同一条消息被重复消费
消息基于什么传输?
由于tcp连接的创建和销毁开销较大,且并发数受系统资源限制,会造成性能瓶颈,rabbiMQ使用信道的方式来传输数据。信道是建立在真实的tcp连接内的虚拟连接,且没有tcp连接上的信道数量没有限制
rabbitmq的三种常用路由?
1.direct:这种模式下,交换机根据routingkey进行完全匹配,匹配失败则丢弃消息
2.fanout:这种模式会完全忽略掉路由键,只要向交换机中发送消息,就会广播给与交换机绑定的所有消息队列
3.top: 这种模式可以和路由键进行模糊匹配,如果失败则丢弃消息,如果匹配多个结果,则向多个结果都发消息
如何确保消息不会丢失?
消息持久化(前提是队列持久化)
rabbitMQ确保持久性消息能够从服务器重启中恢复的方式是:当发布一条持久化消息到交换机上时,rabbitMQ会在把消息提交给持久化日志文件后才会给生产者发送ack信号。一旦消费者从持久队列中消费了一条持久化消息,rabbitMQ会在持久化日志中将这条消息删除。如果持久化消息在被消费之前rabbitMQ重启,那么rabbit会自动重建交换器和队列,并重新发布持久化日志文件中的消息到合适的队列
rabbitmq的高可用?
镜像集群模式:每个rabbitmq节点上都有queue的完整镜像,每次写消息到queue时,都会自动同步到多个实例的queue上。具体实现就是在后台新增一个策略,是镜像集群模式的策略,可以要求所有数据同步到所有节点,也可以指定要同步的节点,再次创建queue的时候,应用这个策略,就会自动同步到其他的节点上去了。
有几百万消息持续积压几个小时怎么办?
对consumer进行临时扩容
停掉现在的consumer,新建topic,partition为原来的很多倍,然后建立更多的消息队列,再新写一个consumer,用来消费积压的数量,只不过这个consumer消费完一条消息后就立即进行轮询,然后用更多的机器来部署consumer,也就是将queue和consumer的数量增大,以此来增加对消息的消费速度,处理完积压的消息后再恢复原来的consumer和queue
消息队列中如果回调放入消息队列时网络抖动丢包怎么办?
第一种方法:在生产者发送数据之前开启事务,然后再发送消息,如果消息没有被rabbitmq接收到,那么生产者会收到异常报错,这个时候回滚事务,然后重试发送消息
第二种方法:开启confirm模式,这样的话每次发送消息都会分配一个唯一的id,如果发送到了rabbitMQ,那么rabbitMQ会回传一个ack消息,如果这里发送失败,比如网络抖动丢包了,那么rabbitMQ会回调一个nack接口,告诉生产者发送失败
这两种方法不同之处在于:事务机制是同步的,提交一个事务会阻塞在那儿,但是confirm是异步的,发送一个消息后可以发送下一个消息