分布式系统消息中间件-RabbitMQ介绍及其应用

分布式系统消息中间件-RabbitMQ

 

一、消息中间件

1.1 中间件

1.1.1 什么是中间件?

中间件(Middleware)是处于操作系统和应用程序之间的软件。人们在使用中间件时,往往是一组中间件集成在一起,构成一个平台(包括开发平台和运行平台),但在这组中间件中必须要有一个通信中间件,即中间件=平台+通信,这个定义也限定了只有用于分布式系统中才能称为中间件,同时还可以把它与支撑软件和实用软件区分开来。如果把它看成三明治的话,它的上面一层就是应用软件,下面一层就是操作系统、网络和数据库软件。

                                    分布式系统消息中间件-RabbitMQ介绍及其应用_第1张图片

1.1.2 中间件的基本功能

1、通信支持:中间件为其所支持的应用软件提供平台化的运行环境,该环境屏蔽底层通信之间的接口差异,实现互操作,所以通信支持是中间件一个最基本的功能。

2、应用支持:中间件的目的就是服务上层应用,提供应用层不同服务之间的互操作机制。

3、公共服务:公共服务是对应用软件中共性功能或约束的提取。

 

1.1.3 中间件的基本特点

①能满足大量应用的需要。

②能运行于多种硬件和多种操作系统平台上。

③支持分布计算。

④提供跨网络、跨硬件和跨操作系统平台的交互式应用和服务。

⑤支持标准协议。

⑥支持标准接口

 

1.2 消息中间件

1.2.1 什么是消息中间件?

消息中间件,是一类以消息为载体进行通信的中间件,利用高效可靠的消息机制来实现不同应用间大量的数据交换。按其通信模型的不同,消息中间件的通信模型有两类:点对点和发布订阅。通过这两种消息模型,不同应用之间的通信和网络的复杂性脱离,摆脱对不同通信协议的依赖,可以在复杂的网络环境中高可靠、高效率的实现安全的异步通信。消息中间件的非直接连接,支持多种通信规程,达到多个系统之间的数据的共享和同步。一句话总结,我们消息中间件不生产消息,只是消息的搬运工。

1.2.2 为什么需要消息中间件?

通过服务调用让其他系统感知事件的发生,系统之间耦合度太高,用户体验不好

 

 

分布式系统消息中间件-RabbitMQ介绍及其应用_第2张图片

 

通过消息中间件可以将服务调用进行解耦

分布式系统消息中间件-RabbitMQ介绍及其应用_第3张图片

 

生活中的示例: 微信公众号、电视、黑板

分布式系统消息中间件-RabbitMQ介绍及其应用_第4张图片

 

分布式系统消息中间件-RabbitMQ介绍及其应用_第5张图片

 

1.2.3 消息中间件的组成

1、Broker:消息服务器,作为server提供消息核心服务

2、Producer:消息生产者,业务的发起方,负责生产消息传输给broker

3、Consumer:消息消费者,业务的处理方,负责从broker获取消息并进行业务逻辑处理

4、Topic:主题,发布订阅模式下的消息统一汇集地,不同生产者向topic发送消息,由MQ服务器分发到不同的订阅者,实现消息的广播

5、Queue:队列,PTP模式下,特定生产者向特定queue发送消息,消费者订阅特定的queue完成指定消息的接收

6、Message:消息体,根据不同通信协议定义的固定格式进行编码的数据包,来封装业务数据,实现消息的传输

1.2.4 消息中间件模式分类

1.2.4.1  P2P点对点

以队列作为通信载体,消息生产者生产消息发送到queue中,然后消息消费者从queue中取出并且消费消息。消息被消费以后,queue中不再存储,所以消息消费者不可能消费到已经被消费的消息。queue支持存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费。如下图所示:

           分布式系统消息中间件-RabbitMQ介绍及其应用_第6张图片

 

1.2.4.2  Pub/Sub发布订阅(广播)

使用topic作为通信载体,消息生产者(发布)将消息发布到topic中,同时有多个消息消费者(订阅)消费该消息。和点对点方式不同,发布到topic的消息会被所有订阅者消费。

