Contents
  1. 1. Nova消息队列
  2. 2. Nova的RPC映射
    1. 2.1. Topic Publisher
    2. 2.2. Direct Consumer
    3. 2.3. Topic Consumer
    4. 2.4. opic Exchange
    5. 2.5. Direct Exchange
    6. 2.6. Queue Element
  3. 3. RPC Call
  4. 4. RPC Cast
  5. 5. AMQP代理负载

  最近需要在项目中使用到消息队列,虽然之前有过使用经验,但是因为当时并无具体要求,所以只是在看完RabbitMQ的tutorial之后就自行实现了,并不知道合理性和效率如何。所以在新的项目设计时,打算借鉴一下Openstack中AMQP的使用经验

Nova消息队列

  Openstack云选用AMQP作为其消息技术。AMQP代理,不管是RabbitMQ或者Qpid,位于两个Nova组件之间并允许它们以松耦合的风格通信。更准确地说,Nova组件之间使用RPC通信。但是这个机制是建立在发布/订阅机制之上的,它有以下优势:

  • 解耦client和Server(Client不需要知道Server的具体引用)

  • Client和Server完全异步(Client不需要Server在收到RPC call时同时执行)

  • 随机平衡远程调用(多个Servant时,优先分配空闲者处理调用)

  Nova使用direct, fanout,和topic Exchange。其架构如下图所示

  Nova通过一个封装和解封装消息到调用的类来实现RPC功能,包括请求/响应(rpc.call), 单向(rpc.cast)。每个Nova服务(计算,调度等)在初始化时都实现两个AMQP队列,一个接收带有NODE-TYPE.NODE-ID的routingkey(如 compute.hostname)的消息,另一个接受通用的带有NODE-TYPE的routingkey(如compute)的消息。前者将消息传递给特定的物理节点,例如,终止某个虚拟机实例时使用。这个API在调用是“请求/响应”类型时充当consumer,rpc.cast时仅为publisher。

Nova的RPC映射

  下图当Openstack云只部署和共享了一个实例时,消息Broker节点(RabbitMQ节点)的内部结构。

  每一个Nova组件都连接到消息Broker,根据它的特性(如计算节点还是网络节点),将队列当作Invoker(如调度器,API),或者是Worker(如计算,网络)。Invoker,Worker并不实际存在于Nova对象模型中,我们只是用它便于表述。

  Invoker通过两个操作将消息发送到消息队列中:

  1. rpc.call

  2. rpc.cast

  Worker组件接收来自队列的消息,并对rpc.call进行回复。

图中组件的说明:

Topic Publisher

  每当有任意call或者cast类型的调用时被激活,发送消息到队列中。每个Publisher问题连接到同一个Topic类型的Exchange,它的生命周期限于消息传递。

Direct Consumer

  只在rpc.call操作时激活,接收来自队列的消息。每个consumer通过专用Queue连接到唯一的direct Exchange,生命周期限于消息传递。Exchange和Queue的身份标识由UUID生成器决定,封装于Topic Publisher发布的消息中(限rpc.call)。

Topic Consumer

  Worker初始化时即激活并在生命周期内存在。它接收消息并调用与Worker角色适应的动作。Topic consumer通过专一或共有的Queue连接唯一的Topic Exchange,每个Worker都有两个topic consumer,一个只接收rpc.cast操作(连接到共享的topic exchange),另一个接收rpc.call操作(连接到唯一的topic.host exchange)。

opic Exchange

  位于虚拟主机(RabbitMQ提供的多租房机制)间的路由表,其类型(如topic, direct)决定路由策略。一个消息代理只有一个topic Exchange处理所有Nova中的Topic。

Direct Exchange

  rpc.call期间创建的路由表,在消息代理节点生命周期内将有许多这种类型的Exchange实例,和每个rpc.call对应。

Queue Element

  在消息被处理前缓存消息,可以是专用的也可以是共用的,具有同种属性的Worker共享使用相同routing Key的Topic队列。

RPC Call

  下图为rpc.call时消息的流向。

  1. Topic Publisher发送消息到队列系统,在此之前一个Direct Consumer被初始化以等待此次调用的响应。

  2. 当消息被传递到Exchange,路由到routingKey(如topic.host)对应的consumer,并由负责这个任务的worker处理。

  3. 任务处理完后,分配一个Direct publisher来发送响应到队列系统。

  4. 当消息被Exchange分发以后,被具有对应routingKey(如msg_id)的consumer接收并传递给最初的RPC调用者。

RPC Cast

  下图为rpc.cast时消息的流向。

  1. 使用topic publisher来发送消息到队列系统

  2. 消息到达Exchange后,由有对应routingKey的topic consumer获取并传递给负责处理的Worker。

AMQP代理负载

  任何时候,消息代理的负载是以下参数的函数:

  1. API调用的吞吐量: Openstack云提供的rpc.call数量影响direct Exchange的数量,以及关联的Queue及consumer数量 。

  2. Worker数量: 相同属性的Wokers共享一个Queue,但是也有和Worker同样数量的专属Queue。Worker数量影响共享的Topic Exchange内的routingKey数量。

  下图展示了RabbitMQ节点Nova组件的bootstrap在测试环境中的状态。Exchange和queue包括:

Exchange

  1. Nova(topic exchange)

Queue

  1. compute.phantom

  2. compute

  3. network.phantom

  4. network

  5. scheduler.phantom

  6. scheduler

Contents
  1. 1. Nova消息队列
  2. 2. Nova的RPC映射
    1. 2.1. Topic Publisher
    2. 2.2. Direct Consumer
    3. 2.3. Topic Consumer
    4. 2.4. opic Exchange
    5. 2.5. Direct Exchange
    6. 2.6. Queue Element
  3. 3. RPC Call
  4. 4. RPC Cast
  5. 5. AMQP代理负载