【消息中间件】Rabbitmq的基本要素、生产和消费、发布和订阅

news2024/12/23 15:52:44

原文作者:我辈李想
版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。


文章目录

  • 前言
  • 一、消息队列的基本要素
    • 1.队列:queue
    • 2.交换机:exchange
    • 3.事件:routing_key
    • 4.任务:task
  • 二、生产消费模式
    • 1.安装pika
    • 2.模拟生产者进程
    • 3.模拟消费者进程
    • 4.ACK消息确认机制
    • 5.类的写法
      • (1)新建MyRabbitMQ.py文件
      • (2)基础RabiitMQ
  • 三、发布订阅模式
  • 四、多消息队列
  • 五、异常处理
    • 1. 死信队列


前言

Rabbitmq消息队列,Windows安装RabbitMQ教程


一、消息队列的基本要素

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

消息队列是一种中间件 ,用于在不同的组件或系统之间传递消息(进程间通讯的一种)。 它提供了一种可靠的机制(AMQP)来存储和传递消息,并确保消息的顺序性和可靠性。消息队列需要存储消息。

1.队列:queue

用于接入消息队列的出入口

2.交换机:exchange

用于存储的一种通道

3.事件:routing_key

用于记录的一种标记

4.任务:task

这里的任务就是处理程序,还可能包含回调函数

注:基于我们使用不同的要素组合,分化出了基础的生产消费模式和发布订阅模式。其中只使用队列和任务的方式划为生产消费模式,4个同时使用的方式划为发布订阅模式。

二、生产消费模式

消息队列处理的是进程间通讯问题,生产者和消费者正是2个进程的程序,代表了不同的组件或系统。
我们使用python来实现相关功能,可以通过pika这个三方库来实现。

1.安装pika

pip install pika -i https://pypi.tuna.tsinghua.edu.cn/simple

2.模拟生产者进程

这里的生产者进程可能是一个后端程序、也可能是一个py文件、也可能知识一条触发命令。

# !/usr/bin/env python
import pika

# ######################### 生产者 #########################
# 如果设置密码,那么就需要加以下一句话配置用户名与密码
credentials = pika.PlainCredentials("root", "123")
# host:ip地址 credentials:链接凭证
connection = pika.BlockingConnection(pika.ConnectionParameters(
    host='localhost', credentials=credentials))
# 声明一个channel,类似数据库打开一个链接
channel = connection.channel()
# 创建一个队列,队列名称叫做hello
channel.queue_declare(queue='hello')
# 向hello这个队列里发送一个Hello World!   exchange:如果当做一个普通队列,就为空
channel.basic_publish(exchange='', routing_key='hello', body='Hello World!')
print(" [x] Sent 'Hello World!'")
connection.close()

3.模拟消费者进程

消费者

# !/usr/bin/env python
import pika

# ########################## 消费者 ##########################
# 如果设置密码,那么就需要加以下一句话配置用户名与密码
credentials = pika.PlainCredentials("root", "123")
# host:ip地址 credentials:链接凭证
connection = pika.BlockingConnection(pika.ConnectionParameters(
    host='localhost', credentials=credentials))
channel = connection.channel()

# channel.queue_declare(queue='hello')

def callback(ch, method, properties, body):
    print(" [x] Received %r" % body)
    # 取一个就关掉的方法
    channel.stop_consuming()
# 去hello队列里拿数据,一但有数据,就执行callback
channel.basic_consume(callback, queue='hello', no_ack=True)

print(' [*] Waiting for messages. To exit press CTRL+C')
# 开始去取得意思【表示一直去队列中取会夯住】注意可以去一个就关掉
channel.start_consuming()

4.ACK消息确认机制

ACK机制是消费者从RabbitMQ收到消息并处理完成后,反馈给RabbitMQ,RabbitMQ收到反馈后才将次消息从队列中删除。

生产者

# !/usr/bin/env python
import pika

# ######################### 生产者 #########################
# 如果设置密码,那么就需要加以下一句话配置用户名与密码
credentials = pika.PlainCredentials("root", "123")
# host:ip地址 credentials:链接凭证
connection = pika.BlockingConnection(pika.ConnectionParameters(
    host='localhost', credentials=credentials))