queue实现了负载均衡,将producer生产的消息发送到消息队列中,由多个消费者消费。但一个消息只能被一个消费者接受,当没有消费者可用时,这个消息会被保存直到有一个可用的消费者。 topic实现了发布和订阅,当你发布一个消息,所有订阅这个topic的服务都能得到这个消息,所以从1到N个订阅者都能得到一个消息的拷贝。如下图所示:

           分布式系统消息中间件-RabbitMQ介绍及其应用_第7张图片

 

 

 

1.2.5 消息中间件的好处

1、低耦合:不管是程序还是模块之间,使用消息中间件进行间接通信。

2、异步通信能力:使得子系统之间得以充分执行自己的逻辑而无需等待。

3、缓冲能力:消息中间件像是一个巨大的蓄水池,将高峰期大量的请求存储下来慢慢交给后台进行处理,对于秒杀业务来说尤为重要。

4、伸缩性:是指通过不断向集群中加入服务器的手段来缓解不断上升的用户并发访问压力和不断增长的数据存储需求。就像弹簧一样挂东西一样,用户多,伸一点,用户少,缩一点。衡量架构是否高伸缩性的主要标准就是是否可用多台服务器构建集群,是否容易向集群中添加新的服务器。加入新的服务器后是否可以提供和原来服务器无差别的服务。集群中可容纳的总的服务器数量是否有限制。

5、可恢复性:当系统一部分组件失效时,不会影响到整个系统,消息中间件降低了进程间的耦合度,所以即使多个处理消息的进程挂掉,加入消息中间件中的消息仍然可以在系统恢复后进行处理。

6、扩展性:消息中间件解耦了应用的处理过程,所以提高消息入队和处理的效率是很容易的,只要另外增加处理过程即可,不需要改变代码,也不需要调节参数。

7、削峰:在访问量剧增的情况下,程序不会因为突发的超负荷请求而崩溃。

8、冗余(存储):有些情况下处理数据的过程会失败,造成数据丢失,可使用消息中间件进行数据持久化。

9、顺序保证:在大多使用场景下,数据处理的顺序都很重要。大部分消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。

 

  • RabbitMQ

2.1 什么是RabbitMQ?

RabbitMQ是一个开源的消息代理和队列服务器,用来通过普通协议在完全不同的应用之间共享数据,或者简单地将作业队列以便让分布式服务器进行处理。它现实了AMQP协议,并且遵循MPL开源协议,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。可以方便的和spring集成消息队列使用消息将应用程序连接起来,这些消息通过像RabbitMQ这样的消息代理服务器在应用程序之间路由。

2.2 RabbitMQ前提知识

2.2.1 什么是AMQP?

AMQP(Advanced Message Queuing Protocol),是一个提供统一消息服务的应用层标准协议,基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。

支持各种消息交换的体系结构:

存储转发(多个消息发送者,单个消息接收者)。

分布式事务(多个消息发送者,多个消息接收者)。

发布订阅(多个消息发送者,多个消息接收者)。

基于内容的路由(多个消息发送者,多个消息接收者)。

文件传输队列(多个消息发送者,多个消息接收者)。

点对点连接(单个消息发送者,单个消息接收者)。

2.2.2 什么是MPL?

是The Mozilla Public License的简写,是1998年初Netscape的 Mozilla小组为其开源软件项目设计的软件许可证。MPL许可证出现的最重要原因就是,Netscape公司认为GPL许可证没有很好地平衡开发者对源代码的需求和他们利用源代码获得的利益。其主要是用于开源补助保护。

2.2.3 什么是Erlang语言

Erlang是一种面向并发运行环境的通用编程语言。该语言由爱立信公司在1986年开始开发。设计之初,Erlang的开发者着眼于找到一种适用于开发大型电信交换设备的编程语言。

