一 MQ优点
1.解耦,系统A在代码中直接调用系统B和系统C的代码,若是未来D系统接入,系统A还须要修改代码,过于麻烦!java
2.异步,将消息写入消息队列,非必要的业务逻辑以异步的方式运行,加快响应速度面试
3.削峰,并发量大的时候,全部的请求直接怼到数据库,形成数据库链接异常redis
二 MQ缺点
1.系统可用性下降。你想啊,原本其余系统只要运行好好的,那你的系统就是正常的。如今你非要加个消息队列进去,那消息队列挂了,你的系统不是呵呵了。所以,系统可用性下降数据库
2.系统复杂性增长。要多考虑不少方面的问题,好比一致性问题、如何保证消息不被重复消费,如何保证保证消息可靠传输。所以,须要考虑的东西更多,系统复杂性增大。架构
三 如何保证消息队列是高可用的
使用集群的方式维持MQ的可高用性。
四 如何保证消息不被重复消费
保证消息不被重复消费的关键是保证消息队列的幂等性,这个问题针对业务场景来答分如下几点:
1.好比,你拿到这个消息作数据库的insert操做。那就容易了,给这个消息作一个惟一主键,那么就算出现重复消费的状况,就会致使主键冲突,避免数据库出现脏数据。
2.再好比,你拿到这个消息作redis的set的操做,那就容易了,不用解决,由于你不管set几回结果都是同样的,set操做原本就算幂等操做。
3.若是上面两种状况还不行,上大招。准备一个第三方介质,来作消费记录。以redis为例,给消息分配一个全局id,只要消费过该消息,将
五 如何解决丢数据的问题
1.生产者丢数据
RabbitMQ提供transaction和confirm模式来确保生产者不丢消息。
transaction机制就是说,发送消息前,开启事物(channel.txSelect()),而后发送消息,若是发送过程当中出现什么异常,事物就会回滚(channel.txRollback()),若是发送成功则提交事物(channel.txCommit())。
然而缺点就是吞吐量降低了。
生产上用confirm模式的居多。一旦channel进入confirm模式,全部在该信道上面发布的消息都将会被指派一个惟一的ID(从1开始),一旦消息被投递到全部匹配的队列以后,rabbitMQ就会发送一个Ack给生产者(包含消息的惟一ID),这就使得生产者知道消息已经正确到达目的队列了.若是rabiitMQ没能处理该消息,则会发送一个Nack消息给你,你能够进行重试操做。
2.消息队列丢数据
处理消息队列丢数据的状况,通常是开启持久化磁盘的配置。这个持久化配置能够和confirm机制配合使用,你能够在消息持久化磁盘后,再给生产者发送一个Ack信号。这样,若是消息持久化磁盘以前,rabbitMQ阵亡了,那么生产者收不到Ack信号,生产者会自动重发。
持久化步骤:
①、将queue的持久化标识durable设置为true,则表明是一个持久的队列
②、发送消息的时候将deliveryMode=2
这样设置之后,rabbitMQ就算挂了,重启后也能恢复数据。在消息尚未持久化到硬盘时,可能服务已经死掉,这种状况能够经过引入mirrored-queue即镜像队列,但也不能保证消息百分百不丢失(整个集群都挂掉)
3.消费者丢数据
启用手动确认模式能够解决这个问题,在finally里ack。
手动确认模式,若是消费者来不及处理就死掉时,没有响应ack时会重复发送一条信息给其余消费者;若是监听程序处理异常了,且未对异常进行捕获,会一直重复接收消息,而后一直抛异常;若是对异常进行了捕获,可是没有在finally里ack,也会一直重复发送消息(重试机制)。
六 消息积压
1、出现原因
消息积压出现的场景一般有两种:
1)、消费方的服务挂掉,导致一直无法消费消息;
2)、消费方的服务节点太少,导致消费能力不足,从而出现积压,这种情况极可能就是生产方的流量过大导致。
2、解决方案
1)、既然消费能力不足,那就扩展更多消费节点,提升消费能力;
2)、建立专门的队列消费服务,将消息批量取出并持久化,之后再慢慢消费。
七 如何保证消息的顺序性
将须要保持前后顺序的消息放到同一个消息队列中。而后只用一个消费者去消费该队列。
参考文章:
RabbitMQ消息丢失|消息重复|消息积压原因+解决方案
RabbitMQ如何解决被重复消费和数据丢失的问题?