# 声明一个channel,类似数据库打开一个链接
channel = connection.channel()
# 创建一个队列,队列名称叫做hello
channel.queue_declare(queue='hello')
# 向hello这个队列里发送一个Hello World!   exchange:如果当做一个普通队列,就为空
channel.basic_publish(exchange='', routing_key='hello', body='Hello World!')
print(" [x] Sent 'Hello World!'")
connection.close()

消费者

# !/usr/bin/env python
import pika

# ########################## 消费者 ##########################
# 如果设置密码,那么就需要加以下一句话配置用户名与密码
credentials = pika.PlainCredentials("root", "123")
# host:ip地址 credentials:链接凭证
connection = pika.BlockingConnection(pika.ConnectionParameters(
    host='localhost', credentials=credentials))

channel = connection.channel()


# channel.queue_declare(queue='hello')

def callback(ch, method, properties, body):
    print(" [x] Received %r" % body)
    # 取值做确认工作
    ch.basic_ack(delivery_tag=method.deliver_tag)


# 去hello队列里拿数据,一但有数据,就执行callback,
# no_ack=Flask必须在取值时做确认工作,否则值不会被取出
channel.basic_consume(callback, queue='hello', no_ack=False)

print(' [*] Waiting for messages. To exit press CTRL+C')
# 开始去取得意思【表示一直去队列中取会夯住】注意可以去一个就关掉
channel.start_consuming()

5.类的写法

这个类使用 pika 库进行与 RabbitMQ 的通信。当你使用 send_message() 或 receive_message() 、consume_messages方法时,Channel 对象必须是打开的。如果没有连接或者通道没有打开,这些方法将引发 ValueError 异常。

(1)新建MyRabbitMQ.py文件

文件包含rabbitmq的类,类中包含连接到RabbitMQ,并在连接对象上创建一个管道,然后就可以使用send_message()receive_message()方法、consume_messages发送和接收消息,接收消息会调用回调方法。

下面是一个带有消费回调的完整 RabbitMQ 类

import pika
import time

class RabbitMQ:
    def __init__(self, host, port, username, password):
        self.host = host
        self.port = port
        self.username = username
        self.password = password
        self.connection = None
        self.channel = None

    def connect(self, timeout=10):
        credentials = pika.PlainCredentials(self.username, self.password)
        parameters = pika.ConnectionParameters(host=self.host,
                                               port=self.port,
                                               credentials=credentials)
        start_time = time.time()
        while time.time() - start_time < timeout:
            try:
                self.connection = pika.BlockingConnection(parameters)
                self.channel = self.connection.channel()
                return True
            except pika.exceptions.AMQPConnectionError:
                time.sleep(1)
        return False

    def send_message(self, exchange, routing_key, message):
        try:
            self.channel.basic_publish(exchange=exchange,
                                       routing_key=routing_key,
                                       body=message,
                                       properties=pika.BasicProperties(delivery_mode=2))
        except AttributeError:
            raise ValueError("Channel is not open. Call connect() before send_message().")

    def receive_message(self, queue, auto_ack=False):
        try:
            method_frame, properties, body = self.channel.basic_get(queue=queue, auto_ack=auto_ack)
            if method_frame:
                return body.decode('utf-8')
            else:
                return None
        except AttributeError:
            raise ValueError("Channel is not open. Call connect() before receive_message().")

    def consume_messages(self, queue, callback):
        try:
            self.channel.basic_consume(queue=queue, on_message_callback=callback, auto_ack=True)
            self.channel.start_consuming()
        except AttributeError:
            raise ValueError("Channel is not open. Call connect() before consume_messages().")
    
    def create_queue(self, name):
        try:
            self.channel.queue_declare(queue=name, durable=True)
        except AttributeError:
            raise ValueError("Channel is not open. Call connect() before create_queue().")

    def bind_queue(self, queue, exchange, routing_key):
        try:
            self.channel.queue_bind(queue=queue, exchange=exchange, routing_key=routing_key)
        except AttributeError:
            raise ValueError("Channel is not open. Call connect() before bind_queue().")

    def close(self):
        try:
            self.connection.close()
        except AttributeError:
            raise ValueError("Connection is not open. Call connect() before close().")

(2)基础RabiitMQ

基于队列_生产

