携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第15天,点击查看活动详情
概述
什么是消息队列
MQ全称为Message Queue 消息队列(MQ)是一种应用程序对应用程序的通信方法。MQ是消费-生产者模型的一个典型的代表,一端往消息队列中不断写入消息,而另一端则可以读取队列中的消息。这样发布者和使用者都不用知道对方的存在。
RabbitMQ 是信息传输的中间者。本质上,从生产者(producers)接收消息,转发这些消息给消费者(consumers)。换句话说,能够根据指定的规则进行消息转发,缓冲,和持久化
消息队列可以简单理解为:把要传输的数据放在队列中。
消息队列的场景和工作流程
场景
有一些业务逻辑是不能立刻完成,会阻塞程序,类似于发送短信、邮件,这些都需要服务器给第三方发起请求,不能立刻得到结果。这就会造成用户操作过程停滞,所以解决办法就是将这些耗时操作,放到队列中去异步执行。
在程序系统中,例如外卖系统,订单系统,库存系统,优先级较高 发红包,发邮件,发短信,app消息推送等任务优先级很低,很适合交给消息队列去处理,以便于程序系统更快的处理其他请求。
工作流程
消息队列一般有三个角色:
队列服务端;
队列生产者;
队列消费者;
消息队列工作流程就如同一个流水线,有产品加工,一个输送带,一个打包产品
输送带就是 不停运转的消息队列服务端;
加工产品的就是 队列生产者;
在传输带结尾打包产品的 就是队列消费者;
消息队列的优点
1、程序解耦
允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。
2、冗余
消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。
许多消息队列所采用的"插入-获取-删除"范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。
3、峰值处理能力
在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见。
如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。
使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。
4、可恢复性
系统的一部分组件失效时,不会影响到整个系统。
消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。
5、顺序保证
在大多使用场景下,数据处理的顺序都很重要。
大部分消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。(Kafka保证一个Partition内的消息的有序性)
6、缓冲
有助于控制和优化数据流经过系统的速度,解决生产消息和消费消息的处理速度不一致的情况。
7、异步通信
很多时候,用户不想也不需要立即处理消息。比如发红包,发短信等流程。
消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。
总结
消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构。目前使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ。
vue中使用RabbitMQ
前提
后端需要在代码中引入RabbitMQ,这个就不赘述了,我也不懂。
Docker中安装RabbitMQ,并暴露15674端口
在RabbbitMq开启 stomp 协议的端口,
开启web界面rabbitmq
rabbitmq-plugins enable rabbitmq_web_stomp
rabbitmq-plugins enable rabbitmq_web_stomp_examples
安装过后别忘记重启了!!!
官方的RabbitMQ Web STOMP 插件文档:
官方文档:
可以遇到的问题:
解决:rabbitmq stomp启用以后无法访问http://localhost:15674/stomp
RabbitMQ在vue中的使用
安装依赖插件
npm install --save stompjs
连接成功的打印
完整代码
<!-- index.vue -->
<template>
<div class="page"></div>
</template>
<script>
// 引入stompjs
import Stomp from "stompjs"
export default {
data() {
return {
MQTT_SERVICE: "ws://192.168.1.102/ws", // mqtt服务地址
MQTT_USERNAME: "ppai", // 连接用户名
MQTT_PASSWORD: "ppai" // 连接密码
}
},
mounted() {
this.setRabitMQ()
},
methods: {
// 初始化
setRabitMQ() {
this.client = Stomp.client(this.MQTT_SERVICE)
this.connect()
},
onConnected: function (frame) {
//订阅频道
this.client.subscribe(
// 订阅到交换机
"/exchange/epai.xihan.ui",
this.responseCallback
// this.onFailed
)
},
// 失败后的处理
onFailed: function (frame) {
console.log("MQ Failed: " + frame)
// 失败后 等待5秒后重新连接
setTimeout(() => {
this.getRabitMQ()
}, 5000)
},
// 回传消息 MQ连接成功后的 数据相应 接收消息处理
responseCallback: function (frame) {
// console.log(frame.body);
try {
// 格式化MQ消息
let data = JSON.parse(JSON.parse(frame.body))
// 将mq信息放到vuex中
// this.$store.dispatch("setMQCutterDataList", data);
} catch (e) {
console.log(e)
}
},
// 开始连接
connect: function () {
const headers = {
// 賬號
login: this.MQTT_USERNAME,
// 密碼
passcode: this.MQTT_PASSWORD
}
// 登录Rabbit MQ服务
this.client.connect(headers, this.onConnected, this.onFailed)
}
}
}
</script>
<style scoped></style>