openstack组件oslo.message之RPCServer实现

这一章主要讲openstack的组件oslo.message中RPCServer实现

在openstack中初始化一个RPC的server源代码:在/nova/rpc.py中

def get_server(target, endpoints, serializer=None):
    assert TRANSPORT is not None
    serializer = RequestContextSerializer(serializer)
    return messaging.get_rpc_server(TRANSPORT,
                                    target,
                                    endpoints,
                                    executor='eventlet',
                                    serializer=serializer)

首先看看messaging.get_rpc_server,文件位于oslo_messaging/rpc/server.py中

def get_rpc_server(transport, target, endpoints,
                   executor='blocking', serializer=None):
    """rpc_server代码结构
    """
    dispatcher = rpc_dispatcher.RPCDispatcher(target, endpoints, serializer)
    return msg_server.MessageHandlingServer(transport, dispatcher, executor)

exector参数控制如何接收和派遣传入消息,关于transport,dispatch,executor三者区别,引用一段代码注释Connect a transport to a dispatcher that knows how to process the message using an executor that knows how the app wants to create new tasks.transport是传输层,在消息中间件层接收消息,executor确定接收消息的线程模型,dispatch负责最终处理消息。

下面看下第一个类RPCDispatcher,文件位于oslo_messaging/rpc/dispatcher.py

class RPCDispatcher(object):
    """在PRC消息之下的消息调度
    """

    def __init__(self, target, endpoints, serializer):
        """rpc服务器调度的结构
        """

        self.endpoints = endpoints
        self.serializer = serializer or msg_serializer.NoOpSerializer()
        self._default_target = msg_target.Target()
        self._target = target
回到get_rpc_server方法,在分析下MessageHandlingServer类的初始化
class MessageHandlingServer(service.ServiceBase):
    """消息处理服务器
    """

    def __init__(self, transport, dispatcher, executor='blocking'):
        """消息处理服务器的结构
        """
        self.conf = transport.conf

        self.transport = transport
        self.dispatcher = dispatcher
        self.executor = executor
        //executor如果是blocking,则在新的线程处理消息,其他的则在当前线程处理消息
        if self.executor != "blocking":
            self._state_cond = threading.Condition()
            self._dummy_cond = False
        else:
            self._state_cond = _utils.DummyCondition()
            self._dummy_cond = True

        try:
            mgr = driver.DriverManager('oslo.messaging.executors',
                                       self.executor)
        except RuntimeError as ex:
            raise ExecutorLoadFailure(self.executor, ex)
        else:
            self._executor_cls = mgr.driver
            self._executor = None
            self._running = False

        super(MessageHandlingServer, self).__init__()
dispacher的参数是一个可调用的上下文和收到的消息字典,执行程序参数控制如何接收和派遣传入消息

在回到刚开始,rpcserver.start()方法的实现,rpc.get_server()返回的MessageHandingServer,所以start()方法也就是MessageHandlingServer的start方法

    def start(self):
        """start方法处理传递过来的信息
        """
        if self._executor is not None:
            return
        with self._state_cond:
            if self._executor is not None:
                return
            try:
                listener = self.dispatcher._listen(self.transport)
            except driver_base.TransportDriverError as ex:
                raise ServerListenError(self.target, ex)
            self._running = True
            self._executor = self._executor_cls(self.conf, listener,
                                                self.dispatcher)
            self._executor.start()
            self._state_cond.notify_all()

这种方法使服务器开始为传入的消息,通过轮询传输调度程序。消息直到调用stop()方法停止。下面来一句一句的分析

 listener = self.dispatcher._listen(self.transport)
这里调用的_listen是的transport类中的方法_listen

    def _listen(self, target):
        if not (target.topic and target.server):
            raise exceptions.InvalidTarget('A server\'s target must have '
                                           'topic and server names specified',
                                           target)
        return self._driver.listen(target)
如果没有指定target.topic和target.server则报错,必须要指定,下面看下listen的源码

    def listen(self, target):
        conn = self._get_connection(rpc_amqp.PURPOSE_LISTEN)

        listener = AMQPListener(self, conn)

        conn.declare_topic_consumer(exchange_name=self._get_exchange(target),
                                    topic=target.topic,
                                    callback=listener)
        conn.declare_topic_consumer(exchange_name=self._get_exchange(target),
                                    topic='%s.%s' % (target.topic,
                                                     target.server),
                                    callback=listener)
        conn.declare_fanout_consumer(target.topic, listener)

        return listener
首先获取一个连接,然后建立一个Listen对象

class AMQPListener(base.Listener):
    //AMQPListener的初始化
    def __init__(self, driver, conn):
        super(AMQPListener, self).__init__(driver)
        self.conn = conn
        self.msg_id_cache = rpc_amqp._MsgIdCache()
        self.incoming = []
        self._stopped = threading.Event()
        self._obsolete_reply_queues = ObsoleteReplyQueuesCache()
