openstack中的AMQP & RPC
开始的时候我只是想要了解下opensatck中的消息队列如何工作的,消息从哪来怎样分发,到哪去。网上搜寻了写资料,看的似懂非懂,转天我发现已然成了浆糊,一般通信协议就那么回事,和咱打电话聊聊天差不多,不过晕就晕在概念太多,没分清层次,那就捋捋概念伐……
AMQP
AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。
你看,AMQP只是一个协议,是一个虚的东西,要说实的嘛,有啊,比如:
AMQP中有三个重要的角色(其实还有一个routing key,待会说它):
- Publisher: 消息的发出者
- Exchange: 消息的传递者
- Consumer: 消息的接收者
咔咔……整理的简明扼要啊(啪啪,让你多嘴)
好吧,看着几个角色就知道了,消息也无非是酱紫走的啦:
这就很像是你写了一封信,为了传递给收件人,首先需要信封把信的内容装起来,然后在信封上写好收件人的信息,再把信放到邮筒里,后面邮局会拿到信然后根据信封上的收件人信息来看最终把信给谁。你,也就是写信的人就是那个Publisher,邮局就是Exchange,收件人就是Consumer。
不同的Consumer会创建不同的Queue,然后将对应的Exchange绑定到Queue上。在消息的传递过程中,Publisher从来不会直接的把Message放到Queue中,也从来不管Message如何分发。Publisher只管准备好消息,然后上交给国家……不对,是交给Exchange,而Exchange做的事情也很简单,一手从Publisher拿到消息,然后就把消息扔到Queue中。
对于Exchange,这个扔就有学问了,怎么扔?扔到某一个Queue中,还是扔给多个Queue,或者扔垃圾桶里?实际上在Publisher发出消息的时候会附加一个条件,Exchange会根据这个条件来决定扔的方法,这个条件就是routing key
。Exchange有几种扔的方式:
- Direct Exchange: 点对点的方式,精确匹配routing key的Queue才能收到消息
- Fanout Exchange: 将消息广播给所有知道的Queue
- Topic Exchange:根据routing key进行模式匹配
Direct 方式图解:
Topic 方式图解
AMQP的其他概念,这篇文章介绍的很简练:AMQP基本概念
RPC
哎呀……这也是个协议,RPC(Remote Procedure Call Protocol)—-远程过程调用协议,干嘛用的呢?比如我想在远程节点调用一个方法,并且要知道结果,咋办咧……就得RPC了。在RPC中有两个角色,client和server。Client发起RPC请求,Server接收RPC请求然后调用本地的程序,再把结果返回给client。当然,这只是最简单的理解,实际RPC是为了方便构建分布式的应用更加容易,为此,RPC框架提供了一种方式,让使用者不必在意和区分是本地调用还是远程调用。
RPC调用分为两种方式:
- 同步调用: Client发出消息后,等待Server端执行完成并返回相应结果。
- 异步调用: Client发出消息后,不需要等待server执行完成。如果关心结果,可用其他方式获取结果,如果不关心则Server端不需要返回结果。
Openstack 通信原理
Openstack中有着众多组件,他们之间交互的信息也异常之多,这些消息都是通过rpc的方式进行的。Openstack中的rpc又是利用AMQP来实现的。每个Nova的组件都要连接消息队列中间件,可能是以消息的发出者的身份,比如:API、Scheduler,也可能是作为消息的接收者,比如:Compute、Network。消息的发出者通过rpc.call或者rpc.cast将消息发出到消息队列,消息的接收者从队列里获得消息,并对rpc.call的发出者返回结果。
rpc.call实现:
- 初始化一个topic publisher,将消息发送到消息队列,在此之前,初始化一个direct consumer,用来等待返回的结果
- 消息根据routing-key进行分发,被相应的topic consumer获取到,然后与进行处理
- 处理结束后,创建一个direct publisher,将结果发送到相应的消息队列
- 结果通过direct exchange分发到消息队列中被direct consumer获取
rpc.cast实现:
- 初始化Topic publisher,将消息发送到消息队列
- 根据routing key,exchage分发消息,相应的topic consumer获得消息并进行处理。
图中consumer均有两个队列,因为每一个nova服务都会初始化的时候创建两个队列,一个用来接收routing key匹配NODE-TYPE.NODE-ID
的消息,一个用来接收routing key匹配NODE-TYPE
的消息。
由于openstack中的rpc调用到处都是,为了方便维护和使用,就把rpc相关的功能打包成了一个库,奏是oslo.messaging了。openstack中使用的rabbitmq库是kombu,oslo.messaging是对其的一个封装。但是具体实现还没有看,以后再说。