内容


Openstack RPC 通信原理

Comments

OpenStack 背景

OpenStack 是当前热门的云服务平台,目前各大企业及个人都积极参与的开源项目,OpenStack 是由 NASA 和 RackSpace 合作研发的云计算平台,可以帮助企业实现类似于 Amazon EC2 和 S3 的云服务基础架构服务即 Iaas(Infrastructure as a Service)平台。

Openstack 的主要组件有 Nova、Cinder、Neutron、Glance 等,分别负责云平台的计算、存储、网络资源管理。OpenStack 各组件之间是通过 REST 接口进行相互通信,而各组件内部则采用了基于 AMQP 模型的 RPC 通信。在本文中,笔者将会以 OpenStack 块存储组件 Cinder 为例,分享 OpenStack RPC 机制的实现以及应用。文中所用的实验环境是 Linux 操作系统 Redhat 6.4 版本。

在讲述 OpenStack RPC 通信机制之前,首先介绍一下 cinder 系统架构,Cinder 主要由 3 个组件组成,cinder-api, cinder-scheduler 和 cinder-volume,如图 1 所示。

图 1. Cinder 系统架构
图 1. Cinder 系统架构
图 1. Cinder 系统架构

Cinder-api 是 cinder 服务的 endpoint,提供 rest 接口,负责处理 client 请求,并将 RPC 请求发送至 cinder-scheduler 组件。

Cinder-scheduler 负责 cinder 请求调度,其核心部分就是 scheduler_driver, 作为 scheduler manager 的 driver,负责 cinder-volume 具体的调度处理,发送 cinder RPC 请求到选择的 cinder-volume。

Cinder-volume 负责具体的 volume 请求处理,由不同后端存储提供 volume 存储空间。目前各大存储厂商已经积极地将存储产品的 driver 贡献到 cinder 社区。目前支持的后端存储系统,可参见:https://wiki.Openstack.org/wiki/CinderSupportMatrix

OpenStack RPC 通信

Openstack 组件内部的 RPC(Remote Producer Call)机制的实现是基于 AMQP(Advanced Message Queuing Protocol)作为通讯模型,从而满足组件内部的松耦合性。AMQP 是用于异步消息通讯的消息中间件协议,AMQP 模型有四个重要的角色:

  • Exchange:根据 Routing key 转发消息到对应的 Message Queue 中
  • Routing key:用于 Exchange 判断哪些消息需要发送对应的 Message Queue
  • Publisher:消息发送者,将消息发送的 Exchange 并指明 Routing Key,以便 Message Queue 可以正确的收到消息
  • Consumer:消息接受者,从 Message Queue 获取消息

消息发布者 Publisher 将 Message 发送给 Exchange 并且说明 Routing Key。Exchange 负责根据 Message 的 Routing Key 进行路由,将 Message 正确地转发给相应的 Message Queue。监听在 Message Queue 上的 Consumer 将会从 Queue 中读取消息。

Routing Key 是 Exchange 转发信息的依据,因此每个消息都有一个 Routing Key 表明可以接受消息的目的地址,而每个 Message Queue 都可以通过将自己想要接收的 Routing Key 告诉 Exchange 进行 binding,这样 Exchange 就可以将消息正确地转发给相应的 Message Queue。图 2 就是 AMQP 消息模型。

图 2. AMQP 消息模型
图 2. AMQP 消息模型
图 2. AMQP 消息模型

AMQP 定义了三种类型的 Exchange,不同类型 Exchange 实现不同的 routing 算法:

  • Direct Exchange:Point-to-Point 消息模式,消息点对点的通信模式,Direct Exchange 根据 Routing Key 进行精确匹配,只有对应的 Message Queue 会接受到消息
  • Topic Exchange:Publish-Subscribe(Pub-sub)消息模式,Topic Exchange 根据 Routing Key 进行模式匹配,只要符合模式匹配的 Message Queue 都会收到消息
  • Fanout Exchange:广播消息模式,Fanout Exchange 将消息转发到所有绑定的 Message Queue