创建RabiitMQ_生产.py文件,内容如下:

from MyRabbitMQ import RabbitMQ

if __name__ == '__main__':
    print('RabbitMQ生产')
    my_host = '127.0.0.1'
    my_username = 'guest'
    my_password = 'guest'
    my_queue = 'hello'
    my_exchange = 'BBB'
    my_routing_key = 'hello'

    rabbitmq = RabbitMQ(my_host, 5672, my_username, my_password)
    if rabbitmq.connect():
        rabbitmq.create_queue(my_queue)
        rabbitmq.send_message('', my_queue, message='开始了')
    else:
        print("Failed to connect to RabbitMQ.")

基于队列_消费

from MyRabbitMQ import RabbitMQ

if __name__ == '__main__':
    print('RabbitMQ消费')
    my_host = '127.0.0.1'
    my_username = 'guest'
    my_password = 'guest'
    my_queue = 'hello'
    my_exchange = 'BBB'
    my_routing_key = 'hello'


    def callback(channel, method, properties, body):
        print("Received message: %s" % body.decode('utf-8'))
        channel.basic_ack(delivery_tag=method.delivery_tag)


    rabbitmq = RabbitMQ(my_host, 5672, my_username, my_password)
    if rabbitmq.connect():
        rabbitmq.create_queue(my_queue)
        rabbitmq.consume_messages(my_queue, callback)
    else:
        print("Failed to connect to RabbitMQ.")

在此例中,当一个新的消息从名为 my_queue 的队列中接收时,回调函数 callback 将被调用并打印消息内容。

注意:如果你的回调函数需要执行较复杂的操作(例如长时间运行或使用多线程),则你应该确保它是线程安全的,并且在操作完成后调用 ch.basic_ack,这样 RabbitMQ 就知道消息已经被处理并可以将其从队列中删除。

三、发布订阅模式

发布订阅模式的消费者是queue队列,需要绑定exchange和routing_key,实际使用时可能存在一个队列绑定多个routing_key,或多个queue绑定一个routing_key,所以在我们的消费者处理中,需要判断routing_key事件做必要的区分。

基于exchangs交换机的生产者

from MyRabbitMQ import RabbitMQ

if __name__ == '__main__':
    print('RabbitMQ消费')
    my_host = '127.0.0.1'
    my_username = 'guest'
    my_password = 'guest'
    my_queue = 'hello'
    my_exchange = 'BBB'
    my_routing_key = 'hello'


    rabbitmq = RabbitMQ(my_host, 5672, my_username, my_password)
    if rabbitmq.connect():
		rabbitmq.send_message(my_exchange, my_routing_key, message='开始了')
    else:
        print("Failed to connect to RabbitMQ.")

基于exchangs交换机的消费者

from MyRabbitMQ import RabbitMQ

if __name__ == '__main__':
    print('RabbitMQ消费')
    my_host = '127.0.0.1'
    my_username = 'guest'
    my_password = 'guest'
    my_queue = 'hello'
    my_exchange = 'BBB'
    my_routing_key = 'hello'


    def callback(channel, method, properties, body):
        print("Received message: %s" % body.decode('utf-8'))
        channel.basic_ack(delivery_tag=method.delivery_tag)


    rabbitmq = RabbitMQ(my_host, 5672, my_username, my_password)
    if rabbitmq.connect():
        rabbitmq.create_queue(my_queue)
        # rabbitmq.send_message(my_exchange, my_routing_key, message='开始了')
        rabbitmq.bind_queue(my_queue, my_exchange, my_routing_key)
        rabbitmq.consume_messages(my_queue, callback)
    else:
        print("Failed to connect to RabbitMQ.")

在这里插入图片描述

四、多消息队列

import pika
import random
from retry import retry
def on_message(channel, method_frame, header_frame, body)
    print(method_frame.delivery_tag)
    print(body)
    print(header_frame)
    channel.basic_ack(delivery_tag=method_frame.delivery_tag)

node1 = pika.URLParameters('amqp://node1')
node2 = pika.URLParameters('amqp://node2')
node3 = pika.URLParameters('amqp://node3')
all_endpoints = [node1, node2, node3]