Erlang语言具有以下特征:

  1. 分布式运行环境:一个用Erlang开发的系统,其程序运行在一组被称为Erlang Node的物理节点上。可以用一个私有局域网内的若干台主机构成这些物理节点,也可以用通过使用TCP/IP套接字将更大范围中的物理节点连接起来组成一个系统。

 

  1. 基于编程语言本身的进程管理Erlang语言本身支持进程概念。一个Erlang系统中通常运行大量的进程(在电信交换系统中同时存在数百万进程并不让人惊讶),每个进程运行在一个Erlang Node上并可以跨Node创建其它进程。通常建议每个进程只处理轻量级的任务;如果有较复杂的大型任务需要处理,则软件设计人员应设法将大型任务尽可能分解成较小的任务,这样做的目的是尽可能充分发挥大规模分布式系统中所有物理节点的处理能力。

 

  1. 基于异步消息的进程问通信用传统语言编程通常都会用到复杂的共享内存管理机制,这也是用传统语言编程的一个容易出错的方;Erlang的各进程之间则完全不共享内存,进程之问的通信只通过异步消息来完成。

 

  1. 基于进程机制的软件出错处理:Erlang提供了定义“相连”进程的机制,即在进程之间可定义“相连”关系,当一个进程因出错而死亡时,向所有与其有“相连”关系的进程报告自身的死亡信息;收到死亡信息的进程如果是普通进程(区别于系统进程),则也立刻死亡(一旦出错,所有相连进程全部死亡);系统进程则可进行出错信息记录等操作,然后继续运行。

 

  1. 基于双机备份的容错机制:一个考虑了容错设计的Erlang系统至少要包含2个节点,它们之间互相监视;当一个节点出错岩机(无论是软件原因还是硬件故障),其工作立即由另一个节点接替。这种容错机制背后的理念是:一旦一个节点失效,则不再信任其能进行任何后续的故障处理;为保证容错,失效节点的职责必须立刻由其它节点接替。

2.3 RabbitMQ产生的背景

1、1983年最早的消息队列软件Teknekron诞生,当时仅用于一些金融交易等系统。

 

2、上世纪九十年代,诞生了多家消息队列系统,例如IBM MQ、微软的MSMQ、TIBCO MQ等消息队列在企业中的应用也愈加广泛。显然这些商用的消息队列系统如果企业要使用需要付出高昂的成本,并且各个消息队列之间使用不同的API不同的协议。

 

3、中小技术公司对高价格MQ供应商表示不满,金融服务公司也对此激动不起来,为了解决这个问题,Java Message Servive在2001年诞生了,JMS只需要针对JMS API编程,选择合适的MQ驱动即可,JMS会打理好其他部分,问题是你在尝试使用单独接口标准化来胶合众多不同的接口,就想把不同类型的衣服黏在一起,缝合处终究会裂开,使用JMS的应用程序会变得更加脆弱,我们需要新的消息通信标准化方案

 

4、2004年,AMQP(Advanced Message Queuing Protocol,高级消息队列协议)开始开发。通过这一标准可以和任意AMQP供应商提供的MQ服务进行交互。

 

5、2006年,Rabbit科技有限公司使用Erlang语言实现了AMQP开源版本,RabbitMQ诞生了,同年AMQP协议首次发布。

 

6、为什么要叫RabbitMQ呢?根据《RabbitMQ实战》一书叙述:兔子行动非常迅速而且繁殖起来也非常疯狂,所以就把Rabbit用作这个分布式软件的命名。

 

7、为了解决什么类型问题?在Web应用高并发环境下,由于来不及同步处理,请求往往会发生堵塞。比如说,大量的insert、update请求同时到达mysql,会带来无数的行锁表锁,最后导致请求数过多,触发too many connections错误。

2.4 RabbitMQ与其他MQ对比

目前较为常用的分布式消息中间件主要有ActiveMQ,RabbitMQ,Kafka,RocketMQ等。这里就拿ActiveMQ,RabbitMQ,Kafka,RocketMQ这四个分布式消息中间件进行对比。

Apache ActiveMQ是Apache软件基金会所研发的开放源代码消息中间件;由于ActiveMQ是一个纯Java程序,因此只需要操作系统支持Java虚拟机,ActiveMQ便可执行。

Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据。 Kafka的目的是通过Hadoop的并行加载机制来统一线上和离线的消息处理,也是为了通过集群来提供实时的消息。