OpenStack 目前支持的基于 AMQP 模型的 RPC backend 有 RabbitMQ、QPid、ZeroMQ,对应的具体实现模块在 cinder 项目下 Openstack/common/RPC/目录下,impl_*.py 分别为对应的不同 backend 的实现。在本文中将选择 Qpid 做为 RPC backend 进行分析学习,本文实验所使用的 Qpid 的版本为 Version 0.22。

Qpid 是 Apache 的一个开源项目,支持 AMQP 协议标准。Qpid 提供了 C++/Python/Java/C# 等主流编程语言的客户端库。

安装和配置 RPC 服务

想要使 cinder 通信机制正常工作必须要安装并启动 QPid server 服务

yum -y install qpid-cpp-server
service qpidd start

Cinder 需要配置 RPC backend,并且设置 Qpid server 信息,例如

RPC_backend=cinder.Openstack.common.RPC.impl_qpid     #RPC backend driver 配置
qpid_hostname = hostname    #qpid server 的主机名或者 IP 地址
qpid_port=port    #qpid server 端口号

OpenStack RPC 通信角色

在 RPC 通信中有两个角色:Client 和 Server。Client 发起 RPC 请求,Server 端接收 RPC 请求调用本地的程序执行,并将执行结果返回 Client。Openstack RPC 实现采用了 AMQP 机制,AMQP 模型中由两个重要角色 Publisher 和 Consumer,Openstack RPC 即利用了 Publisher 和 Consumer 实现 Client 和 Server 之间的 RPC 通信过程。

Publisher 就是用于发布消息,在 Openstack 内部有四种类型的 Publisher 负责不同类型的消息发布,分别是 Topic Publisher、Direct Publisher、Notification Publisher 和 Fanout Publisher。不同的 Publisher 分别对应 AMQP 模型中的三种类型 Exchange,其中 Nofication Publisher 其实就是 Topic Publisher 的一种。Qpid 模块中 Publisher 的 UML 如图 3 所示,从 UML 图中可以看出 RPC 通信的关键元素

图 3. Publisher
图 3. Publisher
图 3. Publisher
  • address:用于定义 Message 发送的目的地,类似于 Message 的门牌号号码。 Publisher 发送信息时,必须填写 address 才能够发送信息。Qpid address 的定义方式
address_string ::= <address> [ / <subject> ] [ ; <options> ]

address:就是用于标识 Exchange,相当于地区邮编

subject:就是 Routing Key,相当于门牌号码,也是 Exchange 的路由信息

options:Exchange 的属性信息,以 key-value 的格式进行描述

options ::= { <key> : <value>, ... }

例如, {‘create’: ‘always’} 表示如果 Exchange 不存在的话就创建,options 的选项有很多,有兴趣的朋友们可以直接查看 qpid 的 API 文档

  • Session:消息发送的会话,消息发送方和接受方通信需要依附于同一 session 保证消息的可靠性
  • Sender:qpid 提供的用于发送消息的方法

四种不同的 Publisher 在 RPC 通信有着不同的消息处理方式也有着不同的作用。

  • Direct Publisher:用于点对点的消息通信,在 OpenStack RPC 通信中用于建立 RPC 消息应答通路。创建或声明 Direct Exchange,用于 RPC 的消息返回,Exchange 的名字以消息 id 命名。
node_name: 
{
    "create": "always", 
    "node": {
        "type": "",  
        "x-declare": {
            "durable": False, 
            "auto-delete": True,  
        },
    },
}
  • Topic Publisher:用于 Publish-Subscribe(Pub-Sub)模式的通信,Topic Publisher 创建 Topic Exchange,用于 RPC 消息发送,并设置消息的 Routing Key 转发消息
node_name: 
{
    "create": "always",
    "node": {
        "type": "",         
        "x-declare": {
            "durable": False,
            "auto-delete": True,
        },
    },
}
  • Fanout Publisher:创建 Fanout Exchange,用于广播消息的发送,所有绑定到该 Exchange 的 Message Queue 都会接收到消息
