rabbitmq学习

Rabbitmq五大核心概念

在这里插入图片描述
其中,中间的Broker表示RabbitMQ服务,每个Broker里面至少有一个Virtual host虚拟主机,每个虚拟主机中有自己的Exchange交换机、Queue队列以及Exchange交换机与Queue队列之间的绑定关系Binding。producer(生产者)和consumer(消费者)通过与Broker建立Connection来保持连接,然后在Connection的基础上建立若干Channel信道,用来发送与接收消息

1.Connection连接:

每个producer(生产者)或者consumer(消费者)要通过RabbitMQ发送与消费消息,首先就要与RabbitMQ建立连接,这个连接就是Connection。Connection是一个TCP长连接。

2.Channel(信道)

Channel是在Connection的基础上建立的虚拟连接,RabbitMQ中大部分的操作都是使用Channel完成的,比如:声明Queue、声明Exchange、发布消息、消费消息等

看到此处,你是否有这样一个疑问:既然已经有了Connection,我们完全可以使用Connection完成Channel的工作,为什么还要引入Channel这样一个虚拟连接的概念呢?因为现在的程序都是支持多线程的,如果没有Channel,那么每个线程在访问RabbitMQ时都要建立一个Connection这样的TCP连接,对于操作系统来说,建立和销毁TCP连接是非常大的开销,在系统访问流量高峰时,会严重影响系统性能。

Channel就是为了解决这种问题,通常情况下,每个线程创建单独的Channel进行通讯,每个Channel都有自己的channel id帮助Broker和客户端识别Channel,所以Channel之间是完全隔离的。

Connection与Channel之间的关系可以比作光纤电缆,如果把Connection比作一条光纤电缆,那么Channel就相当于是电缆中的一束光纤。

3.Virtual host(虚拟主机)

在这里插入图片描述
Virtual host是一个虚拟主机的概念,一个Broker中可以有多个Virtual host,每个Virtual host都有一套自己的Exchange和Queue,同一个Virtual host中的Exchange和Queue不能重名,不同的Virtual host中的Exchange和Queue名字可以一样。这样,不同的用户在访问同一个RabbitMQ Broker时,可以创建自己单独的Virtual host,然后在自己的Virtual host中创建Exchange和Queue,很好地做到了不同用户之间相互隔离的效果。

5.Exchange(交换机)

在这里插入图片描述
Exchange是一个比较重要的概念,它是消息到达RabbitMQ的第一站,主要负责根据不同的分发规则将消息分发到不同的Queue,供订阅了相关Queue的消费者消费到指定的消息。那Exchange有哪些分发消息的规则呢?这就要说到Exchange的4种类型了:direct、fanout、topic、headers。

在介绍这4种类型的Exchange之前,我们先来了解一下另外一个比较重要的概念:Routing key,翻译成中文就是路由键。当我们创建好Exchange和Queue之后,需要使用Routing key(通常叫作Binding key)将它们绑定起来,producer在向Exchange发送一条消息的时候,必须指定一个Routing key,然后Exchange接收到这条消息之后,会解析Routing key,然后根据Exchange和Queue的绑定规则,将消息分发到符合规则的Queue中。

1).direct
    direct的意思是直接的,direct类型的Exchange会将消息转发到指定Routing key的Queue上,Routing key的解析规则为精确匹配。也就是只有当producer发送的消息的Routing key与某个Binding key相等时,消息才会被分发到对应的Queue上。

2).fanout
    fanout是扇形的意思,该类型通常叫作广播类型。fanout类型的Exchange不处理Routing key,而是会将发送给它的消息路由到所有与它绑定的Queue上。

3).topic
    topic的意思是主题,topic类型的Exchange会根据通配符对Routing key进行匹配,只要Routing key满足某个通配符的条件,就会被路由到对应的Queue上。通配符的匹配规则如下:
    a.Routing key必须是一串字符串,每个单词用“.”分隔
    b.符号“#”表示匹配一个或多个单词
    c.符号“*”表示匹配一个单词
    
    eg:
        “*.123” 能够匹配到 “abc.123”,但匹配不到 “abc.def.123”;“#.123” 既能够匹配到 “abc.123”,也能匹配到 “abc.def.123”

