OpenStack基礎組件kombu雜談

        作爲一個典型的分佈式系統,OpenStack的各模塊之間也需要進行大量的消息傳遞。OpenStack採用的是AMQP的消息隊列方案。

        AMQP是一個廣泛使用的消息隊列的規範。服務端常採用的是RabbitMQ(在AMQP的規範中,消息隊列的服務端被成爲broker),現在已收歸vmware麾下,使用erlang實現。OpenStack除了支持RabbitMQ之外,還支持apache上開源的Qpid。Qpid有C++和java兩種broker的實現。

        kombu是AMQP協議client端的一個python實現。其他的client端的python庫還有如pika,py-amqplib等。

        kombu的特點是支持多種的符合APMQ協議的消息隊列系統。不僅支持原生的AMQP消息隊列如RabbitMQ、Qpid,還支持虛擬的消息隊列如redis、mongodb、beantalk、couchdb、in-memory等。我認爲OpenStack使用kombu作爲消息隊列使用的client庫而沒有用廣泛使用的pika庫有兩個原因:

        1. 如上面所述,kombu除了支持純AMQP的實現還支持虛擬AMQP的實現作爲消息隊列系統,如redis、mongodb、beantalk等。衆所周知,OpenStack的設計理念及思想爲各個組件可以方便的替換、組合,這樣用kombu就有了極大的方便,使用者可以依據需要,方便的使用redis等搭建一個openstack的消息系統

# Using pyamqp
amqp://guest:guest@localhost:5672/

# Using Redis
redis://localhost:6379/

# Using Redis over a Unix socket
redis+socket:///tmp/redis.sock

# Using virtual host '/foo'
amqp://localhost//foo

        2. kombu可以通過配置設置AMQP連接的底層庫,librabbitmq或者pyamqp。前者是一個python嫁接C庫的實現,後者是一個純python的實現。openstack內部使用的是eventlet的框架,一個基於python協程的異步網絡框架。其核心是通過greenlet的monkeypath將涉及網絡IO的python模塊進行綠化(協程化)。所以如果用純python實現的AMQP庫,就可以應用eventlet的框架將設計網絡IO的部分變爲協程,提高整體的網絡IO性能。

        下面是一個簡單的例子:

生產者:

from kombu import Connection, Exchange, Queue

media_exchange = Exchange('media', 'direct', durable=True)
video_queue = Queue('video', exchange=media_exchange, routing_key='video')


# connections
with Connection('amqp://guest:guest@localhost//') as conn:

    # produce
    producer = conn.Producer(serializer='json')
    producer.publish({'name': '/tmp/lolcat1.avi', 'size': 1301013},
                      exchange=media_exchange, routing_key='video',
                      declare=[video_queue])

    # the declare above, makes sure the video queue is declared
    # so that the messages can be delivered.
    # It's a best practice in Kombu to have both publishers and
    # consumers declare the queue.  You can also declare the
    # queue manually using:
    #     video_queue(conn).declare()
消費者:

from kombu import Connection, Exchange, Queue

media_exchange = Exchange('media', 'direct', durable=True)
video_queue = Queue('video', exchange=media_exchange, routing_key='video')

def process_media(body, message):
    print body
    message.ack()
# connections
with Connection('amqp://guest:guest@localhost//') as conn:
    # consume
    with conn.Consumer(video_queue, callbacks=[process_media]) as consumer:
        # Process messages and handle events on all channels
        while True:
            conn.drain_events()



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章