分享

openstack之nova创建实例过程分析与rpc调用分析

eason 发表于 2016-2-25 17:04:54 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 2 28387
当我们在dashboard页面上生成新的实例的时候,整个流程是什么样子的呢?我粗略的总结了下
1.调用dashboard中的nova api的server_create方法,请求建立实例
2.nova api(nova/api/openstack/compute/servers.py)获得请求后,调用nova compute的api中的create方法创建实例(nova/compute/api.py),
3.然后调用nova conductor的api中的build_instances方法创建实例(nova/conductor/api.py)
4.然后调用nova conductor的rpcapi(nova/conductor/rpcapi.py)中的build_instances方法,发送创建实例的cast请求——build_instances
5.nova conductor的rpc server获得请求后(代码位于nova/conductor/manager.py),执行相应代码——调用nova scheduler获得host,创建并运行实例
6.然后调用nova compute的rpcapi(nova/compute/rpcapi.py)的build_and_run_instance方法,发送cast请求——build_and_run_instance
7.nova compute的rpc server获得请求后(nova/compute/manager.py),获得网络资源和block资源,调用相应的驱动(比如libvirt)创建实例


通过这个流程,发现代码从nova api到nova compute,在 到nova conductor,在到nova compute,为什么要这么做呢,因为官方想把conductor打造成一个编排任务的地方,让各个任务更专著的处理自己的事物。以下是官方介绍(http://docs.openstack.org/developer/nova/conductor.html
[mw_shl_code=applescript,true]API receives request to build an instance.
API sends an RPC cast to the conductor to build an instance. (or runs locally if conductor is configured to use local_mode)
Conductor sends an RPC call to the scheduler to pick a compute and waits for the response. If there is a scheduler fail it stops the build at the conductor.
Conductor sends an RPC cast to the compute to build the instance.
    If the build succeeds it stops here.
    If the build fails then compute sends an RPC cast to conductor to build an instance. This is the same RPC message that was sent by the API.

This new process means the scheduler only deals with scheduling, the compute only deals with building an instance, and the conductor manages the workflow. The code is now cleaner in the scheduler and computes.[/mw_shl_code]

以上是创建nova实例的粗略过程,方法调用使用了rpc(远程调用方法),但是rpc是如何实现的呢,这个花费了我一些时间,通过官方文档的介绍,rpc位于oslo.messaging中,通过创建rpc的client和server,client执行server上的方法来完成远程调用,其中server上有很多方法,client可以通过transport来执行
官方定义
[mw_shl_code=applescript,true]An RPC server exposes a number of endpoints, each of which contain a set of methods which may be invoked remotely by clients over a given transport.[/mw_shl_code]

client有两种调用方法,cast和call,cast是异步,执行之后不要求返回,call是同步,执行之后需要结果返回。client需要执行target,即消息发送的终点位置。
[mw_shl_code=applescript,true]target = messaging.Target(topic=CONF.conductor.topic,
                                  namespace='compute_task',
                                  version='1.0')
        serializer = objects_base.NovaObjectSerializer()
        self.client = rpc.get_client(target, serializer=serializer)[/mw_shl_code]
server端需要设置监听消息的范围和存在的方法,代码位于nova/service.py,同样需要指定target,server中的方法定义在endpoints中
[mw_shl_code=applescript,true]target = messaging.Target(topic=self.topic, server=self.host)

        endpoints = [
            self.manager,
            baserpc.BaseRPCAPI(self.manager.service_name, self.backdoor_port)
        ]
        endpoints.extend(self.manager.additional_endpoints)

        serializer = objects_base.NovaObjectSerializer()

        self.rpcserver = rpc.get_server(target, endpoints, serializer)
        self.rpcserver.start()[/mw_shl_code]

以上就是rpc调用的整个过程,分为client和server两部分。
但是我们接着思考,rpc是如何实现的呢,rpc中最重要的就是消息是如何传递的呢?这里用到了高级消息通信协议AMQP(Advanced Message Queuing Protocol),但是这只是一个协议,openstack采用的是rabbitmq,rabbitmq实现了amqp,但是openstack没有直接使用他,而是使用了kombu框架,因为kombu提供了一套傻瓜式的api,包装了rabbitmp,可以很方便的使用,所以rpc调用的是kombu的api。


对于kombu,最重要的是comumer和producer,producer产生信息,comsumer消费信息。
对于producer,他首先连接到rabbit server,然后生成一个queue,向消息塞queue中,
[mw_shl_code=applescript,true]from kombu import Connection
import datetime

with Connection('amqp://guest:guest@localhost:5672//') as conn:
    simple_queue = conn.SimpleQueue('simple_queue')
    message = 'helloword, sent at %s' % datetime.datetime.today()
    simple_queue.put(message)
    print('Sent: %s' % message)
    simple_queue.close()[/mw_shl_code]

对于consumer,首先连接到rabbit server,然后获得producer的queue,从queue中获取信息在处理
[mw_shl_code=applescript,true]from kombu import Connection

with Connection('amqp://guest:guest@localhost:5672//') as conn:
    simple_queue = conn.SimpleQueue('simple_queue')
    message = simple_queue.get(block=True, timeout=1)
    print("Received: %s" % message.payload)
    message.ack()
    simple_queue.close()[/mw_shl_code]


通过以上的小例子,基本可以了解rpc的实现,更多细节请查看kombu


参考文献
http://docs.openstack.org/developer/nova/rpc.html
http://docs.openstack.org/developer/oslo.messaging/
http://kombu.readthedocs.org/en/latest/
https://www.rabbitmq.com/tutorials/tutorial-one-python.html

已有(2)人评论

跳转到指定楼层
eason 发表于 2016-2-26 17:15:10
自己支持下自己
回复

使用道具 举报

潜龙慎用 发表于 2019-4-8 15:56:45
你好,想问一下,之前的版本是不是分别在rpcapi.py和manager.py中实现,现在都封装的oslo.messaging中了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条