RabbitMQ:教程
RabbitMQ实战教程
1.什么是MQ?
-
消息队列(Message Queue,简称MQ),从字面意思上看,其本质无非就是个队列,FIFO先入先出(排队买票,先到先得,买定离手),只不过队列中存放的内容是message而已。
-
其主要用途:不同的进程Process/线程Thread之间通信。
为什么会产生消息队列?有几个原因:
-
不同进程(proess)之间传递消息时,两个进程之间耦合度过高,改动一个进程,引发必须修改另一个进程(或者说一个系统或者功能的改变,必然导致另外一个系统或者功能的改变),为了隔离这两个进程,这就需要在这两个进程之间隔离出一个单独的模块,在两个进程之间抽离出一层(一个模块),所有两进程之间传递的消息,都必须通过消息队列来传递,单独修改某一个进程,不会影响另一个;
-
不同进程(proess)之间传递消息时,为了实现标准化,将消息的格式规范化了,并且某一个进程接收的消息太多,一下子无法处理完,并且也有先后顺序,必须对收到的消息进行排队,因此诞生了事实上的消息队列;
-
现在市面上的MQ框架还是非常之多的,比较流行的有RabbitMQ、ActiveMQ、ZeroMQ、kafka、以及阿里开源的RocketMQ。我这里暂时只介绍RabbitMQ。
2.RabbitMQ
2.1 RabbitMQ的简介
- MQ为Message Queue,消息队列是应用程序和应用程序之间的通信方法。
- RabbitMQ是一个开源的,在AMQP基础上完整的,可复用的企业消息系统。
- 多种开发语言支持:Java、Python、Ruby、.NET、php、C/C++、node.js等。
- 开发语言:Erlang - 面向并发的编程语言。
AMQP:消息队列的UI个协议。AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。Erlang中的实现有RabbitMQ等。
其中:ActiveMQ是JMS消息服务器
Kafa是分布式订阅消息系统
3.RabbitMQ主要特性
-
可伸缩性:集群服务
-
消息持久化:从内存持久化消息到硬盘,再从硬盘加载到内存
4.消息使用及展示
RabbitMQ的作用:作为一个中间件存储消息
- 一对一消息分发:
- 一对多消息分发(多系统消费):
- 多对多处理消息(分布式分发-消费):
- 特殊/常见场景(消息推送、异步通知):
- 常见场景:日志划分
基于消息通信的RPC调用 之 RabbitMQ分析
一、openstack Nova的服务间通信机制
Openstack Nova中是由许多组件构成的。而不同的服务之间,都是通过RPC来实现通信。同时,由于采用的是AMQP协议,因此组件之间具有很强的松耦合性。表现在:
(1)、客户端(发布者)无需知道服务器(订阅者)的具体位置
(2)、服务器无需和客户端同步运行。当客户端发起RPC调用,服务器可能并未运行。
(3)、远程调用的随机均衡性。当客户端发起RPC调用时,服务器不止一个。此时,可以随机选择一个服务器来处理消息。
二、Nova远程调用的方式
(1)、两种远程调用方式------rpc.call和rpc.cast。
(2)、rpc.call方式是指request/response方式。当客户端向服务器端发起RPC调用时,还需获取服务器端的响应(有返回值的远程过程调用)。
(3)、rpc.cast方式是指客户端发起RPC调用后,不需要获取服务器端的响应(不带返回值的远程过程调用)
(4)、处理rpc.call方式的远程调用,Nova采用两种消息交换方式:答案交换方式(direct exchange)和话题交换方式(topic exchange)方式。其中话题交换方式主要用于客户端发起远程调用(rpc.call和rpc.cast),答案交换方式主要用于服务器端返回rpc.call调用的结果。
(5)、Nova定义了话题/答案订阅者、话题/答案发布者以及话题/答案交换器等部件。各个部件的结构图如下所示:
Invoker是指RPC调用的发起方,而Woker是指RPC调用的执行方。
a、一个主题交换器可以关联多个队列,而一个直接交换器只能关联一个队列。
在直接交换器中,发布者、交换器、队列和消费者都是唯一的。消费者和发布者之间建立了一个专门的通路,就是"直接"的意义。
b、一个主题交换器可以关联多个队列,而每个队列都关联一个主题。主题交换器中,共有topic和topic.host两种类型的主题。
topic.host类型的主题是指订阅者直接点名需要哪台服务器进行响应。例如:当收到关闭虚拟机请求时,Nova-scheduler会调用虚拟机所在主机的Nova-compute来关闭相应虚拟机。
topic类型的主题是指发布者不指定响应的服务器,而是指定消息的主题。此时,交换器将会随机选择一个消费者处理RPC请求。
显然topic类型的主题可以方便实现负载均衡。例如:在openstack中可以创建多个scheduler节点。当客户端发送创建虚拟机的请求时,会随机选择一个scheduler节点处理该请求。
三、各个部件详细说明
1、Topic Publisher(话题发布者或者会话发布者):
话题发布者的出现主要是rpc.call和rpc.cast函数调用被执行的时候。一个话题发布者实例主要是用来把一个消息推送至消息系统中。 每个会话发布者都是一直在链路上进行收听,当消息传输完毕的时候(比如rpc.cast)或者接收到响应之后(rpc.call),会话发布者的生命周期就结束了。
2、Direct Consumer(直接消费者/订阅者或者答案接收方):
当且仅当rpc.call操作被执行的时候,一个Direct Consumer就被唤起。一个实例化的答案接收方就会接收来自队列的响应消息。与会话发布者类似,生命周期是消息传输影响的。在队列中的消息,是通过一个UUID标识符进行区别的。这些UUID信息会在会话发起者发起会话就封装进去的。
3、Topic Consumer(话题消费者/订阅者或者会话接收方):
当Worker被实例化的时候,话题消费者就开始工作了。会话接收方的工作主要是从队列中接受消息,并将消息中的指令转化为相应的行动。一个会话接收方一直链接在相同的topic交换链路上,不管是通过共享的队列或者是独立排斥性的队列。
每个Worker有两个会话接收方,一个面向rpc.cast操作(连接到一个共享的消息队列,消息交换的标志是topic)
另一个会话接收方用于rpc.call的(连接到一个排斥性、独立的交换通道,交换的时候,消息交换的标志topic.host)
4、Direct Publisher(直接发送方或答案发布者):
当且仅当rpc.call请求到达workers之后,答案发送方就开始工作了。答案发送方的主要工作就是将Worker所做的工作的结果发送给会话接收方。答案发送方连接到一个基于答案的交换。交换之间的识别,主要通过进来的消息。
5、Topic Exchange(话题交换器):
这种交换主要基于一张依赖虚拟主机上下文的路由表,类型决定路由策略。例如:基于话题的交换或者基于答案的交换,会采用不同的策略。一个消息转发器中,针对一个topic的交换,也只有一个话题交换器。
6、Direct Exchange(答案交换器):
答案交换器主要是依赖rpc.call操作的。当rpc.call操作被调用的时候,答案交换器的路由表就产生了。在一个消息转发器的生命周期中,会有许多这种交换器。每个答案交换器都是为一个rpc.call服务。
四、总结
Nova定义的rpc.call和rpc.cast两种远程调用方式中,rpc.call比较复杂。简单介绍下rpc.call方式远程调用的流程。
1、客户端通过主题发布者向主题交换器发送RPC消息。主题交换器根据消息的类型,将消息保存在相应的队列中。
2、服务器端的主题消费者从队列中接收并处理RPC消息。
3、服务器端的主题消费者处理完消息以后,通过直接发布者将消息发送给客户端。
4、客户端通过直接消费者接收服务器返回的RPC结果。
rpc.call远程调用的流程如图: