目录
- 个人主页: 爱吃豆的土豆
- 版权: 本文由【爱吃豆的土豆】原创、在CSDN首发、需要转载请联系博主
- 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦
人必有所执,方能有所成!
希望大家多多支持一起进步呀!
1,初始MQ
1.1:同步和异步通讯
1.1.2:异步通讯
1.2:MQ技术对比:
什么是MQ:
2,快速入门
2.1:安装RabbitMQ
2.1.1:下载
2.1.2:安装
2.1.3:运行
2.1.4:访问
2.2: MQ的基本结构:
2.3:RabbitMQ消息模型
2.3.1:Work queues 工作模式
2.3.2:publish/Subscribe:发布订阅模式
2.3.3:Routing:路由模式
2.3.4:Topics:主题模式
2.3.5:Header
2.3.6:RPC
2.4:总结
1,初始MQ
1.1:同步和异步通讯
微服务间通讯有同步和异步两种方式:
同步通讯:就像打电话,打视频,需要实时响应。(就像你给一个妹子打视频,视频接通,你们两人就建立了同步通讯,什么叫同步?就是接通后你说的任何话即刻传输给对方,对方即刻进行响应就像直播一样,这就是同步。但是呢!万一这个时候又来两个妹子打了过来,你就无法接通,容易措施良机)
异步通讯:就像发邮件,微信什么的,不需要马上回复。(异步通讯就当于微信聊天,你给妹子发个信息,妹子不给你回你就收不到消息,这种时效性比较差。但是呢!异步通讯你可以咔咔给好多妹子发信息,这样就可以等待多个妹子回复。)
两种方式各有优劣,打电话可以立即得到响应,但是你却不能跟多个人同时通话。发送微信可以同时与多个人收发信息,但是往往响应会有延迟。
1.1.1:同步通讯
我们之前学习的Feign调用就属于同步方式,虽然调用可以实时得到结果,但存在下面的问题:
总结:
同步调用的优点:
时效性较强,可以立即得到结果
同步调用的问题:
耦合度高:(如下图:产品经理说你支付服务里面在加个短信服务,过一会产品经理又说支付服务里面再加个优惠卷服务,就造成了每次加入新业务就需要修改支付服务里面原先的代码。存在耦合度高的问题)
性能和吞吐能力下降(就像现在支付服务调用自己的每个服务都是150ms处理完整的一次请求就是500ms,1秒才能处理两个用户支付请求,当用户量大,并发量大的时候处理的如此慢。就存在一个性能和吞吐的能力下降的问题)
有额外的资源消耗(就像支付服务调用订单服务,订单服务处理150ms,其他服务在这150ms内静静的看着,占用着Cpu和内存啥都不干,造成额外的资源浪费)
有级联失败问题 (假设仓储服务,扛不住压力服务挂了,支付服务调用一直调用都不行,导致支付服务也资源也占用完了服务也挂了,那么这条链路上的服务都不能用了,就造成了级联失败的问题)
1.1.2:异步通讯
异步调用则可以避免上述问题:
我们以购买商品为例,用户支付后需要调用订单服务完成订单状态修改,调用物流服务,从仓库分配响应的库存并准备发货。
在事件模式中,支付服务是事件发布者(publisher),在支付完成后只需要发布一个支付成功的事件(event),事件中带上订单id。
订单服务和物流服务是事件订阅者(Consumer),订阅支付成功的事件,监听到事件后完成自己业务即可。
为了解除事件发布者与订阅者之间的耦合,两者并不是直接通信,而是有一个中间人(Broker)。发布者发布事件到Broker,不关心谁来订阅事件。订阅者从Broker订阅事件,不关心谁发来的消息。
好处:
耦合度极低,每个服务都可以灵活插拔,可替换(就像项目经理说在支付服务里面再添加一个积分服务,在同步通讯的场景下你还需要在支付服务里面添加代码去调用积分服务。在异步通讯的场景下就不需要了,为什么呢?因为现在支付服务不负责调用自己的子服务,有用户下支付了,支付服务只需要发布一个成功事件到Broker中,Broker拿着喇叭喊一下哪个订单支付了,其关联的服务只需要订阅一下事件,做自己的事就好了,支付服务压根就不管了,或者说产品经理说短信真贵,不让发了只需要取消订阅短信服务就ok了也不需要删除代码,这样就大大的降低了耦合度。)
吞吐量提升:无需等待订阅者处理完成,响应更快速(这样理解在同步通讯的时候,整个完成的工程需要累加起来也就是500ms,而现在异步通讯就不需要了,当用户发起支付服务,支付动作完成给Borker发布一个事件信息,直接就返回给用户,整个流程下来也就60ms,效率提高,吞吐量也大大提升。而不需要等待订阅者服务处理完成后返回,像(订单服务,仓储服务)它做多久都和支付服务没什么关系,只要最后完成就行。)
故障隔离:服务没有直接调用,不存在级联失败问题(这个这样理解,你就假如仓储服务挂了出故障了,在同步通讯中极有可能出现级联失败。在异步通讯中就可以避免这种问题,用户支付完成之后,支付服务发布个事件就成功返回了,Borker拿个喇叭一喊这些服务都来订阅,结果仓储服务挂了出现故障了,那没事我修修这个仓储服务,反正支付服务已经成功了也不会造成堵塞,不存在调用关系)
调用间没有阻塞,不会造成无效的资源占用(在同步通讯操作中一个服务在进行中,其他服务就静静的等着造成资源浪费。在异步通讯中,事件订阅后各干各的不会造成无效的资源占用)
流量削峰:不管发布事件的流量波动多大,都由Broker接收,订阅者可以按照自己的速度去处理事件(这个就是,当大量的用户下单了支付服务,然后支付服务就像发洪水一样发布事件到Broker中,但是呢!假设【订单服务,仓储服务,短信服务】一次只能处理一个,如果大批量的订阅搞不好这些服务有挂机了,所以呢!这时候Borker就化身一个大坝把这些支付服务订单事件都给拦下,保证【订单服务,仓储服务,短信服务】能处理几个处理几个保证正常进行,这样就把并发量高峰降低到趋于平稳。)
缺点:
需要依赖于Broker的可靠、安全、性能(相信大家了解完上面的异步通讯的优势已经明显发现异步通讯需要依赖Broker,当然异步通讯虽然好,但也有缺点,你就像异步通讯处理流量削峰,大量的用户支付生成大量的事件交给了Broker,万一Borker没有抗住压力崩了怎么办呢!就像洪水来了大坝没有建好直接轰然倒塌了,这还能玩吗?所以昂这就是存在的第一个问题就是对Broker的性能,安全,可靠要求很高)
架构复杂了,业务没有明显的流程线,不好管理(第二个问题就是使用异步通讯服务之间的调用问题不在那么清晰明了,你发布了一个事件,但是你并不知道这个事件是哪个服务处理的,这种调用链不清晰,就导致以后出了问题,不容易进行排查问题所在。)
好在现在开源软件或云平台上 Broker 的软件是非常成熟的,比较常见的一种就是我们今天要学习的MQ技术。
1.2:MQ技术对比:
什么是MQ:
MQ,中文是消息队列(MessageQueue),字面来看就是存放消息的队列。也就是事件驱动架构中的Broker。
比较常见的MQ实现:
ActiveMQ
RabbitMQ
RocketMQ
Kafka
几种常见MQ的对比:
RabbitMQ | ActiveMQ | RocketMQ | Kafka | |
---|---|---|---|---|
公司/社区 | Rabbit | Apache | 阿里 | Apache |
开发语言 | Erlang | Java | Java | Scala&Java |
协议支持 | AMQP,XMPP,SMTP,STOMP | OpenWire,STOMP,REST,XMPP,AMQP | 自定义协议 | 自定义协议 |
可用性 | 高 | 一般 | 高 | 高 |
单机吞吐量 | 一般 | 差 | 高 | 非常高 |
消息延迟 | 微秒级 | 毫秒级 | 毫秒级 | 毫秒以内 |
消息可靠性 | 高 | 一般 | 高 | 一般 |
追求可用性:Kafka、 RocketMQ 、RabbitMQ
追求可靠性:RabbitMQ、RocketMQ
追求吞吐能力:RocketMQ、Kafka
追求消息低延迟:RabbitMQ、Kafka
2,快速入门
2.1:安装RabbitMQ
2.1.1:下载
- 官网下载地址:Downloading and Installing RabbitMQ — RabbitMQ
- https://www.rabbitmq.com/install-windows.html#installer
2.1.2:安装
安装erlang
安装完成之后,如果有不能正常启动RabbitMQ服务。
报以下错误:目录名称无效。文件名, 目录名或卷标语法不正确
原因是:erlang要求电脑名称不能有中文。
解决方法:
1,卸载erlang和rabbitmq
2,重命名电脑名,重启电脑
3,安装erlang和rabbitmq,配置环境变量。
配置环境变量:
安装RabbitMQ
2.1.3:运行
- 步骤一:打开控制台
2.步骤二:激活插件
3.步骤三:重启
net stop rabbitmq && net start rabbitmq
2.1.4:访问
- 步骤一:输入 http://127.0.0.1:15672/
- 步骤二:默认账号登录:guest/ guest
2.2: MQ的基本结构:
RabbitMQ中的一些角色:
publisher:生产者
consumer:消费者
exchange个:交换机,负责消息路由
queue:队列,存储消息
virtualHost:虚拟主机,隔离不同租户的exchange、queue、消息的隔离
2.3:RabbitMQ消息模型
RabbitMQ官方提供了6个不同的Demo示例,对应了不同的消息模型(可以将官网页面翻译成中文方便查找 ):
2.3.1:Work queues 工作模式
work queues两个消费端共同消费同一个队列中的消息。
结果:
1、一条消息只会被一个消费者接收;
2、rabbit采用轮询的方式将消息是平均发送给消费者的;
3、消费者在处理完某条消息后,才会收到下一条消息。
2.3.2:publish/Subscribe:发布订阅模式
发布订阅模式:就是一个消息,同时发给多个消费者(没有筛选条件)
1、每个消费者监听自己的队列。
2、生产者将消息发给broker,由交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的队列都将接收到消息
2.3.3:Routing:路由模式
路由模式:一个小时,同时发送给“符合条件”的多个消费者(等值筛选)
1、每个消费者监听自己的队列,并且设置routingkey。
2、生产者将消息发给交换机,由交换机根据routingkey来转发消息到指定的队列。
2.3.4:Topics:主题模式
主题模式:一个消息,同时发送给“符合条件”的多个消费者(模糊筛选)
1、每个消费者监听自己的队列,并且设置带统配符的routingkey。
2、生产者将消息发给broker,由交换机根据routingkey来转发消息到指定的队列。
2.3.5:Header
header模式与routing不同的地方在于,header模式取消routingkey,使用header中的 key/value(键值对)匹配队列
2.3.6:RPC
RPC即客户端远程调用服务端的方法 ,使用MQ可以实现RPC的异步调用,基于Direct交换机实现,流程如下:
1、客户端即是生产者就是消费者,向RPC请求队列发送RPC调用消息,同时监听RPC响应队列。
2、服务端监听RPC请求队列的消息,收到消息后执行服务端的方法,得到方法返回的结果
3、服务端将RPC方法 的结果发送到RPC响应队列
4、客户端(RPC调用方)监听RPC响应队列,接收到RPC调用结果。
2.4:总结
基本消息队列的消息发送流程:
建立connection
创建channel
利用channel声明队列
利用channel向队列发送消息
基本消息队列的消息接收流程:
建立connection
创建channel
利用channel声明队列
定义consumer的消费行为handleDelivery()
利用channel将消费者与队列绑定