基本用法流程
- 生产者:
- 建立socket连接上rabbitmq
1 connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
1 pika.ConnectionParameters(host=_DEFAULT, port=_DEFAULT, virtual_host=_DEFAULT, credentials=_DEFAULT, channel_max=_DEFAULT, frame_max=_DEFAULT, heartbeat=_DEFAULT, ssl=_DEFAULT, ssl_options=_DEFAULT, connection_attempts=_DEFAULT, retry_delay=_DEFAULT, socket_timeout=_DEFAULT, locale=_DEFAULT, backpressure_detection=_DEFAULT, blocked_connection_timeout=_DEFAULT, client_properties=_DEFAULT, tcp_options=_DEFAULT, **kwargs)
- 常用参数
- host,与rabbitmq服务器连接,设置为localhost表示与本机的rabbitmq建立连接,通常程序与rabbitmq服务需要在统一环境方可使用
- port,默认5672
- credentials:用户认证,使用如
pika.credentials.PlainCredentials
进行认证
- 建立通信通道
channel = connection.channel()
- 建立队列/建立交换机
- 简单模式建立队列
result = channel.queue_declare(self, queue='', passive=False, durable=False, exclusive=False, auto_delete=False, arguments=None)
- 常用参数
- queue,队列名
- durable,消息是放在队列由消费者取走,该参数表示取走时是否备份一份
- exclusive,队列是否本连接独占
- 建立的队列
queue = result.method.queue
- 其他模式建立交换机
channel.exchange_declare(exchange=None, exchange_type='direct', passive=False, durable=False, auto_delete=False, internal=False, arguments=None)
- 常用参数
- exchange,交换机名称
- exchange_type,重点,交换机的模式,有三种:fanout,direct,topic
- durable,该参数表示消费者取走时是否备份一份
- 传输数据
channel.basic_publish(exchange, routing_key, body, properties=None, mandatory=False, immediate=False)
- 常用参数
- exchange,传输到交换机的名,可为’‘,表示不传输到交换机
- routing_key,传输到队列的名,可为’‘,表示不传输到队列
- body,传输的数据properties,额外参数,必须是pika.BasicProperties的实例
- delivery_mode,传输模式
- 设置为2,表示对消息进行持久化
- reply_to,传递队列,可用于RPC回调队列
- correlation_id,关联ID,可用于RPC回调时识别身份
pika.BasicProperties(content_type=None, content_encoding=None, headers=None, delivery_mode=None, priority=None, correlation_id=None, reply_to=None, expiration=None, message_id=None, timestamp=None, type=None, user_id=None, app_id=None, cluster_id=None)
- 结束
connection.close()
- 消费者
- 建立socket连接上rabbitmq
- 同上生产者
- 建立通信通道
channel = connection.channel()
- 建立交换机[可选]
- 同上生产者
- 建立队列
- 同上生产者
- 定制消息处理规则
- 定义回调函数
def callback(ch, method, properties, body): pass
- 定制规则
channel.basic_consume(consumer_callback, queue, no_ack=False, exclusive=False, consumer_tag=None, arguments=None)
- consumer_callback,回调函数
- queue,接收消息队列
- no_ack,是否不应答,True表示不应答,False表示应答
- 是否给rabbitmq返回,已收到并处理消息
- 阻塞监听队列,当有消息,则按照规则处理
channel.start_consuming()
RabbitMQ工作模型
- 工作模型指的是生产者和消费者之间使用不同规则通信使用的RabbitMQ的模式
简单模式
- 示例
- 生产者
1 import pika
2
3 # 封装socket通信,建立连接
4 connection = pika.BlockingConnection(
5 pika.ConnectionParameters(
6 host='192.168.40.128',
7 port=5672,
8 credentials=pika.credentials.PlainCredentials(
9 username='admin',
10 password='123456'
11 )
12 ))
13
14 # 创建通道对象
15 channel = connection.channel()
16
17 # 创建一个队列,名字为hello
18 channel.queue_declare(queue='hello')
19
20 # 直接向队列推送消息
21 msg = "兔子"
22 num = 10
23 for i in range(num):
24 channel.basic_publish(
25 exchange='', # 值为空表示简单模式
26 routing_key='hello', # 队列名
27 body=''.join([msg, str(i)]) # 发送数据
28 )
29
30 print("Sent '%s' * %s" % (msg, num))
31 connection.close()
- 消费者
1 import pika
2
3 # 封装socket通信,建立连接
4 connection = pika.BlockingConnection(
5 pika.ConnectionParameters(
6 host='192.168.40.128',
7 port=5672,
8 credentials=pika.credentials.PlainCredentials(
9 username='admin',
10 password='123456'
11 )
12 ))
13
14 # 创建通道对象
15 channel = connection.channel()
16
17 # 创建一个叫hello的队列,有则连接该队列
18 channel.queue_declare(queue='hello')
19
20 # 定义回调函数
21 def callback(ch, method, properties, body):
22 print(" [x] Received %r" % body.decode("utf-8"))
23
24 # 设置执行命令
25 channel.basic_consume(
26 callback,
27 queue='hello',
28 no_ack=True
29 )
30
31 print(' [*] Waiting for messages. To exit press CTRL+C')
32 # 执行命令
33 channel.start_consuming()
exchange模式(三种)
fanout
- 分发模式,报纸订阅模式,生产者生产一份数据,交换机为每个消费者绑定的队列发送一样的数据
- 生产者
1 import pika
2 import sys
3
4 connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
5 channel = connection.channel()
6
7 channel.exchange_declare(exchange='logs',
8 exchange_type='fanout')
9
10 message = ' '.join(sys.argv[1:]) or "info: Hello World!"
11 channel.basic_publish(exchange='logs',
12 routing_key='',
13 body=message)
14 print(" [x] Sent %r" % message)
15 connection.close()
- 消费者
1 import pika
2
3 connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
4 channel = connection.channel()
5
6 channel.exchange_declare(exchange='logs',
7 exchange_type='fanout')
8
9 result = channel.queue_declare(exclusive=True)
10 queue_name = result.method.queue
11
12 channel.queue_bind(exchange='logs',
13 queue=queue_name)
14
15 print(' [*] Waiting for logs. To exit press CTRL+C')
16
17 def callback(ch, method, properties, body):
18 print(" [x] %r" % body)
19
20 channel.basic_consume(callback,
21 queue=queue_name,
22 no_ack=True)
23
24 channel.start_consuming()
direct
- 关键字指定发送,
- 生产者
1 import pika
2 import sys
3
4 connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
5 channel = connection.channel()
6
7 channel.exchange_declare(exchange='direct_logs',
8 exchange_type='direct')
9
10 severity = sys.argv[1] if len(sys.argv) > 2 else 'info'
11 message = ' '.join(sys.argv[2:]) or 'Hello World!'
12 channel.basic_publish(exchange='direct_logs',
13 routing_key=severity,
14 body=message)
15 print(" [x] Sent %r:%r" % (severity, message))
16 connection.close()
- 消费者
1 import pika
2 import sys
3
4 connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
5 channel = connection.channel()
6
7 channel.exchange_declare(exchange='direct_logs',
8 exchange_type='direct')
9
10 result = channel.queue_declare(exclusive=True)
11 queue_name = result.method.queue
12
13 severities = sys.argv[1:]
14 if not severities:
15 sys.stderr.write("Usage: %s [info] [warning] [error]\n" % sys.argv[0])
16 sys.exit(1)
17
18 for severity in severities:
19 channel.queue_bind(exchange='direct_logs',
20 queue=queue_name,
21 routing_key=severity)
22
23 print(' [*] Waiting for logs. To exit press CTRL+C')
24
25 def callback(ch, method, properties, body):
26 print(" [x] %r:%r" % (method.routing_key, body))
27
28 channel.basic_consume(callback,
29 queue=queue_name,
30 no_ack=True)
31
32 channel.start_consuming()
- 测试
python producer.py warning error > logs_from_rabbit.log
python comsumer.py info warning error
topic
- 生产者
1 import pika
2 import sys
3
4 connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
5 channel = connection.channel()
6
7 channel.exchange_declare(exchange='topic_logs',
8 exchange_type='topic')
9
10 routing_key = sys.argv[1] if len(sys.argv) > 2 else 'anonymous.info'
11 message = ' '.join(sys.argv[2:]) or 'Hello World!'
12 channel.basic_publish(exchange='topic_logs',
13 routing_key=routing_key,
14 body=message)
15 print(" [x] Sent %r:%r" % (routing_key, message))
16 connection.close()
- 消费者
1 import pika
2 import sys
3
4 connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
5 channel = connection.channel()
6
7 channel.exchange_declare(exchange='topic_logs',
8 exchange_type='topic')
9
10 result = channel.queue_declare(exclusive=True)
11 queue_name = result.method.queue
12
13 binding_keys = sys.argv[1:]
14 if not binding_keys:
15 sys.stderr.write("Usage: %s [binding_key]...\n" % sys.argv[0])
16 sys.exit(1)
17
18 for binding_key in binding_keys:
19 channel.queue_bind(exchange='topic_logs',
20 queue=queue_name,
21 routing_key=binding_key)
22
23 print(' [*] Waiting for logs. To exit press CTRL+C')
24
25 def callback(ch, method, properties, body):
26 print(" [x] %r:%r" % (method.routing_key, body))
27
28 channel.basic_consume(callback,
29 queue=queue_name,
30 no_ack=True)
31
32 channel.start_consuming()
- 测试
- 接收所有日志
python comsumer.py "#"
- 接收包含kern开头的
python comsumer.py "kern.*"
- 接收critical结尾的
python comsumer.py "*.critical"
- 发送kern.critical、A critical kernel error
python producer.py "kern.critical" "A critical kernel error"
基于RabbitMQ的RPC
- 何为RPC
- 客户端通过消息队列向服务端发送数据
- 服务端处理完数据,将数据通过回调队列返回给客户端
- 客户端可能回同时发起多个任务,在服务端回调后应当根据唯一标识为每一个任务返回值的指定数据
- 服务端
1 import pika
2
3 connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
4
5 channel = connection.channel()
6
7 channel.queue_declare(queue='rpc_queue')
8
9 def fib(n):
10 if n == 0:
11 return 0
12 elif n == 1:
13 return 1
14 else:
15 return fib(n-1) + fib(n-2)
16
17 def on_request(ch, method, props, body):
18 n = int(body)
19
20 print(" [.] fib(%s)" % n)
21 response = fib(n)
22
23 ch.basic_publish(exchange='',
24 routing_key=props.reply_to,
25 properties=pika.BasicProperties(correlation_id = \
26 props.correlation_id),
27 body=str(response))
28 ch.basic_ack(delivery_tag = method.delivery_tag)
29
30 channel.basic_qos(prefetch_count=1)
31 channel.basic_consume(on_request, queue='rpc_queue')
32
33 print(" [x] Awaiting RPC requests")
34 channel.start_consuming()
- 客户端
1 import pika
2 import uuid
3
4 class FibonacciRpcClient(object):
5 def __init__(self):
6 self.connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
7
8 self.channel = self.connection.channel()
9
10 result = self.channel.queue_declare(exclusive=True)
11 self.callback_queue = result.method.queue
12
13 self.channel.basic_consume(self.on_response, no_ack=True,
14 queue=self.callback_queue)
15
16 def on_response(self, ch, method, props, body):
17 if self.corr_id == props.correlation_id:
18 self.response = body
19
20 def call(self, n):
21 self.response = None
22 self.corr_id = str(uuid.uuid4())
23 self.channel.basic_publish(exchange='',
24 routing_key='rpc_queue',
25 properties=pika.BasicProperties(
26 reply_to = self.callback_queue,
27 correlation_id = self.corr_id,
28 ),
29 body=str(n))
30 while self.response is None:
31 self.connection.process_data_events()
32 return int(self.response)
33
34 fibonacci_rpc = FibonacciRpcClient()
35
36 print(" [x] Requesting fib(30)")
37 response = fibonacci_rpc.call(30)
38 print(" [.] Got %r" % response)