封面

nodejs中使用redis的订阅分发功能

订阅者模式是23中设计模式中常用的模式之一,我们经常会在代码中用到。那么redis的订阅和分发有什么作用呢?当应用同时有多个实例时,如果调用某个api,那么通过负载均衡请求只会到达某一个实例,但是如果我们有需求调用api时所有的实例都需要对应的处理,那要怎么实现呢?

pub/sub的原理

应用在启动时可以通过subscribe来订阅一个或多个channel,这就好比我们通过RSS订阅某个或者多个喜欢的博主,那么此是我们对这个channel就处于监听状态。当博主发布新的文章的话就会给所有的订阅者发送消息,我们监听到发过来的消息后就可以做对应的处理。

nodejs redis库

image-20210517123635837

通过关键字搜索排名前三的依次是redis,connect-redis,ioredisredis发布最早当然积累的人气也最高,但它的方法比较古老,leader推荐使用ioredis。不过经过实际尝试,不同的库写法基本上没有区别,互相切换也就只需要换一个依赖库,不到3分钟即可解决。

  1. node-redis
    注意:这个库在github名字和npm托管上不一样,npm上直接叫redis

    const redis = require("redis");

    const subscriber = redis.createClient(port,host);
    const publisher = redis.createClient(port,host);

    let messageCount = 0;

    subscriber.on("subscribe", function(channel, count) {
    publisher.publish("a channel", "a message");
    publisher.publish("a channel", "another message");
    });

    subscriber.on("message", function(channel, message) {
    messageCount += 1;

    console.log("Subscriber received message in channel '" + channel + "': " + message);

    if (messageCount === 2) {
    subscriber.unsubscribe();
    subscriber.quit();
    publisher.quit();
    }
    });

    subscriber.subscribe("a channel");
  2. ioreids

    注意:这里官方给例子分了2个文件publisher.jssubscriber.js2个文件,这里把合并在了一起。

const Redis = require("ioredis");
const pub = new Redis(port,host);
const sub = new Redis(port,host);

setInterval(() => {
const message = { foo: Math.random() };
// Publish to my-channel-1 or my-channel-2 randomly.
const channel = `my-channel-${1 + Math.round(Math.random())}`;

// Message can be either a string or a buffer
pub.publish(channel, JSON.stringify(message));
console.log("Published %s to %s", message, channel);
}, 1000);

sub.subscribe("my-channel-1", "my-channel-2", (err, count) => {
if (err) {
// Just like other commands, subscribe() can fail for some reasons,
// ex network issues.
console.error("Failed to subscribe: %s", err.message);
} else {
// `count` represents the number of channels this client are currently subscribed to.
console.log(
`Subscribed successfully! This client is currently subscribed to ${count} channels.`
);
}
});

sub.on("message", (channel, message) => {
console.log(`Received ${message} from ${channel}`);
});

// There's also an event called 'messageBuffer', which is the same as 'message' except
// it returns buffers instead of strings.
// It's useful when the messages are binary data.
sub.on("messageBuffer", (channel, message) => {
// Both `channel` and `message` are buffers.
console.log(channel, message);
});

主要API

  • publish 给某个channel发布一条消息,一般是通过用户或者程序主动触发。
  • subscribe 订阅某个或多个channel,一般来说应用启动时就会将需要的channel进行订阅。
  • on 监听某个或多个channel的消息,一旦publish了对应channel的消息,On就会收到然后做对应的业务逻辑处理。

总结

不难发现,redis的示例中创建了2个redis实例,分别为publishersubscriber,而ioredis中虽然也是创建了2个redis实例,但是它分成了2个文件,名字者叫redis。因此当对redis实现原理不熟仅仅按照api使用的情况下很容易像我一样只创建一个实例,然后用同一个实例进行pub/sub/on。这样做的后果是只会pub,sub中收不到任何消息, 实际上pub/sub需要分别创建单独的实例进行处理。

文章目录
  1. 1. pub/sub的原理
  2. 2. nodejs redis库
  3. 3. 主要API
  4. 4. 总结


twitter分享


如果想及时收到回复,可在 订阅中心Participating中勾选Email

Fork me on GitHub