Nodejs 第七十六章(MQ进阶)

MQ介绍和基本使用在上一章介绍过了,不再重复

  1. 消息:在RabbitMQ中,消息是传递的基本单元。它由消息体和可选的属性组成

  2. 生产者Producer:生产者是消息的发送方,它将消息发送到RabbitMQ的交换器(Exchange)中

  3. 交换器Exchange:交换器接收从生产者发送的消息,并根据特定的规则将消息路由到一个或多个队列中

  4. 队列Queue:队列是消息的接收方,它存储了待处理的消息。消费者可以从队列中获取消息并进行处理

  5. 消费者Consumer:消费者是消息的接收方,它从队列中获取消息并进行处理

MQ进阶用法

发布订阅

发布订阅,消息的发送者称为发布者(Publisher),而接收消息的一个或多个实体称为订阅者(Subscriber

回顾上一篇,点对点通讯生产者发送一条消息通过路由投递到Queue,只有一个消费者能消费到 也就是一对一发送

回归主题 发布订阅就是生产者的消息通过交换机写到多个队列,不同的订阅者消费不同的队列,也就是实现了一对多

发布订阅的模式分为四种

  1. Direct(直连)模式:把消息放到交换机指定key的队列里面。
  2. Topic(主题)模式: 把消息放到交换机指定key的队列里面,额外增加使用"*"匹配一个单词或使用"#"匹配多个单词
  3. Headers(头部)模式:把消息放到交换机头部属性去匹配队列
  4. Fanout(广播)模式:把消息放入交换机所有的队列,实现广播

发布订阅-代码编写

1. direct模式编写

主要就是通过 routingKey 匹配实现路由 这里的zs就是routingKey

生产者

js 复制代码
import amqplib from 'amqplib'
const connection = await amqplib.connect('amqp://localhost:5672')
//创建一个频道
const channel = await connection.createChannel() 
//声明一个交换机
/**
 * @param {String} exchange 交换机的名称
 * @param {String} type "direct" | "topic" | "headers" | "fanout" | "match" | 使用广播模式
 * @param {Object} options {durable: true} //开启消息持久化
 */
await channel.assertExchange('logs', 'direct', {
    durable: true
})
//发送消息
/**
 * @param {String} exchange 交换机的名称
 * @param {String} routingKey 路由键
 * @param {Buffer} content 消息内容
 */
 //这里的zs就是routingKey
channel.publish('logs', 'zs', Buffer.from('小满direct模式发送的消息'))

//断开
await channel.close()
await connection.close()
process.exit(0)

消费者(我们编写多个方便测试)

consume.js

js 复制代码
import amqplib from 'amqplib'
const connection = await amqplib.connect('amqp://localhost:5672')
const channel = await connection.createChannel() //创建一个频道

await channel.assertExchange('logs', 'direct', {
    durable: true
})

//添加一个队列
const { queue } = await channel.assertQueue('queue1', {
    durable: true
})
//绑定交换机
/**
 * @param {String} queue 队列名称
 * @param {String} exchange 交换机名称
 * @param {String} routingKey 路由键
 */
//匹配对应的zs值才能收到
await channel.bindQueue(queue, 'logs', 'zs')
//接收消息
channel.consume('queue1', (msg) => {
    console.log(msg.content.toString());
}, {
    noAck: true //自动确认消息被消费
})

consume2.js

js 复制代码
import amqplib from 'amqplib'
const connection = await amqplib.connect('amqp://localhost:5672')
const channel = await connection.createChannel() //创建一个频道

await channel.assertExchange('logs', 'direct', {
    durable: true
})

//添加一个队列
const { queue } = await channel.assertQueue('queue2', {
    durable: true
})
//绑定交换机
/**
 * @param {String} queue 队列名称
 * @param {String} exchange 交换机名称
 * @param {String} routingKey 路由键
 */
 //匹配对应的zs值才能收到
await channel.bindQueue(queue, 'logs', 'zs')
//接收消息
channel.consume('queue2', (msg) => {
    console.log(msg.content.toString());
}, {
    noAck: true //自动确认消息被消费
})
2. Topic模式编写

我们把模式切换成了Topic 并且publish 发布的时候 routingKey 换成了 xm.xxxxxxxx

生产者

js 复制代码
import amqplib from 'amqplib'
const connection = await amqplib.connect('amqp://localhost:5672')
//创建一个频道
const channel = await connection.createChannel() 
//声明一个交换机
/**
 * @param {String} exchange 交换机的名称
 * @param {String} type "direct" | "topic" | "headers" | "fanout" | "match" | 使用广播模式
 * @param {Object} options {durable: true} //开启消息持久化
 */
await channel.assertExchange('topic', 'topic', {
    durable: true
})
//发送消息
/**
 * @param {String} exchange 交换机的名称
 * @param {String} routingKey 路由键
 * @param {Buffer} content 消息内容
 */
 //注意这儿匹配规则换了 换成xm.xxxxxxxxxxxxxxxxxxxxx
channel.publish('logs', 'xm.sadsdsdasdasdasdsda', Buffer.from('小满topic模式发送的消息'))

//断开
await channel.close()
await connection.close()
process.exit(0)

消费者匹配(注意这里匹配规则xm.*'使用了* 就是模糊匹配的意思)

js 复制代码
import amqplib from 'amqplib'
const connection = await amqplib.connect('amqp://localhost:5672')
const channel = await connection.createChannel() //创建一个频道

await channel.assertExchange('topic', 'topic', {
    durable: true
})

//添加一个队列
const { queue } = await channel.assertQueue('queue1', {
    durable: true
})
//绑定交换机
/**
 * @param {String} queue 队列名称
 * @param {String} exchange 交换机名称
 * @param {String} routingKey 路由键 *匹配一个单词 #匹配多个单词
 */
 //这儿变化了
await channel.bindQueue(queue, 'topic', 'xm.*')
//接收消息
channel.consume('queue1', (msg) => {
    console.log(msg.content.toString());
}, {
    noAck: true //自动确认消息被消费
})
3. Headers模式

生产者(注意 publish 增加第四个参数开启了header 添加了data参数)

js 复制代码
import amqplib from 'amqplib'
const connection = await amqplib.connect('amqp://localhost:5672')
//创建一个频道
const channel = await connection.createChannel() 
   //声明一个交换机
   /**
    * @param {String} exchange 交换机的名称
    * @param {String} type "direct" | "topic" | "headers" | "fanout" | "match" | 使用广播模式
    * @param {Object} options {durable: true} //开启消息持久化
    */
   await channel.assertExchange('headers', 'headers', {
       durable: true
   })
   //发送消息
   /**
    * @param {String} exchange 交换机的名称
    * @param {String} routingKey 路由键
    * @param {Buffer} content 消息内容
    * @param {Object} options {headers: {'key': 'value'}} //定义匹配规则
    */
    //嘿 这儿变了
   channel.publish('headers', '', Buffer.from('小满headers模式发送的消息'),{
       headers: {
           data:'xmzs'
       }
   })

   //断开
   await channel.close()
   await connection.close()
   process.exit(0)

消费者(bindQueue 增加一个对象 属性跟生产者对应即可)

js 复制代码
   import amqplib from 'amqplib'
   const connection = await amqplib.connect('amqp://localhost:5672')
   const channel = await connection.createChannel() //创建一个频道
   await channel.assertExchange('headers', 'headers')

   //添加一个队列
   const { queue } = await channel.assertQueue('queue1')
   //绑定交换机
   /**
    * @param {String} queue 队列名称
    * @param {String} exchange 交换机名称
    * @param {String} routingKey 路由键 *匹配一个单词 #匹配多个单词
    */
   await channel.bindQueue(queue, 'headers', '',{
       data:'xmzs' //注意这儿不加headers 直接放值即可
   })
   //接收消息
   channel.consume(queue, (msg) => {
       console.log(msg.content.toString());
   }, {
       noAck: true //自动确认消息被消费
   })
4. Fanout模式

生产者(其实也就是routingKey 变成一个空值实现全体广播)

js 复制代码
import amqplib from 'amqplib'
const connection = await amqplib.connect('amqp://localhost:5672')
//创建一个频道
const channel = await connection.createChannel()
//声明一个交换机
/**
* @param {String} exchange 交换机的名称
* @param {String} type "direct" | "topic" | "headers" | "fanout" | "match" | 使用广播模式
* @param {Object} options {durable: true} //开启消息持久化
*/
await channel.assertExchange('fanout', 'fanout')
//发送消息
/**
* @param {String} exchange 交换机的名称
* @param {String} routingKey 路由键
* @param {Buffer} content 消息内容
*/
channel.publish('fanout', '', Buffer.from('小满fanout模式发送的消息'))

//断开
await channel.close()
await connection.close()
process.exit(0)

消费者(routingKey接受空值即可 就算有值也会被忽略)

js 复制代码
import amqplib from 'amqplib'
const connection = await amqplib.connect('amqp://localhost:5672')
const channel = await connection.createChannel() //创建一个频道
await channel.assertExchange('fanout', 'fanout')

//添加一个队列
const { queue } = await channel.assertQueue('queue1')
//绑定交换机
/**
* @param {String} queue 队列名称
* @param {String} exchange 交换机名称
* @param {String} routingKey 路由键 *匹配一个单词 #匹配多个单词
*/
await channel.bindQueue(queue, 'fanout', '')
//接收消息
channel.consume(queue, (msg) => {
console.log(msg.content.toString());
}, {
noAck: true //自动确认消息被消费
})

总结

通过使用RabbitMQ作为缓冲,避免数据库服务崩溃的风险。生产者将消息放入队列,消费者从队列中读取消息并进行处理,随后确认消息已被处理。在应用之间存在一对多的关系时,可以使用Exchange交换机根据不同的规则将消息转发到相应的队列:

  1. 直连交换机(direct exchange):根据消息的路由键(routing key)将消息直接转发到特定队列。
  2. 主题交换机(topic exchange):根据消息的路由键进行模糊匹配,将消息转发到符合条件的队列。
  3. 头部交换机(headers exchange):根据消息的头部信息进行转发。
  4. 广播交换机(fanout exchange):将消息广播到交换机下的所有队列
相关推荐
滚雪球~39 分钟前
npm error code ETIMEDOUT
前端·npm·node.js
沙漏无语40 分钟前
npm : 无法加载文件 D:\Nodejs\node_global\npm.ps1,因为在此系统上禁止运行脚本
前端·npm·node.js
m0_748234522 小时前
前端Vue3字体优化三部曲(webFont、font-spider、spa-font-spider-webpack-plugin)
前端·webpack·node.js
wy02_7 小时前
Linux下载RabbitMQ,并解决Github拒绝访问443的问题
linux·rabbitmq·github
丰云10 小时前
一个简单封装的的nodejs缓存对象
缓存·node.js
泰伦闲鱼10 小时前
nestjs:GET REQUEST 缓存问题
服务器·前端·缓存·node.js·nestjs
敲啊敲952711 小时前
5.npm包
前端·npm·node.js
j喬乔12 小时前
Node导入不了命名函数?记一次Bug的探索
typescript·node.js
z千鑫14 小时前
【前端】入门指南:Vue中使用Node.js进行数据库CRUD操作的详细步骤
前端·vue.js·node.js
小马哥编程19 小时前
原型链(Prototype Chain)入门
css·vue.js·chrome·node.js·原型模式·chrome devtools