python使用rabitmq详细介绍

文章目录

  • 1 消息队列介绍
    • 1.1 什么是消息队列
    • 1.2 消息队列的三大作用
      • 1.2.1 异步、解耦
      • 1.2.2 削峰(限流)
    • 1.3 消息队列的两种模式
      • 1.3.1 点对点模式
      • 1.3.2 发布/订阅模式
  • 2 常用消息队列比较和选型
    • 2.1 总体对比
  • 1 rabbitmq介绍
    • 1.1 rabbitmq是什么
    • 1.2 有什么特点
    • 1.3 将交换机推送队列的几种模式
  • (井号) 用来表示任意数量(零个或多个)单词
    • 1.4 能解决什么问题
  • 2 python使用rabbitmq
  • 3 场景案例
    • 3.1 场景一 轮询消费
      • 具体场景
      • 场景模拟图
      • 代码实现
        • 3.1.1 创建生产者
        • 3.1.2 创建三个消费者
      • 测试
    • 3.2 场景二 负载均衡,公平分发
      • 具体场景描述
      • 代码实现

1 消息队列介绍

1.1 什么是消息队列

python使用rabitmq详细介绍_第1张图片

1.2 消息队列的三大作用

1.2.1 异步、解耦

​ 也就是不需要同步处理

python使用rabitmq详细介绍_第2张图片

1.2.2 削峰(限流)

python使用rabitmq详细介绍_第3张图片
​ 请求先入消息队列,而不是由业务处理系统直接处理,做了一次缓冲,服务器A、B根据各自处理能力,去消息队列取相应数量的请求进行处理,暂时没有处理的请求就在消息队列中等待,避免了大流量冲垮系统。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V3ibOCuc-1589255031784)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1588218418837.png)]

1.3 消息队列的两种模式

1.3.1 点对点模式

​ 也称P2P模式,包含三个角色:消息队列(Queue),发送者(Sender),接收者(Receiver)。每个消息都被发送到一个特定的队列,接收者从队列中获取消息。队列保留着消息,直到他们被消费或超时。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7PO3QwMq-1589255031786)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1588218581261.png)]

点对点模式特点:

  • 第三方是每个消息只有一个接收者(Consumer)(即一旦被消费,消息就不再在消息队列中);
  • 发送者和接收者间没有依赖性,发送者发送消息后,消息直接存储在消息队列中,接收者是否在线并不影响发送;
  • 接收者在成功接收消息之后需向队列应答成功,以便消息队列删除当前接收的消息;

1.3.2 发布/订阅模式

​ 包含三个角色主题(Topic),发布者(Publisher),订阅者(Subscriber) 多个发布者将消息发送到Topic,系统将这些消息传递给多个订阅者。
python使用rabitmq详细介绍_第4张图片

发布/订阅模式特点

  • 每个消息可以有多个消费者;
  • 发布者和订阅者之间有时间上的依赖性。针对某个主题(Topic)的订阅者,它必须创建一个订阅者之后,才能接收发布者的消息;
  • 为了消费消息,订阅者必须保持运行的状态;

2 常用消息队列比较和选型

​ 常用的四种MQ:RabbitMQ/ActiveMQ/RocketMQ/Kafka,各有优缺点。因业务量并发量可能并不高,本文后半篇主要介绍rabbitmq的使用

2.1 总体对比

RabbitMQ
RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

   如果业务场景对并发量要求不是太高(十万级、百万级),那这四种消息队列中,RabbitMQ 一定是你的首选。

ActiveMQ
ActiveMQ是由Apache出品,ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现。它非常快速,支持多种语言的客户端和协议,而且可以非常容易的嵌入到企业的应用环境中,并有许多高级功能。

   ActiveMQ 的社区算是比较成熟,但是较目前来说,ActiveMQ 的性能比较差,而且版本迭代很慢,不推荐使用。

RocketMQ
RocketMQ出自 阿里公司的开源产品,用 Java 语言实现,在设计时参考了 Kafka,并做出了自己的一些改进,消息可靠性上比 Kafka 更好。RocketMQ在阿里集团被广泛应用在订单,交易,充值,流计算,消息推送,日志流式处理,binglog分发等场景。

   文档相对来说简单一些,然后接口这块不是按照标准 JMS 规范走的有些系统要迁移需要修改大量代码,适合有一定技术实力的公司。

Kafka
Apache Kafka是一个分布式消息发布订阅系统。它最初由LinkedIn公司基于独特的设计实现为一个分布式的提交日志系统( a distributed commit log),之后成为Apache项目的一部分。

   kafka 的特点其实很明显,就是仅仅提供较少的核心功能,但是提供超高的吞吐量,ms 级的延迟,极高的可用性以及可靠性,而且分布式可以任意扩展。同时 kafka 最好是支撑较少的 topic 数量即可,保证其超高吞吐量。如果是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的事实性规范。

