RabbitMQ tutorial (b) - to ensure that the message persistence (pika version 1.1.0), RabbitMQ Publish and Subscribe

The last chapter introduces the RabbitMQ installation and simple parameters and transmit information, today we introduce a number of other parameters.

When the message queue is created and sent, if no time is consumer spending, restart RabbitMQ services, queues, and the message will be lost.

pika version 1.1.0

A, RabbitMQ persistence

The default MQ queue created is temporary and exchange, if you do not declare persistent, once rabbitmq hang up, queue, exchange will be lost. So we generally create a queue or exchange time will declare persistence.

1.queue statement persistence

# Declare the message queue, the message will be passed in this queue, such as does not exist, it is created. Representative durable = True message queue persistent storage, False nonpersistent storage 
Result = channel.queue_declare (Queue = ' Python-Test ' , durable = True )

2.exchange statement endurance of

# Statement exchange, designated by the message exchange which queue passed, if not exist, create .durable = True Representative exchange persistent storage, False nonpersistent storage 
channel.exchange_declare (exchange = ' Python-Test ' , Durable = True )

Note: If there is already a non-persistent queue or exchange, executing the code error, because you can not change the current state of the queue storage or exchange property, need to remove the reconstruction. If the queue and exchange in a statement persistence, persistence does not declare another is not permitted binding. Queue must be the first time declared, it must be persistent.

3. news endurance of (******)

Although the exchange and declare a persistent queue, but the message exists only in memory, after rabbitmq restart, memory there's something still missing. It is necessary to declare the message is persistent, dump memory from the hard disk.

# Insert routing_key value to the queue is the queue name. delivery_mode = 2 declared persistent message in the queue, delivery_mod = 1 non-persistent message 
    channel.basic_publish (= Exchange '' , routing_key = ' Python-Test ' , body = Message,
                          properties=pika.BasicProperties(delivery_mode = 2))

4.Message acknowledgment message is not lost (******)

Consumers (consumer) calls the callback function, there will be the risk of treatment failure message, if the process fails, the message is lost. But consumers can also choose to deal with failure, the message is rolled back to rabbitmq, was re consumer spending, this time needs to be set to confirm identity.

channel.basic_consume ( ' Python-the Test ' , callback
 # NO_ACK set to False, when calling the callback function, did not receive the confirmation ID, message queue back .True, regardless of success or failure callback calls, messages are consumed 
                      auto_ack = False)

Those who can afford Second, the message is more work

Server performance sizes, some server processing of fast and slow some server processes, so the default polling is not able to meet our needs, we want abler, 
maximize our machines performance. to solve this problem, in various consumer side, configure perfetch = 1, meaning that when I tell RabbitMQ the consumer has not finished processing the current message, do not give me the news.

channel.basic_qos(prefetch_count=1)
channel.basic_consume(callback,queue='task_queue')

Three, RabbitMQ Publish and Subscribe

We see the producer delivers messages to the Queue, in fact, this kind of thing will never happen in the RabbitMQ. The fact is, the producer sends a message to the Exchange (switch), by the Exchange routes the message to a Queue or more (or discarded). So rabbitmq of publish and subscribe to be implemented by means of the principle of exchange (Exchange) of

 

 

Prior to this we need to understand some of the parameters:

routing key

Producers in time to send a message to the Exchange, will generally specify a routing key (specify the connection queue name) to specify the routing rules the news, and this routing key needs and Exchange Type and 
binding key used in combination in order to ultimately take effect. At a fixed Exchange Type the binding key cases (usually these elements are fixed configured in normal use), our producers will be sending the message to the Exchange,
by specifying routing key to determine where the message flow. RabbitMQ routing key set is limited to 255 bytes in length

Binding

RabbitMQ in the Exchange associated with the Queue up by the Binding , so RabbitMQ will know how to route the message to the specified Queue up correctly.

 

 

Binding key

In binding (Binding) Exchange Queue simultaneously with, generally specify a binding key ; consumer when the message to the Exchange, typically specify a routing key; 
when the binding key match routing key, the message will be routed corresponding to the Queue. When multiple binding to the same Exchange Queue, which Binding allows the same binding key. binding key does not take effect in all cases, it depends on the Exchange Type, such as fanout type of Exchange will ignore the binding key, but the message is routed to the Exchange all bound to the Queue.