@retry(pika.exceptions.AMQPConnectionError, delay=5, jitter(1, 3)
def consume():
    random.shuffle(all_endpoints)
    connection = pika.BlockingConnection(all_endpoints)
    channel = connection.channel()
    channel.basic_qos(prefetch_count=1)
    channel.queue_declare('recovery-example', durable=False, auto_delete=True)
    channel.basic_consume('recovery-example', on_message)
    try:
        channel.start_consuming()
    except KeyboardInterrupt:
        channel.stop_consuming()
        connection.close()
    except pika.excaptions.ConnectionClosedByBroker:
        continue
consume()

五、异常处理

from pika.exceptions import ChannelClosed
from pika.exceptions import ConnectionClosed

    try:
        mq.start_consuming_message()
    except ConnectionClosed as e:
        mq.clear()
        mq.reconnect(queue_oname, exchange, route_key, is_use_rabbitpy=1)
        mq.start_consuming_message()
    except ChannelClosed as e:
        mq.clear()
        mq.reconnect(queue_oname, exchange, route_key, is_use_rabbitpy=1)
        mq.start_consuming_message()

1. 死信队列

死信队列就是备份队列,rabbitMQ有,kafka还没有

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1317927.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

git的安装及使用

git的安装及使用 git的安装 官网地址&#xff1a;https://git-scm.com/download/win 在任何位置输入bash或sh,进入git 设置用户名邮箱。 git config --global user.name “wfyfly” git config --global user.email 2423217861qq.com 查看配置信息 git config --list --globa…

【FPGA】Verilog:编码器 | 实现 4 到 2 编码器

0x00 编码器&#xff08;Encoder&#xff09; 编码器与解码器相反。当多台设备向计算机提供输入时&#xff0c;编码器会为每一个输入生成一个与设备相对应的信号&#xff0c;因此有多少比特就有多少输出&#xff0c;以数字形式表示输入的数量。 例如&#xff0c;如果有四个输…

C# 编写Windows服务程序

1.什么是windows服务&#xff1f; Microsoft Windows 服务&#xff08;即&#xff0c;以前的 NT 服务&#xff09;使您能够创建在它们自己的 Windows 会话中可长时间运行的可执行应用程序。这些服务可以在计算机启动时自动启动&#xff0c;可以暂停和重新启动而且不显示任何用…

智能优化算法应用:基于天牛须算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于天牛须算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于天牛须算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.天牛须算法4.实验参数设定5.算法结果6.参考文…

[verilog] Verilog 数值表示

主页&#xff1a; 元存储博客 文章目录 前言1. 整数表示1.1 整数数据类型1.2 整数转换函数 2. 负数表示3. 实数表示4. 逻辑电平表示5. 逻辑值表示6. 字符表示法7. 字符串表示 前言 Verilog中&#xff0c;可以使用多种方式表示数值。 1. 整数表示 1.1 整数数据类型 基数格式…

高分通过HarmonyOS基础认证-必学HarmonyOS第一课_附题库答案【官网课程提炼关键知识点-精炼】【鸿蒙专栏-26】

系列文章&#xff1a; HarmonyOS应用开发者基础认证满分答案&#xff08;100分&#xff09; HarmonyOS应用开发者基础认证【闯关习题 满分答案】 HarmonyOS应用开发者高级认证满分答案&#xff08;100分&#xff09; HarmonyOS云开发基础认证满分答案&#xff08;100分&#xf…

博客动态校验+静态校验二次开发方式

静态校验&#xff1a; 1&#xff1a;将需要静态校验的参数继承BaseReqeust类重写validate方法&#xff1a; 动态校验&#xff1a; 1&#xff1a;在需要校验的实现类上加&#xff1a; BizValidate注解 2&#xff1a;写一个校验类&#xff0c;方法命名规范为&#xff1a;需要校…

【013】查看qtawesome 库,并调用库中的元素_#py

qtawesome 库 1. 安装2. 查看库3. 查询图标4. 使用图标 1. 安装 pip install qtawesome -i https://pypi.douban.com/simple-i https://pypi.douban.com/simple 为镜像方法&#xff0c;可以使下载速度变快 2. 查看库 运行下述代码&#xff0c;可以打开下面的窗口。 from qt…

R语言【rgbif】——occ_search对待字符长度大于1500的WKT的特殊处理真的有必要吗?

一句话结论&#xff1a;只要有网有流量&#xff0c;直接用长WKT传递给参数【geometry】、参数【limit】配合参数【start】获取所有记录。 当我在阅读 【rgbif】 给出的用户手册时&#xff0c;注意到 【occ_search】 强调了 参数 【geometry】使用的wkt格式字符串长度。 文中如…

牛客网 DP35 【模板】二维前缀和

代码&#xff1a; import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextInt()) { //…

基于Java SSM框架实现水果销售网站系统项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架实现水果销售网站系统演示 摘要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&a…

多维时序 | MATLAB实现RIME-LSSVM【23年新算法】基于霜冰优化算法(RIME)优化最小二乘向量机(LSSVM)多变量时间序列预测

多维时序 | MATLAB实现RIME-LSSVM【23年新算法】基于霜冰优化算法(RIME)优化最小二乘向量机(LSSVM)多变量时间序列预测 目录 多维时序 | MATLAB实现RIME-LSSVM【23年新算法】基于霜冰优化算法(RIME)优化最小二乘向量机(LSSVM)多变量时间序列预测预测效果基本介绍模型描述程序设…

【日积月累】Mysql性能优化

目录 【日积月累】Mysql性能优化 1.前言2.MySql性能优化的主要方面2.1硬件和操作系统成面优化2.2架构设计层优化&#xff08;表结构&#xff09;2.3程序配置优化2.5表结构及索引优化2.4sql执行优化 3.总结4.参考 文章所属专区 积月累 1.前言 MySQL是一种常用的开源关系型数据…

WorkPlus:保护组织数据安全与提升企业效率的局域网即时通讯软件

在当今互联网时代&#xff0c;随着企业信息化的进一步推进&#xff0c;数据安全和高效沟通成为企业发展不可忽视的重要因素。局域网即时通讯软件WorkPlus以其强大的数据保护功能和便利的沟通协作特性&#xff0c;成为企业选择的首选软件解决方案。 为何企业需要安全的即时消息…

Unity升级到2022版本后,打开Spine会卡住

1&#xff09;Unity升级到2022版本后&#xff0c;打开Spine会卡住 2&#xff09;iPhone在同时播放多个音效的时候会压低某些音源的音量 3&#xff09;在Y77手机上出现IMGSRV:GetMainShaderConstantBufferBaseAddress: Unsupported 4&#xff09;UE4打包后在部分安卓机型出现“花…

HarmonyOS4.0从零开始的开发教程18HarmonyOS应用/元服务上架

HarmonyOS&#xff08;十六&#xff09;HarmonyOS应用/元服务上架 简介 随着生活节奏的加快&#xff0c;我们有时会忘记一些重要的事情或日子&#xff0c;所以提醒功能必不可少。应用可能需要在指定的时刻&#xff0c;向用户发送一些业务提醒通知。例如购物类应用&#xff0c…

fckeditor编辑器改造示例:增加PRE,CODE控件

查看专栏目录 Network 灰鸽宝典专栏主要关注服务器的配置&#xff0c;前后端开发环境的配置&#xff0c;编辑器的配置&#xff0c;网络服务的配置&#xff0c;网络命令的应用与配置&#xff0c;windows常见问题的解决等。 文章目录 修改方法&#xff1a;1&#xff09;修改fckco…

Linux 基本语句_16_Udp网络聊天室

代码&#xff1a; 服务端代码&#xff1a; #include <stdio.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdlib.h> #include <unistd.h> #include <string…

STM32 DAC+串口

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、DAC是什么&#xff1f;二、STM32 DAC1.什么型号有DAC2. 简介3. 主要特点4. DAC框图5. DAC 电压范围和引脚 三、程序步骤1. 开启DAC时钟2. 配置引脚 PA4 PA5…

【数学建模】《实战数学建模:例题与讲解》第十二讲-因子分析、判别分析(含Matlab代码)

【数学建模】《实战数学建模&#xff1a;例题与讲解》第十二讲-因子分析、判别分析&#xff08;含Matlab代码&#xff09; 基本概念时间判别费歇判别贝叶斯判别 习题10.31. 题目要求2.解题过程3.程序4.结果 习题10.6&#xff08;1&#xff09;1. 题目要求2.解题过程——对应分析…