1 rabbitmq介绍

1.1 rabbitmq是什么

  • 是一个开源的消息中间件,它是首个在功能层次、客户端库、开发工具和文档质量方面达到合理水平的开源消息代理之一,RabbitMQ插件众多,社区成熟,文档完善,官方支持多种客户端:Java, Spring, .NET, PHP, Python, Ruby, JavaScript, Go, Elixir, Objective-C, Swift等等。
  • abbitMQ是一个通用的消息代理,通过包括点对点、请求/响应及发布订阅在内的多种消息通信模式。其采用的是一种智能代理/傻瓜消费的模式。相当于交换机完成消息的分发,分发到各队列。分发方式有直连型,扇形,主题型。在1.3中进行描述

下面列一个简单的一个消息推送到接收的流程,提供一个简单的图

由生产者生产消息,可选择交换机和队列进行推送

消费者消费消息时,需要选择队列消费。也可进行提前注册,达到监听消息的目的。

python使用rabitmq详细介绍_第5张图片

1.2 有什么特点

以下特点结合实际使用场景,通过在代码过程配置实现以下功能

  • rabbitmq有可视化监控界面

  • 可以持久化队列消息,在rabbitmq服务挂了的时候,重启服务不会出现数据丢失

  • 点对点消费,在消费者消费完消息后,消息即从队列中移除

  • 对于消费过程,可以选择轮询模式和公平分发模式

    轮询模式:多个消费者监听同一消息的时候,该消息可以轮流分发到消费者

    公平分发模式:可以理解为,在各个消费者端,通过配置perfetch=1,告诉RabbitMQ在这个消费者当前消息还没处理完的时候就不要再给我发新消息了

  • 消费确认,在消息消费未完成,没有向服务器发送确认信息之前,消息不会从队列中移除。避免消费过程中断导致消息丢失,该功能需要在写代码时修改配置

1.3 将交换机推送队列的几种模式

常用的交换机有以下三种,因为消费者是从队列获取信息的,队列是绑定交换机的(一般),所以对应的消息推送/接收模式也会有以下几种:

Direct Exchange

直连型交换机,根据消息携带的路由键将消息投递给对应队列。

大致流程,有一个队列绑定到一个直连交换机上,同时赋予一个路由键 routing key 。
然后当一个消息携带着路由值为X,这个消息通过生产者发送给交换机时,交换机就会根据这个路由值X去寻找绑定值也是X的队列。

Fanout Exchange

扇型交换机,这个交换机没有路由键概念,就算你绑了路由键也是无视的。 这个交换机在接收到消息后,会直接转发到绑定到它上面的所有队列。

Topic Exchange

主题交换机,这个交换机其实跟直连交换机流程差不多,但是它的特点就是在它的路由键和绑定键之间是有规则的。
简单地介绍下规则:

  • (星号) 用来表示一个单词 (必须出现的)

(井号) 用来表示任意数量(零个或多个)单词

通配的绑定键是跟队列进行绑定的,举个小例子
队列Q1 绑定键为 .TT. 队列Q2绑定键为 TT.#
如果一条消息携带的路由键为 A.TT.B,那么队列Q1将会收到;
如果一条消息携带的路由键为TT.AA.BB,那么队列Q2将会收到;

主题交换机是非常强大的,为啥这么膨胀?
当一个队列的绑定键为 “#”(井号) 的时候,这个队列将会无视消息的路由键,接收所有的消息。
当 * (星号) 和 # (井号) 这两个特殊字符都未在绑定键中出现的时候,此时主题交换机就拥有的直连交换机的行为。
所以主题交换机也就实现了扇形交换机的功能,和直连交换机的功能。

1.4 能解决什么问题

  • 能解决进程通讯问题:可以解决多系统,异构系统之间的数据交换(消息通知/通讯)问题
  • 系统间服务的相互调用:RPC
  • 解决异步处理的问题

2 python使用rabbitmq

引入支持rabbitmq的支持包

pip intall pika

pika模块是python对rabbitmq的api接口,在消费消息的时候,提供了一个可自定义的回调函数入口,在回调函数里,就可以自由发挥了。想实现什么功能私人定制

3 场景案例

3.1 场景一 轮询消费

具体场景

一个生产者,三个消费者同时注册到同一个队列上,然后轮询消费消息。在消费过程中需要考虑队列信息持久化,和消费者异常挂掉消息丢失的情况

在消息传递过程中使用直联机模式

