Last Updated on

前言

这是相关技能的详解系列,是将东西整理归纳总结,系列的进行记录与分享,这种方式更有完善性,更能成体系的学习一个技能,方便我们掌握他,这也是我们这种系列的目标,希望在跟着学习了解完这个系列后,就能将其吸收为自己的东西。并且为后续的继续深入,打下一个基础。

后续我也将更多的将以前零散的东西整理成多个不同的系列,有序的完善整体的知识树。与大家共同学习共同成长

话不多说,下面进入正文

RabbitMQ是什么

什么是消息中间件

消息中间件是基于队列与消息传递技术,在网络环境中为应用系统提供同步或异步以及可靠的消息传输的支撑性软件系统,

一般在系统开发中,常用于将程序解藕,异步,在分布式环境下扩展进程间的通信等。MQ典型应用场景例如:

  • 异步处理。把消息放入消息中间件中,等到需要的时候再去处理。
  • 流量削峰。例如秒杀活动,在短时间内访问量急剧增加,使用消息队列,当消息队列
    满了就拒绝响应,跳转到错误页面,这样就可以使得系统不会因为超负载而崩溃。
  • 日志处理
  • 应用解耦。假设某个服务A需要给许多个服务(B、C、D)发送消息,当某个服务(例如B)不需要发送消息了,服务A需要改代码再次部署;当新加入一个服务(服务E)需要服务A的消息的时候,也需要改代码重新部署;另外服务A也要考虑其他服务挂掉,没有收到消息怎么办?要不要重新发送呢?是不是很麻烦,使用MQ发布订阅模式,服务A只生产消息发送到MQ,B、C、D从MQ中读取消息,需要A的消息就订阅,不需要了就取消订阅,服务A不再操心其他的事情,使用这种方式可以降低服务或者系统之间的耦合。

什么是AMQP

AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。Erlang中的实现有RabbitMQ等。

所以,总结为一句话就是,AMQP是一个开放的消息队列标准协议!,而RabbitMQ就是此协议的一个开源实现,所以RabbitMQ与AMQP的协议中的概念是高度重合的。这在下面讲到RabbitMQ的使用时,再详说。

RabbitMQ是什么

RabbitMQ是当前最主流的消息中间件之一!RabbitMQ是一个开源的AMQP实现!

RabbitMQ服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

当然RabbitMQ除了实现了AMQP协议外,也同时支持MQTT,STOMP,AMQP1.0,HTTP 和 WebSocket等协议,以满足不同场景下的使用。具体的可查看RAbbitMQ官方文档
https://www.rabbitmq.com/protocols.html

RabbitMQ 使用与概念

PS: 所有学习都应该以官方文档为准,所有博客信息都可能会有滞后性,不准确性。这也是我一直的准则,希望教会大家怎么看官方文档,怎么自我学习。
下面要介绍的内容,也可以直接看官方文档:https://www.rabbitmq.com/tutorials/amqp-concepts.html

RabbitMQ作为一个消息中间件,其中设计思路基本都来源于AMQP协议,主要有如下几个重要的概念:

  • Server:接收客户端的连接,实现AMQP实体服务。
  • Connection:连接,应用程序与Server的网络连接,TCP连接。
  • Channel:信道,消息读写等操作在信道中进行。客户端可以建立多个信道,每个信道代表一个会话任务。
  • Message:消息,应用程序和服务器之间传送的数据,消息可以非常简单,也可以很复杂。有Properties和Body组成。Properties为外包装,可以对消息进行修饰,比如消息的优先级、延迟等高级特性;Body就是消息体内容。
  • Virtual Host:虚拟主机,用于逻辑隔离。一个虚拟主机里面可以有若干个Exchange和Queue,同一个虚拟主机里面不能有相同名称的Exchange或Queue。
  • Exchange:交换器,接收消息,按照路由规则将消息路由到一个或者多个队列。如果路由不到,或者返回给生产者,或者直接丢弃。RabbitMQ常用的交换器常用类型有direct、topic、fanout、headers四种,后面详细介绍。
  • Binding:绑定,交换器和消息队列之间的虚拟连接,绑定中可以包含一个或者多个RoutingKey。
  • RoutingKey:路由键,生产者将消息发送给交换器的时候,会发送一个RoutingKey,用来指定路由规则,这样交换器就知道把消息发送到哪个队列。路由键通常为一个“.”分割的字符串,例如“com.rabbitmq”。
  • Queue:消息队列,用来保存消息,供消费者消费。

