Openstack 的主要组件有 Nova、Cinder、Neutron、Glance 等,分别负责云平台的计算、存储、网络资源管理。OpenStack 各组件之间是通过 REST 接口进行相互通信,而各组件内部则采用了RPC通信。
RPC即Remote Procedure Call(远程方法调用),是Openstack中一种用来实现跨进程(或者跨机器)的通信机制。Openstack中同项目内(如nova, neutron, cinder…)各服务(service)均通过RPC实现彼此间通信。Openstack中还有另外两种跨进程的通信方式:数据库和Rest API。
Openstack中服务主要以进程的形式实现。也可以以线程的形式实现,但是Python中的线程是协作模型,无法发挥系统中多CPU(或多CPU核心)的能力。RCP只定义了一个通信接口,其底层的实现可以各不相同。目前Openstack中的主要采用AMQP的实现满足组件内部的松耦合性。
AMQP即Advanced Message Queuing Protocol()是一种基于队列的可靠消息服务协议,具体可参考http://en.wikipedia.org/wiki/Advanced_Message_Queuing_Protocol。作为一种通信协议,AMQP同样存在多个实现,如Apache Qpid、RabbitMQ、ZeroMQ等。
AMQP 是一个定义了在应用或者组织之间传送消息的协议的开放标准 (an open standard for passing business messages between applications or organizations),它最新的版本是 1.0。AMQP 目标在于解决在两个应用之间传送消息存在的下列问题:
AMQP 使用异步的、应用对应用的、二进制数据通信来解决这些问题。
AMQP 模型有几个重要的概念:
AMQP 定义了三种类型的 Exchange,不同类型 Exchange 实现不同的 routing 算法:
AMQP工作原理:
消息发布者Publisher将Message发送给Exchange并且说明Routing Key。Exchange 负责根据 Message 的Routing Key和binding 的Message Queue进行路由,将 Message 正确地转发给相应的 Message Queue。监听在 Message Queue 上的 Consumer 将会从 Queue 中读取消息。
Routing Key 是 Exchange 转发信息的依据,因此每个消息都有一个 Routing Key 表明可以接受消息的目的地址,而每个 Message Queue 都可以通过将自己想要接收的 Routing Key 告诉 Exchange 进行 binding,这样 Exchange 就可以将消息正确地转发给相应的 Message Queue。
下面的图显示了整体AMQP模型:
Server就是中间件服务器:它是一个接受消息的数据服务器,并主要做两件事情,依据条件将消息路由给不同的消费者,当消费者消费速度不够快时,它会把消息缓存在内存或磁盘上。
在AMQP之前的服务器中,它们会通过实现了特定类型路由和缓存的庞大引擎来完成. AMQ模块使用较小的模块结合更多样和稳健的方案来实现. 它把这些任务分成了两个不同角色:
在交换器和消息队列之间有一个明显的界面,称为绑定(binding)。
下面的图展示了通过AMQ模块服务器的消息流:
一个AMQP消息由一组属性和不透明的内容组成。一个新消息是由生产者应用程序通过使用AMQP client API来创建的.生产者将“内容”附着在消息中,并对其设置一些消息“属性”。生产者使用路由信息来标记消息,其表面上类似于地址,但几乎可以创建任何模式。然后,生产者将消息发送到服务器上的交换器中。
当消息到达服务器时,交换器通常会将消息路由到一级存在于服务器上的消息队列中.如果消息不能路由,交换器会默默地丢弃或者将其返回给生产者. 生产者可以选择如何来处理未路由消息。
单个消息可存在于多个消息队列. 服务器可以不同方式进行处理,如通过拷贝消息或通过引用计数器等. 这不影响互操作性。然而,当一个消息被路由到多个消息队列时,它在每个消息队列上都是一样的。没有独特的标识符来区分不同的副本。
当消息到达消息队列时,消息队列会通过AMQP,立即尝试将消息传递给消费者应用程序.如果不行,消息队列会存储消息(按发布者要求存储在内存或磁盘中),并等待消费者准备好.如果没有消费者,消息队列通过AMQP将消息返回给生产者(再次地,如果生产者对此有要求的话)。
当消息队列把消息投递给消费者后,它会从内部缓冲区中删除消息.这有可能立即发生,也有可能在消费者应答它已成功处理之后删除.消费者可选择如何以及何时来应答消息.同样地, 消费者也可以拒绝消息(一个否定应答)。
生产者消息和消费者应答可以组成事务. 当一个应用程序同时扮演两种角色时,通常它会做混合工作:发送消息和发送应答,然后提交或回滚事务。
从服务器投递消息给消费者,这个过程不是事务的,它只能通过消息应答来处理。
交换器是一个虚拟主机内的消息路由代理。交换器实例(我们通常称之为“交换器”)接受消息和路由信息-主要是一个路由键-或者将消息传递到消息队列,或到内部服务。交换器是基于每个虚拟主机命名的。
应用程序可以在权限范围内自由地创建、共享、使用和销毁交换器实例。交换器可能是持久的、临时的或自动删除的。持久化的交换器会持续到他们被删除,临时的交换器会持续到服务器关闭。自动删除的交换器直到他们不再使用。服务器提供了一组特定的交换器类型。每个交换器类型都实现了一个特定的匹配和算法,如下一节中定义的。AMQP只要求少量的交换器类型,并推荐了一些。此外,每个服务器实现可以添加自己的交换类型。
交换器可以将单个消息并发地路由到的消息队列中。这将创建一个独立消息的多个实例。
direct 交换器按如下方式来工作:
1. 消息队列使用路由键K来绑定交换器
2. 发布者使用路由键R来向交换器发送消息
3. 在K=R时,消息会传递到消息队列中
Direct 类似于我们生活中的快递, 填写对方的地址, 邮局会根据唯一地址, 来投递邮件。
1) [Producer] 在消息体中, 填写 Routing key
2) [Exchange] 根据Routing key, 在 Binding 中查找和Routing key绑定的 Queue
3) [Exchange] 发送消息到Queue
topic交换器类型按如下方式来工作:
1. 消息队列使用路由模式P来绑定到交换器
2. 发布者使用路由键R来向交换器发送消息
3. 当R匹配P时,消息将被传递到消息队列
用于topic交换器的路由键必须由0个或多个由点号.分隔的单词组成。每个单词必须包含字母A-Z和a-z 以及数字0-9。路由模式与路由键遵循相同的规则,* 用于匹配单个单词,# 用于匹配0个或多个单词。
因此路由模式*.stock.# 会匹配路由键usd.stock 和eur.stock.db 但不匹配stock.nasdaq。
Topic Exchange 和Direct Exchange比较类似, 但是Topic Exchange支持模糊匹配 (#, * 等等)。
Topic 类似于我们生活中的报刊订阅. 使用关键字”体育”订阅杂志后, 邮局会把”体育周刊” 和”体育日报” 都发送给你。
1) [Producer] 在消息体中, 填写 Routing key
2) [Exchange] 根据Routing key, 在 Binding 中, 通过模糊匹配, 查找和Routing key绑定的 Queue
3) [Exchange] 发送消息到Queue
fanout交换器类型按如下方式来工作:
1. 消息队列不使用参数来绑定交换器
2. 发布者向交换器发送消息
3. 消息无条件传递给消息队列
Fanout Exchange 不需要任何 Routing key
Fanout 类似于我们生活中的广播. 任何人无需订阅, 都可以收听到
Fanout Exchange 接收到消息之后, 会把消息发送给所有绑定的Queue中
http://www.amqp.org/
http://www.blogjava.net/qbna350816/archive/2016/08/12/431554.html
https://www.ibm.com/developerworks/cn/cloud/library/1403_renmm_opestackrpc/
http://blog.csdn.net/zhengleiguo/article/details/26758413