场景模拟图

python使用rabitmq详细介绍_第6张图片

代码实现

3.1.1 创建生产者

创建producer.py

import pika

python_exchange = 'python_exchange'
routingKey = 'python_routing_key'
python_queue = 'python_queue'

# 1 建立rabbit连接通道
credentials = pika.PlainCredentials('guest', 'guest')  # 用户名,密码
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost', 5672, '/', credentials))
channel = connection.channel()

# 2 定义交换机名称和交换机类型
# exchange: 交换机名称,可以自定义
# exchange_type: 交换机类型,默认就是直连的
channel.exchange_declare(exchange=python_exchange,  exchange_type='direct')
# 定义路由键信息


# 3 定义队列,绑定交换机 durable=True:队列持久化
channel.queue_declare(queue=python_queue, durable=True, auto_delete=True)
channel.queue_bind(exchange=python_exchange, queue=python_queue, routing_key=routingKey)

# 4 发布消息
# properties=pika.BasicProperties(delivery_mode=2, ) 持久化队列中的消息
test_msg = 'this is a test msg........'
channel.basic_publish(exchange=python_exchange, routing_key=routingKey, body=test_msg,
                      properties=pika.BasicProperties(delivery_mode=2, ))

# 关闭连接
connection.close();

3.1.2 创建三个消费者

同样的代码创建三份:consumer1.py consumer2.py consumer3.py 同样干了以下几件事

  • 创建连接通道
  • 声明队列
  • 定义回调函数
  • 注册消费者到指定队列,开始消费,消费完后向rabbitmq发送确认消息
import pika


python_queue = 'python_queue1'

# 1 建立rabbit连接通道
credentials = pika.PlainCredentials('guest', 'guest')  # 用户名,密码
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost', 5672, '/', credentials))
channel = connection.channel()

# 3 定义队列,只需关注需要监听的队列
channel.queue_declare(queue=python_queue, durable=True, auto_delete=True)

def callback(ch,method,properties,body):
    print("消费者1收到消息如下 %r" % body)
    print("--------------开始后续的业务扩展-----------------")


# 注册消费者,开始消费
channel.basic_consume(python_queue, callback, True)
channel.start_consuming()

注:durable=True, auto_delete=True在生产者和消费者中要保持一直,不然会报错

测试

启动producer.py,访问http://localhost:15672/ 可以看到队列、交换机、和消息都已发送至rabbit

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NFlq3ads-1589255031792)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1588147367448.png)]

分别启动consumer1.py consumer2.py consumer3.py。可以看到消费者轮询接收到消息

3.2 场景二 负载均衡,公平分发

具体场景描述

​ 一个生产者,三个消费者同时注册到同一个队列上,然后轮询消费消息,当自身消费不了消息时会通知rabiitmq不要再继续发送消息。

在消息传递过程中使用直联机模式

​ 如果Rabbit只管按顺序把消息发到各个消费者身上,不考虑消费者负载的话,很可能出现,一个机器配置不高的消费者那里堆积了很多消息处理不完,同时配置高的消费者却一直很轻松。为解决此问题,可以在各个消费者端,配置perfetch=1,意思就是告诉RabbitMQ在我这个消费者当前消息还没处理完的时候就不要再给我发新消息了。

python使用rabitmq详细介绍_第7张图片

代码实现

只需要修改消费者配置:

  • 在消费者注册之前添加: channel.basic_qos(prefetch_count=1)
  • 在回调函数中添加: ch.basic_ack(delivery_tag =method.delivery_tag) 作用是生产者端消息持久后, 保证消息被消费后,消费端发送一个ack,然后服务端从队列删除该消息
  • 关闭消费者注册时的自动消息确认(不然会报错),因为在回调函数时已经主动完成确认

生产者代码可参考3.1 生产者的代码

消费者代码如下:

import pika
import time


python_queue = 'python_queue1'

# 1 建立rabbit连接通道
credentials = pika.PlainCredentials('guest', 'guest')  # 用户名,密码
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost', 5672, '/', credentials))
channel = connection.channel()

# 3 定义队列,只需关注需要监听的队列
channel.queue_declare(queue=python_queue, durable=True, auto_delete=True)

def callback(ch,method,properties,body):
    print("消费者1收到消息如下 %r" % body)
    time.sleep(body.count(b'.'))
    print("--------------开始后续的业务扩展-----------------")
    ch.basic_ack(delivery_tag=method.delivery_tag)

# 注册消费者,开始消费
channel.basic_qos(prefetch_count=1)
channel.basic_consume(python_queue, callback)
channel.start_consuming()

你可能感兴趣的:(python,消息队列)