node_name: 
{
    "create": "always",
    "node": {
        "type": "",
        "x-declare": {
            "durable": False,
            "auto-delete": True,
        },
    },
}
  • Notify Publisher:同 Topic Publisher,在 Openstack 系统中用于发送 Notification 相关的消息。
node_name: 
{
    "create": "always",
    "node": {
        "type": "",         
        "x-declare": {
            "durable": False,
            "auto-delete": True,
        },
    },
}

Consumer 就是消息接受方并处理消息调用服务方法,在 OpenStack 中定义了三种类型的 Consumer,如图 4 所示,分别是 Topic Consumer、Direct Consumer 和 Fanout Consumer,不同类型的 Consumer 也对应处理不同类型的 Message。Consumer 实际的工作是创建 Message Queue,并且设置 Routing Key,相当于在自己家门口安装了收信箱。Consumer 对象也有四个关键元素。

Address:Consumer 用于收取消息的地址,Message Queue 可以看做是用户自己安装的邮箱,并通知 Exchange 声明接受的 Message 地址。Exchange(邮局)会根据 Publisher 发送的 Message address 与 Consumer 声明的 address 进行匹配并转发投送到用户的邮箱即 Message Queue 中。Message Queue 的建立也是根据 address 来创建的,根据 address 的 options 中增加 key 为 link 的项,value 部分用于描述 Queue 的具体信息。

Reciever: qpid 提供的用于获取消息方法

Session: 同 Publisher。

Callback:回调对象,即 RPC 服务提供者,根据消息内容调用具体的处理方法

图 4. Consumer
图 4. Consumer
图 4. Consumer

不同类型的 Consumer 创建不同的 Message Queue 并绑定到对应的 Exchange 用于接收不同类型的消息

  • Direct Consumer:接收 Direct Exchange 发送的消息,创建专属的 Message Queue,即 Message Queue 的消息只能由创建 Message Queue 的 Consumer 获取,地址描述如下
node_name: 
{
    "create": "always",
    "node": {
        "type": "",    
        "x-declare": {
            "durable": True,
            "auto-delete": True,
        },
    },
    "link": {                  
        "name": ,       
        "durable": True,
        "x-declare": {
            "durable": False,
            "auto-delete": True,
            "exclusive": ,  
        },
    },
}
  • Topic Consumer:接收 topic Exchange 根据 Routing Key 转发的消息,创建的 Message Queue 是可共享的,这就意味着多个 Consumer 可以订阅同一个 Message Queue,并从其中读取消息
node_name: 
{
    "create": "always",
    "node": {
        "type": "",          
        "x-declare": {
            "durable": True,
            "auto-delete": True,
        },
    },
    "link": {
        "name": 
        "durable": True,
        "x-declare": {
            "durable": False,
            "auto-delete": True,
            "exclusive": ,    
        },
    },
}
  • Fanout Consumer:接收 Fanout Exchange 广播的消息,并创建专属的 Message Queue
node_name: 
{
    "create": "always",
    "node": {
        "type": "",           
        "x-declare": {
            "durable": False,
            "auto-delete": True,
        },
    },
    "link": {
        "name": ,   
        "durable": True,
        "x-declare": {
            "durable": False,
            "auto-delete": True,
            "exclusive": ,       
        },
    },
}

RPC 发送请求

Client 端发送 RPC 请求由 publisher 发送消息并声明消息地址,consumer 接收消息并进行消息处理,如果需要消息应答则返回处理请求的结果消息。OpenStack RPC 模块提供了 rpc.call,rpc.cast, rpc.fanout_cast 三种 RPC 调用方法,发送和接收 RPC 请求。

  • rpc.call 发送 RPC 请求并返回请求处理结果,请求处理流程如图 5 所示,由 Topic Publisher 发送消息,Topic Exchange 根据消息地址进行消息转发至对应的 Message Queue 中,Topic Consumer 监听 Message Queue,发现需要处理的消息则进行消息处理,并由 Direct Publisher 将请求处理结果消息,请求发送方创建 Direct Consumer 监听消息的返回结果
  • rpc.cast 发送 RPC 请求无返回,请求处理流程如图 6 所示,与 rpc.call 不同之处在于,不需要请求处理结果的返回,因此没有 Direct Publisher 和 Direct Consumer 处理。
  • rpc.fanout_cast 用于发送 RPC 广播信息无返回结果