RocketMQ是一款分布式、队列模型的消息中间件,是阿里巴巴集团自主研发的专业消息中间件,借鉴参考了JMS规范的MQ实现,更参考了优秀的开源消息中间件KAFKA,实现了业务消峰、分布式事务的优秀框架。产品基于高可用分布式集群技术,提供消息订阅和发布、消息轨迹查询、定时(延时)消息、资源统计、监控报警等一系列消息云服务,是企业级互联网架构的核心产品。MQ 历史超过9年,为分布式应用系统提供异步解耦、削峰填谷的能力,同时具备海量消息堆积、高吞吐、可靠重试等互联网应用所需的特性,是阿里巴巴双11使用的核心产品。

 

四者的比较:

分布式系统消息中间件-RabbitMQ介绍及其应用_第8张图片

 

 

 

 

2.5 RabbitMQ应用场景架构

 

             分布式系统消息中间件-RabbitMQ介绍及其应用_第9张图片

对于这个应用场景架构,通过以下几个概念的讲解就能够大致理解过程。

 

RabbitMQ Server:是一种传输服务,负责维护一条从Producer到Consumer的路线,保证数据能够按照指定的方式进行传输。但是这个保证也不是100%的保证,但是对于普通的应用来说这已经足够了。当然对于商业系统来说,可以再做一层数据一致性的guard,就可以彻底保证系统的一致性了。

 

Client P:也叫Producer,数据的发送方。创建Message并将其发布到代理服务器。一个Message有两个部分:Payload(有效载荷)和Label(标签)。Payload顾名思义就是传输的数据,Label是Exchange的名字或者说是一个tag,它描述了payload,而且RabbitMQ也是通过这个label来决定把这个Message发给哪个Consumer。AMQP仅仅描述了label,而RabbitMQ决定了如何使用这个label的规则。

 

Client C:也叫Consumer,数据的接收方。消费者连接到代理服务器(RabbitMQ)并订阅队列。把queue比作是一个有名字的邮箱。当有Message到达某个邮箱后,RabbitMQ把它发送给它的某个订阅者即Consumer。当然可能会把同一个Message发送给很多的Consumer。在这个Message中,只有payload,label已经被删掉了。对于Consumer来说,它是不知道谁发送的这个信息的,就是协议本身不支持。

 

Exchanges:是生产者发布信息的地方。消息交换机可指定消息按什么规则,路由到哪个队列。

Queues:队列是消息结束并由使用者接收的地方。每个消息都会被投入到一个或多个队列

 

Bindings:绑定是消息从交换器路由到特定队列的方式,作用就是把exchange和queue按照路由规则绑定起来。

2.6 RabbitMQ六大工作模式

根据RabbitMQ官方网站,创建消息传递应用程序的工作模式主要分为6种。如下图所示:

 

                分布式系统消息中间件-RabbitMQ介绍及其应用_第10张图片

 

2.6.1 simple简单模式

                                        分布式系统消息中间件-RabbitMQ介绍及其应用_第11张图片

消息产生者P将消息放入消息队列中,消息的消费者C监听消息队列,如果队列中有消息,就消费掉,消息被拿走后,自动从队列中删除,但是消息从队列中消失后,消息可能没有被消费者正确处理,造成消息的丢失。上图中生产者发送消息到“hello”队列。消费者从该队列接收消息。

应用场景:聊天(中间有一个过渡的服务器;p端,c端)

2.6.2 工作队列

 

                                             分布式系统消息中间件-RabbitMQ介绍及其应用_第12张图片

消息产生者P将消息放入队列,消费者可以有多个。消费者1,消费者2,同时监听同一个队列,消息被消费者C1 C2共同争抢当前的消息队列内容,谁先拿到谁负责消费消息。但是在高并发情况下,默认会产生某一个消息被多个消费者共同使用,可以设置一个synchronized 保证一条消息只能被一个消费者使用。

应用场景:红包;大项目中的资源调度(任务分配系统不需知道哪一个任务执行系统在空闲,直接将任务扔到消息队列中,空闲的系统自动争抢)

 

2.6.3 publish/subscribe发布订阅(共享资源)

                                        分布式系统消息中间件-RabbitMQ介绍及其应用_第13张图片