后来就是声明三个consumer,首先看看declare_topic_consumer()

    def declare_topic_consumer(self, exchange_name, topic, callback=None,
                               queue_name=None):
        """创建一个Topic的消费者."""
        consumer = Consumer(exchange_name=exchange_name,
                            queue_name=queue_name or topic,
                            routing_key=topic,
                            type='topic',
                            durable=self.amqp_durable_queues,
                            auto_delete=self.amqp_auto_delete,
                            callback=callback,
                            rabbit_ha_queues=self.rabbit_ha_queues)

        self.declare_consumer(consumer)
declare_topic_consumer()函数主要是封装一个Topic的消费者,然后看下Consumer的类

class Consumer(object):
    """Consumer类"""

    def __init__(self, exchange_name, queue_name, routing_key, type, durable,
                 auto_delete, callback, nowait=True, rabbit_ha_queues=None):
        """初始化Consumer类 exchange_name, routing_key,type, durable auto_delete等参数
        """
        self.queue_name = queue_name
        self.exchange_name = exchange_name
        self.routing_key = routing_key
        self.auto_delete = auto_delete
        self.durable = durable
        self.callback = callback
        self.type = type
        self.nowait = nowait
        self.queue_arguments = _get_queue_arguments(rabbit_ha_queues)
	
        self.queue = None
        self.exchange = kombu.entity.Exchange(
            name=exchange_name,
            type=type,
            durable=self.durable,
            auto_delete=self.auto_delete)
同样declare_fanout_consumer()方法实现和topic一样

def declare_fanout_consumer(self, topic, callback):
    """创建一个fanout的消费者."""

    unique = uuid.uuid4().hex
    exchange_name = '%s_fanout' % topic
    queue_name = '%s_fanout_%s' % (topic, unique)

    consumer = Consumer(exchange_name=exchange_name,
                        queue_name=queue_name,
                        routing_key=topic,
                        type='fanout',
                        durable=False,
                        auto_delete=True,
                        callback=callback,
                        rabbit_ha_queues=self.rabbit_ha_queues)

    self.declare_consumer(consumer)

继续回到前面看MessageHandingServer的start方法,现在已经将消息相关的exchange、queue都建立好了

            self._executor = self._executor_cls(self.conf, listener,
                                                self.dispatcher)
            self._executor.start()
开始调用blocking的start方法,执行监听过程

def start(self):
    self._running = True
    while self._running:
        with self.dispatcher(self.listener.poll()) as callback:
            callback()
关键进入self.dispatcher()的callbac()方法

def __call__(self, incoming):
    incoming.acknowledge()
    yield lambda: self._dispatch_and_reply(incoming)
第二行可以看到这里对消息做了一个ACK操作,当从incoming中取出后就要做ACK,执行完之后就要进行调度和回复具体看方法_dispatch_and_reply

    def _dispatch_and_reply(self, incoming, executor_callback):
        try:
            incoming.reply(self._dispatch(incoming.ctxt,
                                          incoming.message,
                                          executor_callback))
        except ExpectedException as e:
            LOG.debug(u'Expected exception during message handling (%s)',
                      e.exc_info[1])
            incoming.reply(failure=e.exc_info, log_failure=False)
        except Exception as e:
            exc_info = sys.exc_info()
            LOG.error(_LE('Exception during message handling: %s'), e,
                      exc_info=exc_info)
            incoming.reply(failure=exc_info)
            del exc_info
再分析_dispatch方法

 def _dispatch(self, ctxt, message, executor_callback=None):
        """将RPC消息发送到一个端点的方法
        """
        method = message.get('method')
        args = message.get('args', {})
        namespace = message.get('namespace')
        version = message.get('version', '1.0')

        found_compatible = False
        for endpoint in self.endpoints:
            target = getattr(endpoint, 'target', None)
            if not target:
                target = self._default_target

            if not (self._is_namespace(target, namespace) and
                    self._is_compatible(target, version)):
                continue

            if hasattr(endpoint, method):
                localcontext._set_local_context(ctxt)
                try:
                    return self._do_dispatch(endpoint, method, ctxt, args,
                                             executor_callback)
                finally:
                    localcontext._clear_local_context()

            found_compatible = True

        if found_compatible:
            raise NoSuchMethod(method)
        else:
            raise UnsupportedVersion(version, method=method)
这个方法首先做message到端点的映射,然后从消息中得到相关的method和一些参数信息。接下了就是遍历端点匹配target中的信息和message中的是否一致,如果匹配上则调用_do_dispatch方法。

    def _do_dispatch(self, endpoint, method, ctxt, args, executor_callback):
        ctxt = self.serializer.deserialize_context(ctxt)
        new_args = dict()
        for argname, arg in six.iteritems(args):
            new_args[argname] = self.serializer.deserialize_entity(ctxt, arg)
        func = getattr(endpoint, method)
        if executor_callback:
            result = executor_callback(func, ctxt, **new_args)
        else:
            result = func(ctxt, **new_args)
        return self.serializer.serialize_entity(ctxt, result)

你可能感兴趣的:(openstack,rabbitmq)