寫在開頭
- 最近的
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