X代表交换机即rabbitMQ内部组件,erlang 消息产生者是代码完成,代码的执行效率不高,消息产生者将消息放入交换机,交换机发布订阅把消息发送到所有消息队列中,对应消息队列的消费者拿到消息进行消费。

应用场景:邮件群发,群聊天,广播(广告)

 

2.6.4 routing路由模式

                             分布式系统消息中间件-RabbitMQ介绍及其应用_第14张图片

 

消息生产者P将消息发送给交换机X,按照路由判断,路由是字符串(info),当前产生的消息携带路由字符(对象的方法),交换机根据路由的key,只能匹配上路由key对应的消息队列,对应的消费者才能消费消息。一般都是根据业务功能定义路由字符串。从系统的代码逻辑中获取对应的功能字符串,将消息任务扔到对应的队列中。

应用场景:利用key路由,可以将程序中的错误封装成消息传入到消息队列中,开发者可以自定义消费者,实时接收错误。

2.6.5 topic 主题模式(路由模式的一种)

                       分布式系统消息中间件-RabbitMQ介绍及其应用_第15张图片

星号井号代表通配符,星号代表多个单词,井号代表一个单词,路由功能添加模糊匹配。

消息产生者P产生消息,把消息交给交换机。交换机根据key的规则模糊匹配到对应的队列,由队列的监听消费者接收消息消费。

 

2.6.6 远程过程调用(RPC)

                      分布式系统消息中间件-RabbitMQ介绍及其应用_第16张图片

 

MQ本身是基于异步的消息处理,前面的五种工作模式的所有的生产者(P)将消息发送到RabbitMQ后不会知道消费者(C)处理成功或者失败,甚至连有没有消费者来处理这条消息都不知道。但实际的应用场景中,我们很可能需要一些同步处理,需要同步等待服务端将我的消息处理完成后再进行下一步处理。这相当于RPC(Remote Procedure Call,远程过程调用)。

RPC工作方式对于RPC请求,客户端发送带有两个属性的消息: reply_to,设置为仅为请求创建的匿名独占队列;以及correlation_id,设置为每个请求的唯一值。请求被发送到rpc_queue队列。RPC worker即Server正在等待该队列上的请求。当出现请求时,它会执行该作业,并使用来自reply_to字段的队列将带有结果的消息发送回客户端。客户端等待回复队列上的数据。出现消息时,它会检查correlation_id属性。如果它与请求中的值匹配,则返回对应用程序的响应。

 

2.7 RabbitMQ实际应用场景

2.7.1 应用解耦

在订单-库存系统中,传统的下订单过程是下订单成功之后,立即减少库存,对库存系统有着强依赖,倘若库存系统出现问题,调用库存系统失败,则数据回滚,导致订单创建失败。

                      分布式系统消息中间件-RabbitMQ介绍及其应用_第17张图片

 

采用RabbitMQ以后的处理过程是,下订单成功之后,将消息写入消息队列,库存系统从消息队列里去取数据,执行自己减库存的操作,这样即便库存系统出现问题,订单依旧能够创建成功。但是这种方式容易造成订单与库存的数据不一致,要注意RabbitMQ的持久化或其它策略来保证数据的一致性。

                 分布式系统消息中间件-RabbitMQ介绍及其应用_第18张图片

 

 

2.7.2 异步处理

在用户注册后需要发送信息和邮件给用户的这个操作流程中,如果采用传统方式,则注册成功之后先发短信再发邮件两个串行操作,执行时间长。如果采用RabbitMQ的方式,注册成功之后将消息写入消息队列,写入的时间远小于发短信或邮件的时间,然后再去发短信和邮件,由于这两个操作基本同时进行,所以这两个操作可以看做是并行操作,大大节省时间。

                        分布式系统消息中间件-RabbitMQ介绍及其应用_第19张图片

 

2.7.3 流量削峰

在我们平时的秒杀活动中,往往都会因为流量过大,而导致应用挂掉。为了解决这个问题,一般在应用前端加入消息队列。当队列写入消息达到某一数值时,不再写入消息队列,而直接跳转到活动结束的页面,由于队列先进先出的这一特性,也能保证秒杀活动的秒杀顺序,当然我们也可以根据特定的秒杀规则来去读取队列。

                 分布式系统消息中间件-RabbitMQ介绍及其应用_第20张图片

 

  • 参考文献
  1. 百度百科.中间件.