图 5. RPC.call 消息流程
图 5. RPC.call 消息流程
图 5. RPC.call 消息流程
图 6. RPC.cast 消息流程
图 6. RPC.cast 消息流程
图 6. RPC.cast 消息流程
图 7. RPC.fanout 消息处理
图 7. RPC.fanout 消息处理
图 7. RPC.fanout 消息处理

RPC 调用过程

RPC 请求处理由 Sever 角色负责,以 cinder 为例,cinder-api 是请求发起者即 Client,请求通过使用 RPC 方法发送给 cinder-scheduler,cinder-scheduler 负责处理请求则为 Server。

Server 负责处理请求,首先需要创建 Consumer。cinder-scheduler server 创建了 cinder-scheduler 和 cinder-scheduler:host 的 Topic Consumer 和 cinder-scheduler Fanout Consumer,分别用于接收不同类型的消息。Consumer 创建时,就会在 Qpid server 上创建对应的 Message Queue,并声明 Routing Key 绑定到 Exchange 上。Cinder-scheduler 服务启动时,将 cinder-scheduler manager 注册为了 RPC_dispatcher 即 callback 对象即 Client 发送的请求最终会有 cinder-scheduler manager 对象调用执行。启动 consumer 线程,接受 Queue 上的消息,当线程接收到 Queue 上消息后,将消息传递给 RPC_dispatcher 即 callback 对象,由 callback 对象根据消息内容,调用对应的处理函数,例如 create_volume,并处理请求。

创建 volume 的 RPC 通信过程

我们分析 cinder 创建 volume 的 RPC 消息的发送过程,从而更加深刻的理解 RPC 消息的处理流程。Create volume 的过程可以看做是两个阶段的 RPC 请求处理,第一阶段:

  1. Client 即 cinder-api 调用 RPC.cast 发送消息,RPC.cast 创建 Topic Publisher 对象,topic 为 cinder-scheduler,也就是消息的 Routing Key,Exchange name 为 OpenStack,消息体中标记了消息接收者即 Server 所需要调用的方法“create_volume”;
  2. Exchange 接收到消息,根据 Routing Key 将消息发送至 Message Queue cinder-scheduler 上,这个 Message Queue 是由 cinder-scheduler 服务的 Topic Consumer 订阅的,因此,cinder-scheduler 服务将接收到 create_volume 的消息
  3. Consumer 调用注册的 RPC_dispatcher,即 cinder-scheduler manager,然后由 cinder-scheduler manager 调用 RPC 处理方法 create_volume
图 8. Create volume 第一阶段
图 8. Create volume 第一阶段
图 8. Create volume 第一阶段

Create volume 请求的第二阶段由 cinder-scheduler 的 create_volume 方法调用发起,即 cinder-scheduler 使用 filter and weighing 算法选取了 cinder-volume 的 host 用于创建 volume,则调用 RPC.cast 请求向 host 发送 RPC 请求,这个阶段 cinder-scheduler 为请求发起者即 client,cinder-volume 为请求处理者即 server。

  1. Cinder-scheduler 调用 RPC.cast,Exchange name 为 Openstack, routing-key 为 cinder-volume:host
  2. Exchange 接收到消息,根据 Routing Key 将消息发送到队列 cinder-volume:host 上
  3. 在主机 host 上的 Cinder-volume consumer 从 Queue 中接收到 message,回调 RPC_dispatcher 即 cinder-volume manager
  4. Cinder-volume manger 根据消息体中 method 信息,调用 create_volume 方法,创建 volume
图 9. Create volume 第二阶段
图 9. Create volume 第二阶段
图 9. Create volume 第二阶段

Qpid 提供了客户端工具 qpid-tool,可以通过命令行查看 Qpid server 的当前状况,我们可以利用 qpid-tool 查看 Openstack 项目创建的 Exchange 和 Queue。

