Kombu 基础

AMQP协议:

Producer产生消息,将消息赋予路由信息,发送给exchange。

queue存储消息,并将消息发送Consumer

bindings queues与exchange通过路由信息进行绑定。发送过来的消息带有路由信息,exchange提取路由信息和queues与exchange绑定的路由信息匹配,

                  匹配成功后,将消息发给相应队列。

consumer 从queues中提取信息,并消耗。

exchange  接收消息,并路由到相应队列。


Kombu代码示例:

producer.py

[python]  view plain  copy
  1. #!/usr/bin/python  
  2.   
  3. from kombu.entity import Exchange  
  4. from kombu.messaging import Producer  
  5. from kombu.connection import Connection  
  6.   
  7. connection = Connection('amqp://guest:bupt@172.16.4.1:5672//')  
  8. channel = connection.channel()  
  9.   
  10. media_exchange = Exchange('media''direct', channel)  
  11. producer = Producer(channel, exchange=media_exchange, routing_key='video')  
  12.   
  13. producer.publish({'name''/tmp/lolcat1.avi''size'1301013})  
思路很简单:

1. 创建连接

2. 获得一个channel

3. 创建一个exchange,名字为‘media’,类型为‘direct’。

4. 创建一个Producer,指定exchange与routing_key,这样,发送信息的时候填充路由信息,发送到指定exchange。也可以在publish的时候指定。

5. 发送消息。


consumer.py

[python]  view plain  copy
  1. #!/usr/bin/python  
  2.   
  3. from kombu.entity import Exchange, Queue  
  4. from kombu.messaging import Consumer  
  5. from kombu.connection import Connection  
  6.   
  7.   
  8.   
  9. def process_media(body, message):  
  10.     print body  
  11.     message.ack()  
  12.   
  13. connection = Connection('amqp://guest:bupt@172.16.4.1:5672//')  
  14. channel = connection.channel()  
  15.   
  16. media_exchange = Exchange('media''direct', channel)  
  17. video_queue = Queue('video', exchange=media_exchange, routing_key='video', channel=channel)  
  18.   
  19.   
  20. consumer =  Consumer(channel, queues=[video_queue], callbacks=[process_media])   
  21. consumer.consume()  
  22.   
  23. while True:  
  24.     connection.drain_events()  
  25. consumer.cancel()  

思路很明确:

1. 创建连接

2. 获得channel

3. 创建exchange

4. 创建队列并与exchange绑定

5. 创建Consumer

6. consume() 向server注册,表明现在可以接收信息啦。server可以向该consumer发送消息。

7. drain_events阻塞程序,等待消息到来。当消息到来时,会执行回调函数process_media

8. cancel()通知server不要向该consumer发送任何消息啦。


疑惑:

1. channel是什么

    When producers and consumers connects to the broker using a TCP socket after authenticating the connection they establish a channel where AMQP commands are sent. The channel is a virtual path inside a TCP connection between this is very useful because there can be multiple channels inside the TCP connection each channels is identified using an unique ID. 


2. process_media的参数message是什么?为什么要调用message.ack()?

         打印message,输出kombu.transport.pyamqplib.Message object at 0x28d2b90。于是定位到Message类。     

[python]  view plain  copy
  1. class Message(base.Message):  
  2.     """A message received by the broker. 
  3.     .. attribute:: body  The message body. 
  4.     .. attribute:: channel The channel instance the message was received on. 
  5.     """  
  6.   
  7.     def __init__(self, channel, msg, **kwargs):  
  8.         props = msg.properties  
  9.         super(Message, self).__init__(channel,  
  10.                 body=msg.body,  
  11.                 delivery_tag=msg.delivery_tag,  
  12.                 content_type=props.get("content_type"),  
  13.                 content_encoding=props.get("content_encoding"),  
  14.                 delivery_info=msg.delivery_info,  
  15.                 properties=msg.properties,  
  16.                 headers=props.get("application_headers"),  
  17.                 **kwargs)  
    可以通过message取得想要的信息。其次,为什么要调用ack呢?

    如果队列要求回复确认信息,那么只有当用户返回一个确认信息,表明该message已经收到,message才会从队列中消失,否则,message一直存放在队列中。

        

3. drain_events做了些什么?

 kombu.transport.pyamqlib.Connection.drain_events

[python]  view plain  copy
  1. def drain_events(self, allowed_methods=None, timeout=None):  
  2.         """Wait for an event on any channel."""  
  3.         return self.wait_multi(self.channels.values(), timeout=timeout)  
  4.   
  5. def wait_multi(self, channels, allowed_methods=None, timeout=None):  
  6.     """Wait for an event on a channel."""  
  7.     chanmap = dict((chan.channel_id, chan) for chan in channels)  
  8.     chanid, method_sig, args, content = self._wait_multiple(  
  9.             chanmap.keys(), allowed_methods, timeout=timeout)  
  10.   
  11.     channel = chanmap[chanid]  
  12.   
  13.     amqp_method = self._method_override.get(method_sig) or \  
  14.                     channel._METHOD_MAP.get(method_sig, None)  
  15.                       
  16.     return amqp_method(channel, args)  
amqp_method即为回调函数。

ampqlib.client_0_8.channel.py.Channel.

[python]  view plain  copy
  1. _METHOD_MAP = {  
  2.        (6060): _basic_deliver,  
  3.        (6071): _basic_get_ok,  
  4.        }  
根据method_sig取得相应函数

[python]  view plain  copy
  1. def _basic_deliver(self, args, msg):  
  2.          
  3.         consumer_tag = args.read_shortstr()  
  4.         func = self.callbacks.get(consumer_tag, None)  
  5.         if func is not None:  
  6.             func(msg)  
从channel中的callback中获得用户注册的回调函数。明明在创建consumer的时候注册的回调函数,为什么回调函数会在channel中呢?

Comsumer类的comsume函数:

[python]  view plain  copy
  1. def consume(self, no_ack=None):  
  2.           
  3.     self._basic_consume(T, no_ack=no_ack, nowait=False)  
  4.               
  5.                                       
  6. def _basic_consume(self, queue, consumer_tag=None,  
  7.             no_ack=no_ack, nowait=True):  
  8.   
  9.     queue.consume(tag, self._receive_callback,  
  10.                   no_ack=no_ack, nowait=nowait)  
  11.   
  12.   
  13. def _receive_callback(self, message):  
  14.   
  15.     self.receive(decoded, message)  
  16.               
  17.                                   
  18. def receive(self, body, message):  
  19.       
  20.     callbacks = self.callbacks  
  21.     if not callbacks:  
  22.         raise NotImplementedError("Consumer does not have any callback")  
  23.     [callback(body, message) for callback in callbacks]  
注册的回调函数被包装了一下。新的回调函数传入了queue.consume

[python]  view plain  copy
  1. def consume(self, consumer_tag='', callback=None, no_ack=None,  
  2.             nowait=False):  
  3.           
  4.     return self.channel.basic_consume(queue=self.name,  
  5.                                       no_ack=no_ack,  
  6.                                       consumer_tag=consumer_tag or '',  
  7.                                       callback=callback,  
  8.                                       nowait=nowait)  
回调函数进入channel中。

总结一下:drain_events等待队列中的消息,当取得消息后,会调用回调函数进行相应处理。

4. 从connection获得Producer与Consumer

    有一个简便方法,可以直接从connection中获得Producer或者Consumer。

[python]  view plain  copy
  1. consumer = connection.Consumer(queues=[video_queue], callbacks=[process_media])  

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值