https://baike.baidu.com/item/%E4%B8%AD%E9%97%B4%E4%BB%B6/452240?fr=aladdin

  1. 流苏.浅谈中间件.博客园

https://www.cnblogs.com/lz0504/p/9911206.html

  1. C语言中文网.什么是中间件?常见中间件有哪些?

http://c.biancheng.net/view/3860.html

  1. 百度百科.消息中间件

https://baike.baidu.com/item/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/5899771?fr=aladdin

  1. Java高级架构狮.应用消息中间件设计可以解决哪些实际问题?.简书

https://www.jianshu.com/p/f3211f420ad2

  1. 百度百科.消息队列

https://baike.baidu.com/item/MQ/9062942?fr=aladdin

  1. 刘欣.Java 帝国之消息队列.

https://mp.weixin.qq.com/s?__biz=MzAxOTc0NzExNg==&mid=2665513507&idx=1&sn=d6db79c1ae03ba9260fb0fb77727bb54&chksm=80d67a60b7a1f376e7ad1e2c3276e8b565f045b1c7e21ef90926f69d99f969557737eb5d8128&mpshare=1&scene=1&srcid=1019awkBx8kaLyFohcuW4Ee7

  1. Broken_心殇.消息中间件基础.博客园

https://www.cnblogs.com/BrokenHeart/p/10827900.html

  1. 51CTO.消息中间件:四种投递模式对比

https://developer.51cto.com/art/201911/606122.htm

  1. Gent.消息中间件及ActiveMQ介绍.segmentfault

https://segmentfault.com/a/1190000014958916

  1. Rabbitmq.RabbitMQ Tutorials

https://www.rabbitmq.com/getstarted.html

  1. Rabbitmq.HelloWorld

https://www.rabbitmq.com/tutorials/tutorial-one-java.html

  1. Rabbitmq.WorkQueues

https://www.rabbitmq.com/tutorials/tutorial-two-java.html

  1. Rabbitmq.Publish/Subscribe

https://www.rabbitmq.com/tutorials/tutorial-three-java.html

  1. Rabbitmq.Routing

https://www.rabbitmq.com/tutorials/tutorial-four-java.html

  1. Rabbitmq.Topics

https://www.rabbitmq.com/tutorials/tutorial-five-java.html

  1. Rabbitmq.RPC

https://www.rabbitmq.com/tutorials/tutorial-six-java.html

  1. Rabbitmq.RabbitMQ Features

https://www.rabbitmq.com/#features

  1. 百度百科.rabbitmq

https://baike.baidu.com/item/rabbitmq

  1. 百度百科.AMQP

https://baike.baidu.com/item/AMQP#3

  1. 百度百科.MPL

https://baike.baidu.com/item/MPL/6597839?fr=aladdin

  1. 百度百科.Erlang语言

https://baike.baidu.com/item/Erlang%E8%AF%AD%E8%A8%80

  1. 进击的辣条.RabbitMQ的优劣势及产生背景.博客园

https://www.cnblogs.com/wyt007/p/9073154.html

  1. GhostStories.RabbitMQ概述与背景.简书

https://www.jianshu.com/p/9d462cda67ef

  1. SoSo.我为什么要选择RabbitMQ ,RabbitMQ简介,各种MQ选型对比.SOJSON在线

https://www.sojson.com/blog/48.html

  1. Jcpp9527.MQ详解及四大MQ比较.CSDN

https://blog.csdn.net/wqc19920906/article/details/82193316

  1. 慕容云甲.RabbitMQ的应用场景、基本原理介绍.CSDN

https://blog.csdn.net/qq_14901335/article/details/80451052

  1. 猿的生活.RabbitMQ-架构及工作原理.CSDN

https://blog.csdn.net/maihilton/article/details/80928661

  1. 高广超.这也许是最全面透彻的一篇RabbitMQ指南.dbaplus

https://dbaplus.cn/news-141-1464-1.html

你可能感兴趣的:(消息队列)