一、
mq是什么?
答:mq代表消息队列,是一种应用程序对另一种应用程序的一种通信方法,通过消息队列来发送或者接受消息数据,支持应用程序、系统、服务和文件之间的转换,简化了业务应用程序的创建和维护。
mq的优点:
1.异步:例如:系统A做的是主要的业务,而系统B、C、D是非主要的业务。比如系统A处理的是订单下单,而系统B是订单下单成功了,那发送一条短信告诉具体的用户此订单已成功,而系统C和系统D也是处理一些小事而已。那么就可以设置成如下:
系统A执行完了以后,将userId写到消息队列中,然后就直接返回了(至于其他的操作,则异步处理)。
- 本来整个请求需要用950ms(同步)
- 现在将调用其他系统接口异步化,只需要100ms(异步)
2.解耦:
系统A将userId写到消息队列中,系统C和系统D从消息队列中拿数据。这样有什么好处?
- 系统A只负责把数据写到队列中,谁想要或不想要这个数据(消息),系统A一点都不关心。
- 即便现在系统D不想要userId这个数据了,系统B又突然想要userId这个数据了,都跟系统A无关,系统A一点代码都不用改。
- 系统D拿userId不再经过系统A,而是从消息队列里边拿。系统D即便挂了或者请求超时,都跟系统A无关,只跟消息队列有关。
这样一来,系统A与系统B、C、D都解耦了。
3.流量削峰:例如:我们再来一个场景,现在我们每个月要搞一次大促,大促期间的并发可能会很高的,比如每秒3000个请求。假设我们现在有两台机器处理请求,并且每台机器只能每次处理1000个请求。那多出来的1000个请求,可能就把我们整个系统给搞崩了...所以,有一种办法,我们可以写到消息队列中
系统B和系统C根据自己的能够处理的请求数去消息队列中拿数据,这样即便有每秒有8000个请求,那只是把请求放在消息队列中,去拿消息队列的消息由系统自己去控制,这样就不会把整个系统给搞崩。
使用场景:
1.对于数据量打或者处理耗时长的操作,可以引入mq实现异步通信,减少客户端的等待,提升响应速度。
2.对于改动影响大的系统之间,可以引入mq实现解耦,减少系统之间的直接依赖
3.对于会出现瞬间的流量峰值的系统(例如:电商网站双十一)可以引入mq实现流量削峰,达到保护应用和数据库的目的。
消息队列使用的问题:
1.高可用:
无论是我们使用消息队列来做解耦、异步还是削峰,消息队列肯定不能是单机的。试着想一下,如果是单机的消息队列,万一这台机器挂了,那我们整个系统几乎就是不可用了。所以,当我们项目中使用消息队列,都是得集群/分布式
的。要做集群/分布式
就必然希望该消息队列能够提供现成的支持,而不是自己写代码手动去实现。
2.数据丢失问题:我们将数据写到消息队列上,系统B和C还没来得及取消息队列的数据,就挂掉了。如果没有做任何的措施,我们的数据就丢了。
解决数据MQ数据丢失的问题:
分为三种情况:
第一种生产者存放消息的过程中丢失消息
解决:
1.事务机制:(同步方式,不推荐,影响性能)
对于RabbitMQ来说,生产者发送数据之前开启RabbitMQ事务机制channel.txselect,如果消息没有进队列,则生产者受到异常报错,并进行回滚channel.txRollvack,然后重试发送消息。如果收到了消息,则提交事务channel.txCommit。这是同步操作,影响性能。
2.异步机制
confirm模式来解决同步机制的性能问题。每次生产者发送的消息都会分配一个id,如果消息写到了消息队列中,则rabbitmq会回传一个ack消息,说明这个消息接收成功,如果MQ没能处理这个消息,则会回调ack接口,说明需要重新发送消息。
两者区别:
事务机制是同步的,提交事务后会被阻塞,直到提交事务完成后。
confirm模式异步接收通知,但可能接收不到通知。需要考虑接收不到通知的场景。
3.消费者怎么得到消息队列的数据?
消费者怎么从消息队列里边得到数据?有两种办法:
- 生产者将数据放到消息队列中,消息队列有数据了,主动叫消费者去拿(俗称push)
- 消费者不断去轮训消息队列,看看有没有新的数据,如果有就消费(俗称pull)