4.headers

6.Queue中Arguments参数详解

1.x-message-ttl
    消息在队列中过期的时间

2.x-expires
    队列在多长时间没有被使用后删除

3.x-max-length
    加入queue中消息的条数。先进先出原则,超过多少条后面的消息会顶替前面的消息

4.x-max-length-bytes
    加入queue中消息的容积

5.x-dead-letter-routing-key
    延迟结束后指向队列(死信收容队列)

6.x-dead-letter-exchange
    延迟结束后指向交换机(死信收容交换机)
    
7.x-max-priority
    列队的优先级该参数会造成额外的CPU消耗

7.死信队列&死信交换器

DLX 全称(Dead-Letter-Exchange),称之为死信交换器,当消息变成一个死信之后,如果这个消息所在的队列存在x-dead-letter-exchange参数,那么它会被发送到x-dead-letter-exchange对应值的交换器上,这个交换器就称之为死信交换器,与这个死信交换器绑定的队列就是死信队列

8.死信消息

1.消息被拒绝(Basic.Reject或Basic.Nack)并且设置 requeue 参数的值为 false

2.消息过期了

3.队列达到最大的长度

9.代码示例

生产者:

# !/usr/bin/python3
# -*- encoding: utf-8 -*-
"""
@File        : producer.py
@Time        : 8/27/23 3:08 PM
@Author      : 
@Software    : PyCharm
@Description : 生产者
"""
import json

import pika

# 用户认证
from pika.exchange_type import ExchangeType

credentials = pika.PlainCredentials(username="admin", password="****")

# 连接配置
conn_addr = pika.ConnectionParameters(
    host="127.0.0.1",
    port=5672,
    virtual_host="/admin",
    credentials=credentials
)
# 连接
conn = pika.BlockingConnection(conn_addr)

# 建立通道 保持tcp连接
channel = conn.channel()

queue = "queue_one"


# direct
def direct_mode():
    exchange = "exchange_one"
    routing_key = "one"

    # 声明消息队列
    # 消息10秒未处理将过期
    queue_result = channel.queue_declare(queue=queue, arguments={"x-message-ttl": 1000 * 10})
    print(queue_result)

    # 声明交换机
    exchange_result = channel.exchange_declare(exchange=exchange, exchange_type=ExchangeType.direct.value)
    print(exchange_result)

    # 绑定队列
    result = channel.queue_bind(queue=queue, exchange=exchange, routing_key=routing_key)
    print(result)

    for i in range(1000):
        message = json.dumps({'========OrderId+++++': "2000%s" % i})
        # 发送消息
        channel.basic_publish(exchange=exchange, routing_key=routing_key, body=message)


# fanout
def fanout_mode():
    exchange = "exchange_two"
    routing_key = ""

    # 声明消息队列
    channel.queue_declare(queue=queue, arguments={"x-message-ttl": 1000 * 10})

    # 声明交换机
    channel.exchange_declare(exchange=exchange, exchange_type=ExchangeType.fanout.value)

    # 绑定队列
    channel.queue_bind(queue=queue, exchange=exchange, routing_key=routing_key)

    for i in range(1000):
        message = json.dumps({'========OrderId+++++': "3000%s" % i})
        # 发送消息
        channel.basic_publish(exchange=exchange, routing_key=routing_key, body=message)


# topic
def topic_mode():
    exchange = "exchange_three"
    # routing_key = "one"
    # routing_key = "*.two"
    routing_key = "*.two.#"

    # 声明消息队列
    channel.queue_declare(queue=queue, arguments={"x-message-ttl": 1000 * 10})

    # 声明交换机
    channel.exchange_declare(exchange=exchange, exchange_type=ExchangeType.topic.value)

    # 绑定队列
    channel.queue_bind(queue=queue, exchange=exchange, routing_key=routing_key)

    for i in range(1000):
        message = json.dumps({'========OrderId+++++': "1000%s" % i})
        # 发送消息
        channel.basic_publish(exchange=exchange, routing_key="one.two.a.b.c", body=message)


