什么是 MQ?
消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过写和检索出入列队的针对应用程序的数据(消息)来通信,而无需专用连接来链接它们。消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。排队指的是应用程序通过队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。
为什么使用 MQ?
使用场景
- 解耦
- 异步
- 削峰
场景举例
解耦
-
数据驱动的任务依赖
什么是任务依赖,举个例子,互联网公司经常在凌晨进行一些数据统计任务,这些任务之间有一定的依赖关系,比如:
1)task3 需要使用task2的输出作为输入
2)task2 需要使用task1的输出作为输入
这样的话,tast1, task2, task3之间就有任务依赖关系,必须 task1 先执行,再 task2 执行,再 task3 执行。
-
不使用MQ
对于这类需求,常见的实现方式是,使用 cron 人工排执行时间表:
1)task1,0:00 执行,经验执行时间为 50 分钟
2)task2,1:00 执行(为 task1 预留 10 分钟 buffer),经验执行时间也是 50 分钟
3)task3,2:00 执行(为 task2 预留 10 分钟 buffer)
这种方法的坏处是:
1)如果有一个任务执行时间超过了预留 buffer 的时间,将会得到错误的结果,因为后置任务不清楚前置任务是否执行成功,此时要手动重跑任务,还有可能要调整排班表
2)总任务的执行时间变长,总是要预留很多 buffer,如果前置任务提前完成,后置任务不会提前开始
3)如果一个任务被多个任务依赖,这个任务将会称为关键路径,排班表很难体现依赖关系,容易出错
4)如果有一个任务的执行时间要调整,将会有多个任务的执行时间要调整
-
使用 MQ
优化方案是,采用 MQ 解耦:
1)task1 准时开始,结束后发一个“task1 done”的消息
2)task2 订阅 “task1 done” 的消息,收到消息后第一时间启动执行,结束后发一个 “task2 done” 的消息
3)task3 同理
采用MQ的优点是:
1)不需要预留 buffer,上游任务执行完,下游任务总会在第一时间被执行
2)依赖多个任务,被多个任务依赖都很好处理,只需要订阅相关消息即可
3)有任务执行时间变化,下游任务都不需要调整执行时间
MQ只用来传递上游任务执行完成的消息,并不用于传递真正的输入输出数据。
-
异步
-
上游不关心执行结果
-
上游关注执行结果,但执行时间很长
-
不使用MQ
上游直接调用下游
1)上游需要同步等待下游执行结果
2)下游系统故障导致上游系统无法使用
3)下游增加需修改上游代码
-
使用MQ
通过使用MQ达到异步、解耦的效果
1)上游无需等待下游执行完毕,加快上游响应速度
2)下游系统故障不会影响上游系统的运行
3)增加下游只需订阅 MQ
-
削峰
-
请求高峰期
举个例子:系统A一天中大部分时间每秒请求并发数量就 100 多个,但是中午12点-1点每秒请求并发量就飙升到 10000 多个,但是系统每秒最大能处理的请求量只有 1000 多。
-
不使用MQ
-
使用MQ
通过使用 MQ 达到限流的效果,系统无法处理的请求会堆积在 MQ 中,高峰期过后系统可以继续消费 MQ 中的请求。
1)系统不会因为高峰期的请求量挂掉
-
引入MQ带来的问题
引入一项新的技术,在解决现有问题的同时势必会带来新的问题。
-
可用性降低
系统引入的外部依赖越多,越容易挂掉,MQ 挂掉之后会导致整个系统不可用。
-
复杂度提高
重复消费、消息丢失、消息的顺序性等这些都是引入 MQ 之后需要考虑的事情。
-
一致性问题
A 系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是 BCD 三个系统那里,BD 两个系统写库成功了,结果 C 系统写库失败了,就会导致数据不一致。