前言
本文讲述的只是主要是RabbitMQ的入门知识,学习本文主要可以掌握以下知识点:
MQ 的发展史AMQP 协议Rabbit MQ 的安装Rabbit MQ 在 Java API 中的使用RabbitMQ 与 SpringBoot 的集成
MQ 的诞生历史
大部分技术的刚产生时适用范围都是特定的。比如互联网的产生,刚开始出现的通信协议各个产商之间是无法兼容的,随着历史的发展,产生了业内的通信标准tcp/ip协议,而MQ也是一样,第一款MQ类软件是由一个在美国印度人Vivek Ranadive创办的一家公司Teknekron,并实现了世界上第一个消息中间件The Information Bus(TIB)。
随着第一款MQ类软件TIB的诞生,各大厂商立刻跟进,百花争鸣,涌现了一批MQ类软件,比如IBM开发的IBM Wesphere,微软开发的MSMQ等等,但是正因为标准不统一,这就给我们使用者带来了很大的不便,每次切换MQ时都需要重复去实现不同的协议和不同API的调用。
2001年,Java语言的老东家Sun公司发布了一个JMS规范,其在各大产商的MQ上进行了统一封装,使用者如果需要使用不同的MQ只需要选择不同的驱动就可以了(和我们使用数据库驱动一个道理)。JMS规范虽然统一了标准,但是JMS规范却有一个很大的缺陷就是它是和Java语言进行绑定的,所以依然没有从根本上解决问题。
2004年,AMQP规范出现了,真正做到了跨语言和跨平台,自此MQ迎来了发展的黄金时代。
2007年,Rabbit公司基于AMQP规范开发出了一款消息队列RabbmitMQ。很快的,RabbitMQ就得到了大家的喜爱,被用户广泛使用。
什么是 MQ
MQ即:Message Queue,称之为消息队列或者消息中间件。MQ的本质是:使用高效可靠的消息传递机制来进行与平台无关的数据传递,并基于数据通信来进行分布式系统的集成。也就是说MQ主要是用来解决消息的通信问题,其主要有以下三个特点:
1、MQ是一个独立运行的服务。通过生产者来发送消息,使用消费者来接收消费。2、内部采用了队列来进行消息存储,一般采用的均是先进先出(FIFO)队列。3、具有发布订阅的模型,消费者可以根据需要来获取自己想要的消息。
为什么需要 MQ
以Java语言为例,JDK本身就提供了许多不同类型的队列,那么为什么还需要用MQ呢?这是因为:
1、跨语言。各大编程语言内部实现的队列是和语言绑定的,而且是单机的,在分布式环境下无法很好的工作,所以我们需要可以单独部署不依赖于语言的MQ。2、异步解耦。消息队列可以实现异步通信,这样发送消息方只需要关心消息是否发送成功,而接受消息方只需要关心怎么处理队列中的消息,实现了消费和生产者的解耦。3、流量削峰。因为消息队列是先进先出,所以如果把需要消费的消息放进队列,那么消费者就可以避免被瞬间大流量击垮,而是可以从容的根据自己的能力从队列中取出消息进行消费。
RabbitMQ
RabbitMQ中的Rabbit是兔子的意思,就是形容跑的和兔子一样快。其是一款轻量级的,支持多种消息传递协议的高可用的消息队列。RabbitMQ是由Erlang语言编写的,而Erlang语言就是一款天生适合高并发的语言。
RabbitMQ 的优势和特性
RabbitMQ作为一款非常流行的消息中间件,其有着非常丰富的特性和优势:
高可靠性:RabbitMQ提供了持久化、发送应答、发布确认等功能来保证其可靠性。灵活的路由:通过不同的交换机(Exchange)来实现了消息的灵活路由。集群与扩展性:多个节点可以组成一个逻辑上的服务器,支持负载。高可用性:通过镜像队列实现了队列中数据的复制,保证了在极端情况下部分节点出现crash整个集群仍然可用。支持多种协议:RabbitMQ最初是为了支持AMQP协议而开发的,所以AMQP是其核心协议,但是其也支持其他如:STOMP,MOTT,HTTP等协议。支持多客户端:RabbitMQ几乎支持所有常用语言客户端,如:Java,Python,Ruby,Go等。丰富的插件系统:支持各种丰富的插件扩展,同时也支持自定义插件。比如最常用的RabbitMQ后台管理系统就是以插件的形式实现的。
AMQP 模型
AMQP 全称是:Advanced Message Queuing Protocol。RabitMQ最核心的协议就是基于AMQP模型的AMQP协议,AMQP模型目前最新的版本是1.0版本,但是目前官方推荐使用者的最佳版本仍是基于0.9.1版本的AMQP模型,0.9.1版本在RabbitMQ官网中也将其称之为AMQP 0-9-1模型。
AMQP 0-9-1(高级消息队列协议)是一种消息传递协议,它允许符合标准的客户端应用程序与符合标准的消息传递中间件代理进行通信。消息传递代理(Broker)从发布者(Publisher,即发布消息的应用程序,也称为生产者:Producter)接收消息,并将其路由到使用者(消费者:Consumer,即处理消息的应用程序)。
AMQP 0-9-1模型的核心思想为:消息被发布到交换处,通常被比作邮局或邮箱。然后,交换机使用称为绑定的规则将消息副本分发到队列。然后,代理将消息传递给订阅了队列的使用者,或者使用者根据需要从队列中获取/提取消息。
下图就是一个AMQP模型简图,理解了这幅图,那么就基本理解了RabbitMQ的工作模式。
Producer 和 Consumer
Producer即生产者,一般指的是应用程序客户端,生产者会产生消息发送给RabbitMQ,等待消费者进行处理。
Consumer即消费者,消费者会从特定的队列中取出消息,进行消费。当消息传递给消费者时,消费者会自动通知Broker,Broker只有在收到关于该消息的通知时才会从队列中完全删除该消息。
Connection:我是一个 TCP 长连接
生产者发送消息和消费者接收消息之前都必须要和Broker建立一个tcp长连接,才能进行通信。
Channel:我是被虚构出来的
消息队列的作用之一就是用来做削峰,所以消息队列在高并发场景可能会有大量的生产者和消费者,那么假如每一个生产者在发送消息时或者每一个消费者在消费消息时都需要不断的创建和销毁tcp连接,那么这对Broker会是一个很大的消耗,为了降低这个tcp连接的创建频率,AMQP模型引入了Channel(通道或者信道)。
Channel是一个虚拟的的连接,可以被认为是轻量级的连接,其共享同一个tcp连接。在同一个tcp长连接里面可以通过创建和销毁不同的Channel来减少了创建和销毁tcp连接的频率,从而大大减少了资源的消耗。
客户端(生产者/消费者)执行的每个协议操作都发生在通道上。特定Channel上的通信完全独立于另一个Channel上的通信,因此每个协议方法还携带一个Channel ID(又称通道号)。
Channel只存在于连接的上下文中,不会独立存在,所以当一个tcp连接被关闭时,其中所有Channel也都会被关闭。
Channel是线程不安全的,所以对于使用多个线程/进程进行处理的应用程序,需要为每个线程/进程创建一个Channel,而不是共享同一个Channel。
Broker:我只是一个普通的代理商
Broker直接翻译成中文就是:中介/代理,所以如果我们使用的是RabbitMQ,那么这个Broker就是指的RabbitMQ服务端。
Exchange:我只是做一个消息的映射
Echange即交换机,因为要实现生产者和消费者的多对多关系,所以只有一个队列是无法满足要求的,那么如果有多个队列,每次我们发送的消息应该存储到哪里呢?交换机就是起到了中间角色的作用,我们发送消息到交换机上,然后通过交换机发送到对应的队列,交换机和队列之间需要提前绑定好对应关系,这样消息就到了各自指定的队列内,然后消费者就可以直接从各自负责的队列内取出消息进行消费。
Queue:我才是真正存储消息的地方
消息发送到Broker之后,通过交换机的映射,存储到指定的Queue里面。
VHost:我只是一个命名空间而已
VHost类似于命名空间,主要作用就是用来隔离数据的,比如我们由很多个业务系统都需要用到RabbitMQ,如果是一台服务器完全可以满足要求,那就没必要安装多个RabbitMQ了,这时候就可以定义不同的VHost,不同的VHost就可以实现各个业务系统间的数据隔离。
RabbitMQ 的安装
RabbitMQ是用Erlang语言开发的,所以在安装RabbitMQ之前,需要先安装Erlang,RabbitMQ和Erlang之间有版本对应关系,这个需要注意,本文以Erlang 21.3和RabbitMQ3.8.4为例进行安装 。
安装Erlang:yum -y install gcc glibc-develmakencurses-devel openssl-devel xmlto perl wget//提前安装一些依赖,个人电脑依赖不同,可根据实际情况选择未安装的依赖进行安装wget http://erlang.org/download/otp_src_21.3.tar.gz 下载(也可以下载好传到服务器)tar -xvf otp_src_21.3.tar.gz//解压mkdir erlang//在指定目录,如/usr/local下创建erlang目录cd otp_src_21.3//切换到解压后的目录./configure --prefix=/usr/local/erlang//编译(路径根据实际情况选择)make