$qpid-tool localhost  #命令连接 Qpid server

进入命令行后,可以敲入 help 命令,查看可以使用的子命令,list 命令查看 Qpid 中的可以存在对象状况,如图 10 所示。

图 10. Qpid 存在的对象
图 10. Qpid 存在的对象
图 10. Qpid 存在的对象

list Exchange 可以查看 Qpid 存在哪些 Exchange,如图 11 所示,其中与 cinder 服务相关的 Exchange 有 OpenStack, cinder-volume_fanout, cinder-scheduler_fanout,reply_XXX。

Cinder-volume_fanout 负责将 Fanout Publisher 的请求发送到 cinder-volume_fanout_uuid 消息队列中;

Cinder-scheduler_fanout 负责将 Fanout Publisher 的请求发送到 cinder-scheduler_fanout_uuid 消息队列中;

Openstack 负责 Topic Publisher 的请求根据具体的 route key 发送到对应的消息队列中;

Reply_XXX 是由 Direct Publisher 创建用于消息处理返回结果通信。

图 11. OpenStack Exchange
图 11. Openstack Exchange
图 11. Openstack Exchange

list Queue 查看 Qpid 中的 Message Queue 创建状况,红框中为 cinder 服务创建的 Message Queue,Consumer 就是监听在自己创建的 Message Queue 上,并及时接收消息进行处理。

图 12. Openstack Queue
图 12. Openstack Queue
图 12. Openstack Queue

OpenStack Notification

OpenStack Notification 机制用于通知用户或者开发者当前请求执行状态,在 RPC 通信角色一节中介绍了 Notification Publisher,其实就是一种 Topic Publisher。

启用 Notification 机制,需要在 Cinder 配置文件中配置 notification_driver。

notification_driver = cinder.Openstack.common.notifier.RPC_notifier

Notification priority 提供了 DEBUG, WARN, INFO, ERROR, CRITICAL 五个级别的消息,Cinder 的 notification 的 Exchange name 是 Openstack,topic 是 notifications.priority,例如 notifications.info

接受 notification 的消息,可以使用 Qpid 提供的 sample 方法 drain,查看 Queue 接受到的消息,通常 drain 方法位于/usr/share/doc/python-qpid-0.18/examples/api/目录下,然后执行

./drain -t 1000 Exchange_name

Cinder 项目默认的 Exchange name 是 OpenStack,由于 Exchange 负责信息转发,因此能够看到所有流入 Exchange 的消息,如果我们仅想要查看 notification 类型的消息,也可以自己创建 Message Queue,使用 Routing key 绑定到 Exchange 上。

一种创建 Queue 的简单方法是使用 Qpid 提供的客户端工具 qpid-config。关于 qpid-config 工具的具体使用方法可以通过帮助文档来获取。

创建接受 notification INFO 级别的消息,则执行如下操作

  1. 创建 Queue
    qpid-config add Queue notification_info

    可以通过 qpid-tool 中使用 list Queue 查看已经创建了以 notification.info 为名的 Queue,这里仅仅是创建了 Message Queue

  2. 建立 Routing Key
    qpid-config [OPTIONS] bind   <Exchange-name> <Queue-name> [binding-key]
    qpid-config bind Openstack notification_info notifications.info

    建立了 Exchange 和 Message Queue 之间的路由关系,Routing Key 为 notifications.info,只要 Exchange 接收到 Routing Key 为 notifications.info 的消息将会将消息转发至名字为 notification_info 的 Queue 中

  3. 查看 notifications.info 的消息
    ./drain -t 1000 notification_info

    使用 cinder 命令创建一个 volume,则能够查看到 notifications.info 的消息内容了。

    取消订阅的消息也很简单,只需要接触绑定关系,并删除 Queue 就行了。

    qpid-config unbind Openstack notification_info notifications.info
    qpid-config del Queue notification_info

相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Cloud computing
ArticleID=966599
ArticleTitle=Openstack RPC 通信原理
publish-date=03272014