其结构大致如下:

如图,主要分为三部分:

  • 生产者
  • 消费者
  • 服务端

整个消息的发布与消费的流程大致如下:

  1. 生产者client端指定服务端地址以及vhost虚拟主机,连接服务端
  2. 建立连接后,创建Channel信道,设置此信道的属性。
  3. 通过信道,声明交换机,队列,绑定关系,以及相关属性
  4. 通过信道,发送Message消息到Exchange交换机
  5. 交换机通过binding绑定关系与RoutingKey路由键,将消息分发到对应的Queue队列
  6. 消费者client通过服务端地址以及vhost连接服务端
  7. 建立连接后,创建信道,设置信道属性
  8. 通过信道,开启消费者监听队列,从队列中获取消息进行消费
  9. 根据是否延迟确认,确认消息已经被正常消费成功后,消息从队列中删除

Exchange交换机类型

在上述结构中,生产者发送消息,并不是直接发送到队列的,而是发送到Exchange交换机,再由交换机分发到相应队列,没有匹配到队列则丢弃消息。根据Exchange的类型不同,可灵活实现常见的消息模式。

Exchange交换机共有四种类型:

  • direct
  • fanout
  • topic
  • headers

direct

Direct,完全匹配型交换机,此种类型交换机,通过RoutingKey路由键将交换机和队列进行绑定, 消息被发送到exchange时,需要根据消息的RoutingKey,来进行匹配,只将消息发送到完全匹配到此RoutingKey的队列。

如图,不同的key绑定不同的队列,实现不同消息分发至不同队列。

PS: 注意同一个key,可以绑定多个queue队列。如图中,当匹配到key1时,则会将消息分发送至queue1和queue2,这样两个队列都会有相同的消息数据。

fanout

Fanout,扇出类型交换机,此种交换机,会将消息分发给所有绑定了此交换机的队列,此时RoutingKey参数无效。

此种方式,最简单快速,性能最好,因为少了中间的匹配判断环节。

topic

Topic,主题类型交换机,此种交换机与Direct类似,也是需要通过routingkey路由键进行匹配分发,区别在于Topic可以进行模糊匹配,Direct是完全匹配。
Topic中,将routingkey通过"."来分为多个部分,通过如下功能字符来进行匹配:

  • "*":代表一个部分
  • "#":代表一个或多个部分

举个例子,加入绑定关系如下图:

然后发送一条信息,routingkey为"a.b.c.d",那么根据"."将这个路由键分为了4个部分,此条路由键,将会匹配:

  • a.b.c. :成功匹配,因为可以代表一个部分
  • a.b.# :成功匹配,因为#可以代表一个或多个部分
  • a..c.. : 成功匹配,因为第一和第三部分分别为a和c,且为4个部分,刚好匹配
  • .d : 成功匹配,因为最后一个部分为d,前面所有部分被#代表了

PS:如果绑定的路由键为 "#" 时,则接受所有消息,因为路由键所有都匹配

headers

Headers,headers信息类型交换机,此类型交换机不通过routingkey路由键来分发消息,而是通过消息内容中的headers属性来进行匹配。headers类型交换器性能差,在实际中并不常用。

虽然不常用,但也可以了解一下其,此种交换机不通过routingkey,但是通过headers进行绑定,也就是在声明binding绑定关系时,需要传入需要匹配的header的key/value键值对。

如图,绑定关系中,需要指定"x-match"匹配类型:

  • all:需要所有的key-value都匹配,才能匹配成功
  • any:只需要其中一个key-value匹配,就匹配成功

PS: 不常用,此种方式性能比较差,如果要使用此种方式,使用前可进行性能测试,确保符合业务场景的需求

尾声

RabbitMQ的基础介绍和四种交换机的类型已经介绍完了,对RabbitMQ的使用,大致就有了了解,当然这些都是RabbitMQ的常用基础知识,了解后,就会对RabbbitMQ有了个大概的了解。
实践是检验真理的唯一标准,下一篇我们就一起动手,搭建部署RabbitMQ。