Exchange Types There are four operating modes: fanout, Direct, Topic, headers

Now we generally do not have headers, so we only analyze the first three

Mode 1: fanout

In this mode, the message is transmitted to the exchange will be forwarded to all the bound queue. fanout type of forwarding the message is the fastest.

Note the following:

  • Not need to specify routing_key, even if specified is invalid.
  • Advance the exchange and queue bindings, a exchange can bind multiple queue, a queue can be bound to multiple exchange.
  • You need to start  subscriber queue in this mode is randomly generated consumer, the publisher  just announced to the exchange, the exchange forwards the message to the queue.

 

 

 Publisher Code:

import pika
import json

Credentials = pika.PlainCredentials ( 'the Guest ' , 'the Guest ' )   # MQ user name and password 
Connection = pika.BlockingConnection (pika.ConnectionParameters (Host = 'localhost ' , Port = 5672, = Credentials Credentials)) 
# create links channel
=connection.channel() # 声明exchange,由exchange指定消息在哪个队列传递,如不存在,则创建。durable = True 代表exchange持久化存储,False 非持久化存储 channel.exchange_declare(exchange = 'python-test',durable = True, exchange_type='fanout') for i in range(10): message=json.dumps({'OrderId':"1000%s"%i}) # 向队列插入数值 exchange指定队列名。delivery_mode = 2 声明消息在队列中持久化,delivery_mod = 1 消息非持久化。routing_key 不需要配置 channel.basic_publish(exchange = 'python-test',routing_key = '',body = message, properties=pika.BasicProperties(delivery_mode = 2)) print(message) connection.close()

订阅者代码:

import pika

credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters(host = 'localhost',port = 5672,credentials = credentials))
channel = connection.channel()
# 创建临时队列,队列名传空字符,consumer关闭后,队列自动删除
result = channel.queue_declare('',exclusive=True)
# 声明exchange,由exchange指定消息在哪个队列传递,如不存在,则创建。durable = True 代表exchange持久化存储,False 非持久化存储
channel.exchange_declare(exchange = 'python-test',durable = True, exchange_type='fanout')
# 绑定exchange和队列  exchange 使我们能够确切地指定消息应该到哪个队列去,queue临时队列
channel.queue_bind(exchange = 'python-test',queue = result.method.queue)
# 定义一个回调函数来处理消息队列中的消息,这里是打印出来
def callback(ch, method, properties, body):
    ch.basic_ack(delivery_tag = method.delivery_tag)
    print(body.decode())

channel.basic_consume(result.method.queue,callback,# 设置成 False,在调用callback函数时,未收到确认标识,消息会重回队列。True,无论调用callback成功与否,消息都被消费掉
                      auto_ack = False)
channel.start_consuming()

模式二:direct

这种工作模式的原理是 消息发送至 exchange,exchange 根据 路由键(routing_key)转发到相对应的 queue 上。

  •  可以使用默认 exchange =' ' ,也可以自定义 exchange
  • 这种模式下不需要将 exchange 和 任何进行绑定,当然绑定也是可以的。可以将 exchange 和 queue ,routing_key 和 queue 进行绑定
  • 传递或接受消息时 需要 指定 routing_key
  • 需要先启动 订阅者,此模式下的队列是 consumer 随机生成的,发布者 仅仅发布消息到 exchange ,由 exchange 转发消息至 queue。

发布者代码:

import pika
import json

credentials = pika.PlainCredentials('guest', 'guest')  # mq用户名和密码
connection = pika.BlockingConnection(pika.ConnectionParameters(host = 'localhost',port = 5672,credentials = credentials))
channel=connection.channel()
# 声明exchange,由exchange指定消息在哪个队列传递,如不存在,则创建。durable = True 代表exchange持久化存储,False 非持久化存储
channel.exchange_declare(exchange = 'python-test',durable = True, exchange_type='direct')

for i in range(10):
    message=json.dumps({'OrderId':"1000%s"%i})
