前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >消息中间件MQ科普

消息中间件MQ科普

作者头像
乐心湖
发布2020-08-10 11:12:05
8360
发布2020-08-10 11:12:05
举报
文章被收录于专栏:MyTechnology

服务之间的常见通信方式

服务调用:

消息机制:

什么是MQ

消息队列(Message Queue),是一种跨进程的通信机制,用于上下游传递消息。

消息队列是典型的:生产者、消费者模型

  • 生产者不断向消息队列中生产消息,消费者不断的从队列中获取消息。
  • 因为消息的生产和消费都是异步的,而且只关心消息的发送和接收,没有业务逻辑的侵入,这样就实现了生产者和消费者的解耦。
  • 使用了MQ之后,消息发送上游只需要依赖MQ,逻辑上和物理上都不用依赖其他服务。

MQ的使用场景

什么时候不使用MQ

既然MQ是互联网分层架构中的解耦利器,那所有通讯都使用MQ岂不是很好?

这是一个严重的误区,调用与被调用的关系,是无法被MQ取代的。

MQ的不足是:

1)系统更复杂,多了一个MQ组件

2)消息传递路径更长,延时会增加

3)消息可靠性和重复性互为矛盾,消息不丢不重难以同时保证

4)上游无法知道下游的执行结果,这一点是很致命的

举个栗子:

小湖学院系统创建订单场景,创建订单时需要查找课程基本信息,订单服务调用课程服务,课程服务的执行结果直接影响创建订单的结果,此处的“订单服务”与“课程服务”就必须使用调用关系,而不能使用MQ通信。

无论如何,记住这个结论:调用方实时依赖执行结果的业务场景,请使用调用,而不是MQ。

什么时候使用MQ

【典型场景一:数据驱动的任务依赖】

什么是任务依赖,举个栗子,互联网公司经常在凌晨进行一些数据统计任务,这些任务之间有一定的依赖关系,比如:

1)task3需要使用task2的输出作为输入

2)task2需要使用task1的输出作为输入

这样的话,tast1, task2, task3之间就有任务依赖关系,必须task1先执行,再task2执行,再task3执行。

对于这类需求,常见的实现方式是,使用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)如果有一个任务的执行时间要调整,将会有多个任务的执行时间要调整

无论如何,采用“cron排班表”的方法,各任务耦合

优化方案是,采用MQ解耦:

1)task1准时开始,结束后发一个“task1 done”的消息

2)task2订阅“task1 done”的消息,收到消息后第一时间启动执行,结束后发一个“task2 done”的消息

3)task3同理

采用MQ的优点是:

1)不需要预留buffer,上游任务执行完,下游任务总会在第一时间被执行

2)依赖多个任务,被多个任务依赖都很好处理,只需要订阅相关消息即可

3)有任务执行时间变化,下游任务都不需要调整执行时间

需要特别说明的是,MQ只用来传递上游任务执行完成的消息,并不用于传递真正的输入输出数据。

【典型场景二:上游不关心执行结果】

上游需要关注执行结果时要用“调用”,上游不关注执行结果时,就可以使用MQ了。

举个栗子,在线教育系统的很多下游需要关注“用户评论课程”这个事件,比如课程服务要增加课程评论数量,积分服务要奖励用户积分,消息服务要给管理员发送站内消息。

对于这类需求,常见的实现方式是,使用调用关系:

用户评论课程执行完成之后,调用下游课程服务、积分服务、消息服务,但事实上,这个通知是否正常正确的执行,帖子发布服务根本不关注。

这种方法的坏处是:

1)课程评论发布流程的执行时间增加了

2)下游服务宕机,可能导致课程评论服务受影响,上下游逻辑+物理依赖严重

3)每当增加一个需要知道“评论发布成功”信息的下游,都要修改课程评论服务的代码,属于架构设计中典型的依赖倒转

优化方案是,采用MQ解耦:

1)评论发布成功后,向MQ发一个消息

2)哪个下游关注“评论发布成功”的消息,主动去MQ订阅

采用MQ的优点是:

1)上游执行时间短

2)上下游逻辑+物理解耦,除了与MQ有物理连接,模块之间都不相互依赖

3)新增一个下游消息关注方,上游不需要修改任何代码

【典型场景三:上游关注执行结果,但执行时间很长】