# 死信队列
def dead_queue():
    """
    模拟延时队列
    1. 创建1个死信交换机(正常创建即可)和一个死信队列(正常创建),二者通过路由键绑定。
    2. 创建1个业务交换机, 创建一个业务队列,队列关联一个死信交换机及与交换机绑定的一个死信队列路由键。
    3. 最后将业务交换机与业务队列绑定。
    4. 代码只需要对生产消息到业务队列,消费死信队列的消息就可以

    :return:
    """
    pro_exchange = "pro_ex"
    pro_routing_key = "pro_route"
    dead_exchange = "dead_ex"
    dead_routing_key = "dead_route"
    pro_queue = "pro_queue"
    dead_queue = "dead_queue_pro"

    # 正常队列
    channel.queue_declare(
        queue=pro_queue,
        arguments={
            "x-message-ttl": 1000 * 10,
            "x-dead-letter-exchange": dead_exchange,
            "x-dead-letter-routing-key": dead_routing_key,
        })

    # 死信队列
    channel.queue_declare(queue=dead_queue)

    # 正常交换机
    channel.exchange_declare(exchange=pro_exchange, exchange_type=ExchangeType.direct.value)

    # 死信交换机
    channel.exchange_declare(exchange=dead_exchange, exchange_type=ExchangeType.direct.value)

    # 绑定正常队列
    channel.queue_bind(queue=pro_queue, exchange=pro_exchange, routing_key=pro_routing_key)

    # 绑定死信队列
    channel.queue_bind(queue=dead_queue, exchange=dead_exchange, routing_key=dead_routing_key)

    for i in range(1000):
        message = json.dumps({'========OrderId+++++': "5000%s" % i})
        # 发送消息
        channel.basic_publish(exchange=pro_exchange, routing_key=pro_routing_key, body=message)


if __name__ == "__main__":

    # direct_mode()
    # fanout_mode()
    # topic_mode()
    dead_queue()

    # 关闭连接
    conn.close()

消费者:

# !/usr/bin/python3
# -*- encoding: utf-8 -*-
"""
@File        : client.py
@Time        : 8/27/23 3:08 PM
@Author      : 
@Software    : PyCharm
@Description : 消费者
"""
import pika

# 用户认证
credentials = pika.PlainCredentials(username="admin", password="****")

# 连接配置
conn_addr = pika.ConnectionParameters(
    host="127.0.0.1",
    port=5672,
    virtual_host="/admin",
    credentials=credentials
)
# 连接
conn = pika.BlockingConnection(conn_addr)

# 建立通道 保持tcp连接
channel = conn.channel()


def consume_one():
    # 定义回调函数处理消息队列中的消息
    def callback(ch, method, properties, body):
        print(method)
        print(properties)
        print(body.decode())
        # 确认消息
        ch.basic_ack(delivery_tag=method.delivery_tag)

    # 添加不按顺序分配消息的参数
    channel.basic_qos(prefetch_count=1)
    # 消费消息
    channel.basic_consume(queue="queue_one", on_message_callback=callback)

    # 开始接收消息,并进入阻塞状态, 队列里有信息才会进行处理
    channel.start_consuming()


# 第二种方式消费数据
def consume_two():
    for method, properties, body in channel.consume('queue_one'):
        print(body.decode())
        channel.basic_ack(method.delivery_tag)


# 消费死信队列消息
def consume_dead():
    for method, properties, body in channel.consume('dead_queue_pro'):
        print(body.decode())
        channel.basic_ack(method.delivery_tag)


if __name__ == "__main__":
    # consume_one()
    # consume_two()
    consume_dead()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值