摘要
电商系统引发的思考:
-
耦合度高
- 每次有新的需求都需要修改改动多处代码和逻辑以实现功能增加
-
性能下降
- 调用者需要等待服务提供者响应,如果调用链过长则响应时间等于每次调用的时间之和。随着调用链的增长,响应时间会变得非常长,影响用户体验和系统的整体性能。
-
资源浪费
- 调用链中的每个服务在等待响应过程中,不能释放请求占用的资源,高并发场景下会极度浪费系统资源可能导致调用链中服务的资源浪费加剧,影响系统性能和稳定性。在这种情况下,必须寻找解决高耦合、性能下降和资源浪费问题的方法,以确保电商系统的健壮性和高效性。
-
级联失败
- 如果服务提供者出现问题,所有调用方都会跟着出问题,如同多米诺骨牌一样,迅速导致整个微服务群故障下文续写的句子为:因此,微服务架构需要具备容错能力,确保服务之间的依赖关系在出现问题时能够迅速恢复,避免整个系统的瘫痪。
异步调用方案
优势一:服务解耦 个业务需要多个模块共同实现,或者一条消息有多个系统需要对应处理,只需要主业务完成以后,发送一条MQ,其余模块消费MQ消息,即可实现业务,降低模块之间的耦合。
优势二:性能提升。通过异步调用,主业务执行结束后,从属业务可以通过MQ进行异步执行,降低了业务的响应时间,提高了系统的吞吐量和整体性能。这样能够有效解决因调用链过长导致的响应时间过长问题,提升了用户体验。
三:由于异步调用的实现,服务之间没有强依赖关系,一个服务的故障不会立即影响其他服务,降低了级联失败的风险。这有助于增强系统的稳定性和容错能力。
优势四:流量削峰。在高并发情况下,通过异步处理业务,可以有效地分散和平衡系统负载,避免服务提供者因高并发请求而瘫痪。同时,这也有助于系统应对突发的流量峰值,提高系统的整体稳定性和容错能力。
初识MQ
MQ(Message Queue)
MQ(Message Queue)消息队列,是基础数据结构中“先进先出”的一种数据结构。一般用来解决应用解耦,异步消息,流量削峰等问题,实现高性能,高可用,可伸缩和最终一致性架构。 我们把要传输的数据(消息)放在队列中,用队列机制来实现消息传递——生产者产生消息并把消息放入队列,然后由消费者去处理。消费者可以到指定队列拉取消息,或者订阅相应的队列,由MQ服务端给其推送消息。用于上下游传递消息。 在互联网架构中,MQ 是一种非常常见的上下游“逻辑解耦+物理解耦”的消息通信服务。使用了 MQ 之后,消息发送上游只需要依赖 MQ,不用依赖其他服务。
-
### 优点
-
解耦:在业务实现过程中,当一项业务需要多个模块共同协作或一条消息需要多个系统处理时,可以通过采用消息队列(MQ)的方式进行解耦。主业务完成后,发送一条MQ消息,其他模块通过消费这条消息来实现各自的功能,从而降低模块之间的耦合度,增强系统的可维护性和可扩展性。
-
异步处理:主业务执行完成后,通过消息队列(MQ)异步执行从属业务。这种方式可以降低业务的响应时间,提升用户体验。
-
削峰:针对高并发情况,实施业务异步处理策略,以应对业务高峰期的挑战,提升系统处理能力并避免系统瘫痪。通过该策略,可以在系统面临大量并发请求时,有效地分散请求压力,减少系统阻塞,提高业务处理效率。
-
-
### 缺点
-
系统可用性下降和服务稳定性问题:由于系统依赖的服务增多,整体可用性可能会降低。特别是在面临MQ(消息队列)瘫痪等突发情况时,服务更容易中断。因此,需要加强对服务稳定性的考虑和应对策略。
-
系统复杂性增加带来的挑战:系统复杂性的提高带来了诸如消息丢失、消息重复消费和消息传递顺序性等问题。为了解决这些问题,需要采取一系列措施,确保消息传递的准确性和可靠性。
-
业务一致性问题:在处理主业务和从属业务时,需要特别关注业务一致性。确保主从业务在数据和处理流程上保持一致,避免因不一致导致的问题和损失。
-
MQ是消息通信的模型
实现MQ的大致有两种主流方式:AMQP
、JMS
-
JMS
- JMS即Java消息服务(Java Message Service)是Java平台中的一种面向消息中间件(MOM)的API,用于在应用程序之间或分布式系统中发送消息以实现异步通信。
该服务接口限定了必须使用Java语言,并定义了统一的接口来进行消息操作的统一管理。
- JMS即Java消息服务(Java Message Service)是Java平台中的一种面向消息中间件(MOM)的API,用于在应用程序之间或分布式系统中发送消息以实现异步通信。
-
AMQP
- AMQP是一种高级消息队列协议,主要用于进程间传递异步消息。它是一种网络协议,更具体地说是一种二进制线级协议(链接协议)。与JMS相比,AMQP的主要区别在于它不局限于API层,而是直接定义网络交换的数据格式。
由于AMQP仅仅是一个协议,并不规定具体的实现方式,因此它具有跨语言的特性。
- AMQP是一种高级消息队列协议,主要用于进程间传递异步消息。它是一种网络协议,更具体地说是一种二进制线级协议(链接协议)。与JMS相比,AMQP的主要区别在于它不局限于API层,而是直接定义网络交换的数据格式。
消息中间件是基于队列与消息传递技术,在网络环境中为应用系统提供同步或异步、可靠的消息传输的支撑性软件系统。
RabbitMQ的安装与使用
RabbitMQ 介绍
出身:诞生于金融行业的消息队列
开发语言:erlang
协议:AMQP
(Advanced Message Queuing Protocol 高级消息队列协议)
RabbitMQ是由erlang语言开发,基于AMQP(Advanced Message Queue 高级消息队列协议)协议实现的消息队列,它是一种应用程序之间的通信方法,该消息队列在分布式系统开发中应用非常广泛
优点
● 由于 erlang 语言的高并发特性,性能较好;吞吐量到万级,
● MQ 功能比较完备,健壮、稳定、易用、跨平台、支持多种语言 如:Python、Ruby、.NET
、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持 AJAX
● 文档齐全;开源提供的管理界面非常棒,用起来很好用,社区活跃度高;更新频率相当高;
-
组成部分说明
-
Broker:接收和分发消息的应用,消息队列服务进程,此进程包括两个部分:Exchange和 Queue。RabbitMQ Server就是Message Broker。
-
Virtual Host :虚拟主机,用于逻辑隔离。一个虚拟主机里面可以有若干个Exchange和 Queue,同一个虚拟主机里面不能有相同名称的Exchange或Queue。
-
Exchange:消息交换机,作用是接收来自生产者的消息,并根据路由键转发消息到所绑定的队列
-
Queue:即队列,RabbitMQ内部用于存储消息的对象,是真正用存储消息的结构,在生产端,生产者的消息最终发送到指定队列,而消费者也是通过订阅某个队列,达到获取消息的目的。
-
Binding:Binding是一种操作,其作用是建立消息从Exchange转发到Queue的规则,在进行Exchange与Queue的绑定时,需要指定一个BindingKey,Binding操作一般用于RabbitMQ的路由工作模式和主题工作模式。
-
Connection:Connection就是一个TCP的连接,Producer和Consumer都是通过 TCP连接到RabbitMQ Server的。
-
Channel:信道,多路复用连接中的一条独立的双向数据流通道。是建立在上述的 TCP连接中,因为建立TCP Connection的开销将是巨大的,所以其是为了节省 Rabbitmq开销
-
Producer:消息生产者,即生产方客户端,生产方客户端将消息发送
-
Consumer:消息消费者,即消费方客户端,接收MQ转发的消息
-
Docker环境下安装RabbitMQ
拉取最新的rabbitmq的镜像
docker pull rabbitmq
拉取指定版本的rabbitmq镜像
docker pull rabbitmq:版本号
创建容器
docker run -d -p 5672:5672 -p 15672:15672 --restart=always --name env_rabbitmq
打开浏览器,输入 虚拟机ip:15672 ,是可以看到一个后台管理界面 ,默认用户名和密码为: guest
SpringBoot整合RabbitMQ
创建SpringBoot项目为demo-rabbitmq修改pom.xml,导入依赖
修改全局配置文件application.yml文件
RabbitMQ几种模式
简单(simple)模式
只有一个生产者、一个消费者和一个队列。生产者和消费者在发送和接收消息时,只需要指定队列名,而不需要指定发送到哪个 Exchange,RabbitMQ服务器会自动使用Virtual host的默认的Exchange,默认Exchange的type为direct。
工作(work)模式
在simple模式下只有一个生产者和消费者,当生产者生产消息的速度大于消费者的消费速度时,我们可以添加一个或多个消费者来加快消费速度,这种在simple模式下增加消费者的模式,称为work模式,可以有多个消费者,但一条消息只能被一个消费者获取。
如下图所示:
发布/订阅(pub/sub)模式
work模式可以将消息转到多个消费者,但每条消息只能由一个消费者获取,如果我们想一条消息可以同时给多个消费者消费呢?这时候就需要发布/订阅模式,其示意图如下所示:
生产者将消息不是直接发送到队列,而是发送到X交换机,然后由交换机发送给两个队列,两个消费者各自监听一个队列,来消费消息
发布/订阅模式中,Echange的type为fanout。相关场景:邮件群发,群聊天,广播(广告)
路由(routing)模式
前面几种模式,消息的目标队列无法由生产者指定,而在路由模式下,消息的目标队列,可以由生产者指定,其示意图如下所示:
路由模式下Exchange的type为direct。
消息的目标队列可以由生产者按照RoutingKey规则指定。
消费者通过Binding Key绑定自己所关心的队列。
条消息队可以被多个消息者获取。
只有Routing Key与Biding Key相匹配的队列才会收到消息
RoutingKey用于生产者指定Exchange最终将消息路由到哪个队列,BindingKey用于消费者绑定到某个队列
主题(topic)模式
主题模式是在路由模式的基础上,将路由键和某模式进行匹配。示意图如下所示:
其中#表示匹配多个词
主题模式Exchange的type取值为topic.
"表示匹配一个词
消费者可以通过某种模式的BindKey来达到订阅某个主题消息的目的
RabbitMQ四种交换机类型
-
DirectExchange:直连交换机
-
直连交换机是一种带路由功能的交换机,需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配。这是一个完整的匹配。如果一个队列绑定到该交换机上要求路由键 “abc”,则只有被标记为“abc”的消息才被转发,不会转发abc.def,也不会转发dog.ghi,只会转发abc。
-
适用场景:有优先级的任务,根据任务的优先级把消息发送到对应的队列,这样可以指派更多的资源去处理高优先级的队列
-
-
Fanout Exchange:扇形交换机
-
扇形交换机是最基本的交换机类型,它所能做的事情非常简单———广播消息。扇形交换机会把能接收到的消息全部发送给绑定在自己身上的队列。因为广播不需要“思考”,所以扇形交换机处理消息的速度也是所有的交换机类型里面最快的。
-
适用场景:邮件群发,群聊天,广播(广告)
-
-
Topic Exchange:主题交换机
-
发送到主题交换机上的消息需要携带指定规则的routing_key,主题交换机会根据这个规则将数据发送到多个队列上。
-
主题交换机的routing_key需要有一定的规则,交换机和队列的binding_key需要采用*.或者#.*的格式,每个部分用.分开,其中:
-
*表示一个单词
-
#表示任意数量(零个或多个)单词。
-
-
-
Headers Exchanges:首部交换机
-
首部交换机是忽略routing_key的一种路由方式。路由器和交换机路由的规则是通过Headers信息来交换的,这个有点像HTTP的Headers。将一个交换机声明成首部交换机,绑定一个队列的时候,定义一个Hash的数据结构,消息发送的时候,会携带一组hash数据结构的信息,当Hash的内容匹配上的时候,消息就会被写入队列。
-
绑定交换机和队列的时候,Hash结构中要求携带一个键“x-match”,这个键的Value可以是any或者all,这代表消息携带的Hash是需要全部匹配(all),还是仅匹配一个键(any)就可以了。相比直连交换机,首部交换机的优势是匹配的规则不被限定为字符串(string)。
-
headers类型的交换机性能很差,不建议使用。
-
总结
版权归属: Handsome 原文链接: www.mmm.sd/archives/Ra…