有时候上游需要关注执行结果,但执行结果时间很长(典型的是调用离线处理,或者跨公网调用,例如支付、调用阿里云接口等业务),也经常使用回调网关+MQ来解耦。

举个栗子,微信支付,跨公网调用微信的接口,执行时间会比较长,但调用方又非常关注执行结果,此时一般怎么玩呢?

一般采用“回调网关+MQ”方案来解耦:

1)调用方直接跨公网调用微信接口

2)微信返回调用成功,此时并不代表返回成功

3)微信执行完成后,回调统一网关

4)网关将返回结果通知MQ

5)请求方收到结果通知

这里需要注意的是,不应该由回调网关来调用上游来通知结果,如果是这样的话,每次新增调用方,回调网关都需要修改代码,仍然会反向依赖,使用回调网关+MQ的方案,新增任何对微信支付的调用,都不需要修改代码啦。

【典型场景四:缓冲流量,削峰填谷】

高并发场景下的服务通信,不管采用“直接调用”还是“MQ推送”,都有一个缺点,下游消息接收方无法控制到达自己的流量,如果调用方不限速,很有可能把下游压垮。

举个栗子,秒杀业务:

上游发起下单操作

下游完成秒杀业务逻辑(库存检查,库存冻结,余额检查,余额冻结,订单生成,余额扣减,库存扣减,生成流水,余额解冻,库存解冻)

上游下单业务简单,每秒发起了10000个请求,下游秒杀业务复杂,每秒只能处理2000个请求,很有可能上游不限速的下单,导致下游系统被压垮,引发雪崩。

为了避免雪崩,常见的优化方案有两种:

1)业务上游队列缓冲,限速发送

2)业务下游队列缓冲,限速执行

问:如何缓冲流量?

使用MQ做消息缓冲。由MQ-server推模式,升级为MQ-client拉模式。MQ-client根据自己的处理能力,每隔一定时间,或者每次拉取若干条消息,实施流控,达到保护自身的效果。并且这是MQ提供的通用功能,无需上下游修改代码。

问:如果上游发送流量过大,会不会导致消息在MQ中堆积?

为了避免消息在MQ中堆积,下游消息接收方可以批量处理消息,提升整体吞吐量。

结论

1)MQ-client提供拉模式,定时或者批量拉取,可以起到削平流量,下游自我保护的作用(MQ需要做的)

2)要想提升整体吞吐量,需要下游优化,例如批量处理等方式(消息接收方需要做的)

总结

  • MQ是一个互联网架构中常见的解耦利器。
  • 什么时候不使用MQ?
    • 上游实时关注执行结果
  • 什么时候使用MQ?
    • 数据驱动的任务依赖
    • 上游不关心多下游执行结果
    • 异步返回执行时间长
    • 缓冲流量,削峰填谷

AMQP和JMS

MQ是消息通信的模型,并不是具体实现。现在实现MQ的有两种主流方式:AMQP、JMS。

两者间的区别和联系:(面试)

  • JMS是定义了统一的接口,来对消息操作进行统一;
  • AMQP是通过规定协议来统一数据交互的格式。
  • JMS限定了必须使用Java语言
  • AMQP只是协议,不规定实现方式,因此是跨语言的。
  • JMS规定了两种消息模型;
  • 而AMQP的消息模型更加丰富。

常见的消息中间件产品

  • ActiveMQ:基于JMS
  • RabbitMQ:基于AMQP协议,erlang语言开发,稳定性好
  • RocketMQ:基于JMS,阿里巴巴产品,目前交由Apache基金会
  • Kafka:分布式消息系统,高吞吐量

本站所有未注明转载的文章均为原创,并采用CC BY-NV-SA 4.0 授权协议,转载请注明来源。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是MQ
  • MQ的使用场景
    • 什么时候不使用MQ
      • 什么时候使用MQ
        • 总结
        • AMQP和JMS
        • 常见的消息中间件产品
        相关产品与服务
        消息队列 CMQ 版
        消息队列 CMQ 版(TDMQ for CMQ,简称 TDMQ CMQ 版)是一款分布式高可用的消息队列服务,它能够提供可靠的,基于消息的异步通信机制,能够将分布式部署的不同应用(或同一应用的不同组件)中的信息传递,存储在可靠有效的 CMQ 队列中,防止消息丢失。TDMQ CMQ 版支持多进程同时读写,收发互不干扰,无需各应用或组件始终处于运行状态。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档