写在开头
- 最近的
Devops
和微前端已经写得差不多,开始复习下后端相关知识,之前想写的这篇文章,终于落地 - 如果你想加入前端交流群,可以文末联系我加入
正式开始
- 电脑环境 推荐Mac|Linux
- 安装
redis
,并且启动redis
`redis-server`
- 启动成功后会如下所示:
- redis默认端口6379
开始写Node.js代码
- 下载redis这个库
yarn add redis --save
- 使用Node.js连接redis
const redis = require('redis');
const client = redis.createClient(6379, '127.0.0.1');
- 由于是消息队列,于是需要有一个生产者、消费者
❝这里普及下消息队列的使用,跟redis一样,都是属于进程外的服务,就是单独要占用一个端口起服务的
❞
什么是消息队列?
- “消息队列”是在消息的传输过程中保存消息的容器。
- 消息被发送到队列中。“消息队列”是在消息的传输过程中保存消息的容器。消息队列管理器在将消息从它的源中继到它的目标时充当中间人。队列的主要目的是提供路由并保证消息的传递;如果发送消息时接收者不可用,消息队列会保留消息,直到可以成功地传递它。
- 即有生产者,消费者,发布订阅模式实现
消息队列使用场景
- 限流削峰(降低成本,不可能按流量最高峰去配备服务器)
开始实现
- 生产者
`const redis = require('redis');
const client = redis.createClient(6379, '127.0.0.1');
client.on('error', function (err) {
console.log('err' + err);
});
client.on('ready', function () {
client.publish('testFirst', 'hi! first!');
client.publish('testSecond', 'hi! second!');
client.publish('message', 'hi! message!');
});`
- 生产者对特定的channel进行publish,并且附带参数
- 消费者订阅特定的channel,消费,并且获取数据
`const client = require('redis').createClient(6379, '127.0.0.1');
client.on('error', function (err) {
console.log('err' + err);
});
client.subscribe('testSecond');
client.subscribe('message');
client.on('subscribe', function (channel, count) {
console.log('subscribe channel:' + channel + ', count:' + count);
});
client.on('message', function (channel, message) {
console.log('message channel:' + channel + ', msg:' + message);
});
client.on('unsubscribe', function (channel, count) {
console.log('unsubscribe channel:' + channel + ', count:' + count);
});`
- 结果:
- 我订阅了testsecoud和message两个通道,于是触发了subscribe事件两次,符合预期
模拟场景,生产者不断提供生产
- 加入定时器
`const redis = require('redis');
const client = redis.createClient(6379, '127.0.0.1');
client.on('error', function (err) {
console.log('err' + err);
});
client.on('ready', function () {
setInterval(() => {
client.publish('testSecond', 'hi! second!');
client.publish('message', 'hi! message!');
},1000);
});`
- 此时消费者不断打印,触发了message事件
❝这样,我们使用redis发布订阅模式,实现了简单的消息队列
❞
实现流量削峰,限流
- 目前我们生产是1S一条消息,但是我想控制成2S消费一次,可以吗?
- 我们控制下消费频率,首先不改变生产频率
`const client = require('redis').createClient(6379, '127.0.0.1');
const ArrayList = [];
client.on('error', function (err) {
console.log('err' + err);
});
client.subscribe('testSecond');
client.subscribe('message');
client.on('subscribe', function (channel, count) {
console.log('subscribe channel:' + channel + ', count:' + count);
});
client.on('message', function (channel, message) {
ArrayList.push({ channel, message });
});
client.on('unsubscribe', function (channel, count) {
console.log('channel:' + channel + ', count:' + count);
});
setInterval(()=>{
console.log(ArrayList,'ArrayList')
},2000)`
- 每2S读取一次队列的数据
-
模拟的跟实际有什么不一样?
- 模拟的是在一个进程端口内,属于进程内缓存
- 真实的是可以通过回复ACK确认消费,独占一个端口进程,属于进程外缓存
一个简单的通过redis实现消息队列就完成了
- 源码地址:
https://github.com/JinJieTan/MQ