# 指定 routing_key。delivery_mode = 2 声明消息在队列中持久化,delivery_mod = 1 消息非持久化
    channel.basic_publish(exchange = 'python-test',routing_key = 'OrderId',body = message,
                          properties=pika.BasicProperties(delivery_mode = 2))
    print(message)
connection.close()

订阅者代码:

import pika

credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters(host = 'localhost',port = 5672,credentials = credentials))
channel = connection.channel()
# 创建临时队列,队列名传空字符,consumer关闭后,队列自动删除
result = channel.queue_declare('',exclusive=True)
# 声明exchange,由exchange指定消息在哪个队列传递,如不存在,则创建。durable = True 代表exchange持久化存储,False 非持久化存储
channel.exchange_declare(exchange = 'python-test',durable = True, exchange_type='direct')
# 绑定exchange和队列  exchange 使我们能够确切地指定消息应该到哪个队列去
channel.queue_bind(exchange = 'python-test',queue = result.method.queue,routing_key='OrderId')
# 定义一个回调函数来处理消息队列中的消息,这里是打印出来
def callback(ch, method, properties, body):
    ch.basic_ack(delivery_tag = method.delivery_tag)
    print(body.decode())


#channel.basic_qos(prefetch_count=1)
# 告诉rabbitmq,用callback来接受消息
channel.basic_consume(result.method.queue,callback,
# 设置成 False,在调用callback函数时,未收到确认标识,消息会重回队列。True,无论调用callback成功与否,消息都被消费掉
                      auto_ack = False)
channel.start_consuming()

模式三:topicd

 这种模式和第二种模式差不多,exchange 也是通过 路由键 routing_key 来转发消息到指定的 queue 。 不同点是 routing_key 使用正则表达式支持模糊匹配,但匹配规则又与常规的正则表达式不同,比如‘’#‘’是匹配全部,“*”是匹配一个词。

举例:routing_key =“#orderid#”,意思是将消息转发至所有 routing_key 包含 “orderid” 字符的队列中。代码和模式二 类似,就不贴出来了。

发布者代码:

import pika
import sys
credentials = pika.PlainCredentials('用户名', '密码')
parameters = pika.ConnectionParameters(host='localhost',credentials=credentials)
connection = pika.BlockingConnection(parameters)
channel = connection.channel() #队列连接通道
channel.exchange_declare(exchange='mytopic',type='topic')
log_level =  sys.argv[1] if len(sys.argv) > 1 else 'all.info'
message = ' '.join(sys.argv[1:]) or "all.info: Hello World!"
channel.basic_publish(exchange='topic_log',
                      routing_key=log_level,
                      body=message)
print(" [x] Sent %r" % message)
connection.close()

订阅者代码:

import pika,sys
credentials = pika.PlainCredentials('用户名', '密码')
parameters = pika.ConnectionParameters(host='localhost',credentials=credentials)
connection = pika.BlockingConnection(parameters)
channel = connection.channel() 
queue_obj = channel.queue_declare(exclusive=True) #不指定queue名字,rabbit会随机分配一个名字,exclusive=True会在使用此queue的消费者断开后,自动将queue删除
queue_name = queue_obj.method.queue
log_levels = sys.argv[1:] # info warning errr
if not log_levels:
    sys.stderr.write("Usage: %s [info] [warning] [error]\n" % sys.argv[0])
    sys.exit(1)
for level in log_levels:
    channel.queue_bind(exchange='topic_log',
                       queue=queue_name,
                       routing_key=level) 
print(' [*] Waiting for logs. To exit press CTRL+C')
def callback(ch, method, properties, body):
    print(" [x] %r" % body)
channel.basic_consume(callback,queue=queue_name, no_ack=True)
channel.start_consuming()

RabbitMQ服务器的管理

./sbin/rabbitmq-server -detached   # 后台启动
./sbin/rabbitmqctl status   # 查看状态
./sbin/rabbitmqctl stop    # 关闭
./sbin/rabbitmqctl list_queues  # 查看queue

Guess you like

Origin www.cnblogs.com/wangcuican/p/12124475.html