once you dive into the notifier(1)

事实上, 之前记录的是MQ,作为分布式架构,懂openstack不知道MQ是没办法进行下去的,但是说MQ的网上教程实在太多了,既然是记录的转化,实在是没必要抄一遍,

还是把一些自己的理解记下来吧。

在使用MQ(消息队列)之前,做过rest的项目,用NIO写过异步网络通信进行RPC调用,可能有的人还用过RMI或者其他的远程调用与通信。同事ZCF问我项目里面

到底是使用rest call还是MQ,我回答说,这两个感觉很像,但是放在一起说是不合适的,rest是一种提供服务的方式,让功能条例化,清晰化,很好的控制系统暴露的

功能与方式,用MQ(自己用NIO写RPC,越写越多就可能会成为一个MQ,当然MQ的东西水也挺深)更多的是解耦,我认为这句话是最合适的,一个大型分布式系统,

“大型”和“分布式”缺一不可,功能繁杂,并行开发使用MQ解耦系统功能是再好不过的,除了提升开发效率,对系统维护功能拓展也很好,作为基础架构云平台,

openstack使用MQ几乎是不二之选。


不看具体的MQ,我们要想实现自己的MQ,有哪些功能:

1. client端实现发送消息, 由于MQ的异步性,我们可能需要queue来让message排队

2. server端要能从queue里面把message拿出来,处理之后给出返回

3. server端响应可能是同步的,也可能是异步的

4. 一条消息可能需要被多个server端接收,也可能被某一个server接收,不该接收消息的绝对不能收到消息,该收到的不能丢失

5. 可能需要接收某一类消息,比如一个节点需要接收所有的报警消息

6. 如果属于新老系统交替时,新老系统的服务同时开启,一条消息可能是发给特定版本系统的,且消息格式只有该版本系统才能处理

7. 消息队列一旦down了,重启之后未成功发送的消息需要"复活",因此消息需要一定程度的持久化

等等。

当然了一个具体的MQ实现涉及面很多,IBM给银行使用的消息中间件以稳定诸城可不便宜。

在上面的功能基础上,我们能想到的function:

rpc.call(同步调用,处理完返回)

rpc.cast(异步,发出去让server处理即可)

call或者cast调用发出的message以什么方式发给什么server,需要router(exchanger),exchanger决定消息:

发给某个特定的server(direct模式)

发给某个topic的server(topic模式)

发给所有server(fanout模式)

消息经过router(exchanger)到某个server,消息很多时需要排队,需要queue

server端consume消息,进行处理。


到这里已经和openstack的MQ功能很像了,早先的openstack没有对消息队列进行很多的封装,现在MQ的功能放在oslo的messaging中,

看openstack源码我们常能看到这些概念:

target, publisher, consumer, transport, serializer等

分别来看看:

transport:

client和server均需指定,在nova/rpc.py中:

TRANSPORT = messaging.get_transport(conf, allowed_remote_exmods=exmods,aliases=TRANSPORT_ALIASES)

TRANSPORT_ALIASES = {
    'nova.openstack.common.rpc.impl_kombu': 'rabbit',
    'nova.openstack.common.rpc.impl_qpid': 'qpid',
    'nova.openstack.common.rpc.impl_zmq': 'zmq',
    'nova.rpc.impl_kombu': 'rabbit',
    'nova.rpc.impl_qpid': 'qpid',
    'nova.rpc.impl_zmq': 'zmq',
}

进入/usr/lib/python2.7/site-packages/oslo/messaging包,在transport.py中get_transport方法,我们看到:

    kwargs = dict(default_exchange=conf.control_exchange,
                  allowed_remote_exmods=allowed_remote_exmods)
    try:
        mgr = driver.DriverManager('oslo.messaging.drivers',
                                   url.transport,
                                   invoke_on_load=True,
                                   invoke_args=[conf, url],
                                   invoke_kwds=kwargs)
    except RuntimeError as ex:
        raise DriverLoadFailure(url.transport, ex)

    return Transport(mgr.driver)

看起来很眼熟,不错,在在/usr/lib/python2.7/site-packages/oslo.messaging-1.4.xxx中的entry_points中

[oslo.messaging.drivers]
qpid = oslo.messaging._drivers.impl_qpid:QpidDriver
amqp = oslo.messaging._drivers.protocols.amqp:ProtonDriver
kombu = oslo.messaging._drivers.impl_rabbit:RabbitDriver
rabbit = oslo.messaging._drivers.impl_rabbit:RabbitDriver
fake = oslo.messaging._drivers.impl_fake:FakeDriver
zmq = oslo.messaging._drivers.impl_zmq:ZmqDriver

这也就是我们在/etc/nova/nova.conf中配置“nova.openstack.common.rpc.impl_kombu‘使用rabbitMQ的原因

所以transport和backend类似,指明实际操作时使用的MQ具体实现方式。


target:

在sourcecode中常能看到这样的语句: target = messaging.Target(topic='%s.%s' % (topic_base, msg_type),server=CONF.host)

看oslo/message包中target.py中Target类,是个很简单的类 :

    def __init__(self, exchange=None, topic=None, namespace=None,
                 version=None, server=None, fanout=None):
        self.exchange = exchange
        self.topic = topic
        self.namespace = namespace
        self.version = version
        self.server = server
        self.fanout = fanout

类__doc__中解释道:

 :param version: Interfaces have a major.minor version number associated
      with them. A minor number increment indicates a backwards compatible
      change and an incompatible change is indicated by a major number bump.
      Servers may implement multiple major versions and clients may require
      indicate that their message requires a particular minimum minor version.
    :type version: str
    :param server: Clients can request that a message be directed to a specific
      server, rather than just one of a pool of servers listening on the topic.

    :type server: str
    :param fanout: Clients may request that a message be directed to all
      servers listening on a topic by setting fanout to ``True``, rather than
      just one of them.
可以看出,指定了server,就是direct方式将message发到指定server,不指定server,但指定了topic就将message发到接受该topic的server,

制定了fanout=true就发到所有server

至于exchange,在nova/config.py的parse_args中:

    rpc.set_defaults(control_exchange='nova')

指定nova使用exchange"nova",默认exchange是”openstack“


serializer

MQ的message在网络上传输,既然网络传输就必然涉及到数据的序列化与反序列化,serializer就是致命这一过程时使用的方式,随便看一个:

serializer = RequestContextSerializer(JsonPayloadSerializer())

JsonPayloadSerializer调用了jsonutils.to_primitive序列化一个entity


publisher和consumer

封装了client和server发送与接收的部分,这个在K版里,J版使用的是rpc.call, cast, server.start(),但是理解起来不难,而且如果愿意,trace进去

publisher和consumer,使用的还是rpc的那些方法。


看nova的rpc.rst文档,有一句mark一下,fanout基本用在cells的部分,之后会说:

Nova uses direct, fanout, and topic-based exchanges

mark link

1.http://www.gaort.com/index.php/archives/366

2.http://blog.csdn.net/juvxiao/article/details/23016155

3.http://blog.csdn.net/juvxiao/article/details/23532617

4.http://www.cnblogs.com/sammyliu/p/4384470.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值