如何使用 redis PUBLISH/SUBSCRIBE 和 nodejs 在数据值更改时通知客户端?

Posted

技术标签:

【中文标题】如何使用 redis PUBLISH/SUBSCRIBE 和 nodejs 在数据值更改时通知客户端?【英文标题】:How to use redis PUBLISH/SUBSCRIBE with nodejs to notify clients when data values change? 【发布时间】:2011-05-25 09:59:38 【问题描述】:

我正在使用 NodeJS 和 Redis 编写一个事件驱动的发布/订阅应用程序。我需要一个示例,说明如何在 Redis 中的数据值更改时通知 Web 客户端。

【问题讨论】:

【参考方案1】:

OLD 仅使用参考

依赖关系

使用express、socket.io、node_redis 和最后但并非最不重要的来自媒体大火的sample code。

安装node.js+npm(非root)

首先你应该(如果你还没有这样做的话)安装node.js+npm in 30 seconds(正确的方法,因为你应该root运行npm):

echo 'export PATH=$HOME/local/bin:$PATH' >> ~/.bashrc
. ~/.bashrc
mkdir ~/local
mkdir ~/node-latest-install
cd ~/node-latest-install
curl http://nodejs.org/dist/node-latest.tar.gz | tar xz --strip-components=1
./configure --prefix=~/local
make install # ok, fine, this step probably takes more than 30 seconds...
curl http://npmjs.org/install.sh | sh

安装依赖项

安装 node+npm 后,您应该通过以下命令安装依赖项:

npm install express
npm install socket.io
npm install hiredis redis # hiredis to use c binding for redis => FAST :)

下载示例

您可以从mediafire下载完整的示例。

解压包

unzip pbsb.zip # can also do via graphical interface if you prefer.

zip 里面有什么

./app.js

const PORT = 3000;
const HOST = 'localhost';

var express = require('express');

var app = module.exports = express.createServer();

app.use(express.staticProvider(__dirname + '/public'));

const redis = require('redis');
const client = redis.createClient();

const io = require('socket.io');

if (!module.parent) 
    app.listen(PORT, HOST);
    console.log("Express server listening on port %d", app.address().port)

    const socket  = io.listen(app);

    socket.on('connection', function(client) 
        const subscribe = redis.createClient();
        subscribe.subscribe('pubsub'); //    listen to messages from channel pubsub

        subscribe.on("message", function(channel, message) 
            client.send(message);
        );

        client.on('message', function(msg) 
        );

        client.on('disconnect', function() 
            subscribe.quit();
        );
    );

./public/index.html

<html>
<head>
    <title>PubSub</title>
    <script src="/socket.io/socket.io.js"></script>
    <script src="/javascripts/jquery-1.4.3.min.js"></script>
</head>
<body>
    <div id="content"></div>
    <script>    
        $(document).ready(function() 
            var socket = new io.Socket('localhost', port: 3000, rememberTransport: false/*, transports: ['xhr-polling']*/);
            var content = $('#content');

            socket.on('connect', function() 
            );

            socket.on('message', function(message)
                content.prepend(message + '<br />');
            ) ;

            socket.on('disconnect', function() 
                console.log('disconnected');
                content.html("<b>Disconnected!</b>");
            );

            socket.connect();
        );
    </script>
</body>
</html>

启动服务器

cd pbsb    
node app.js

启动浏览器

最好启动 google chrome(因为 websockets 支持,但不是必需的)。访问http://localhost:3000 以查看示例(在开始时,除了PubSub 作为标题,您什么都看不到)。

但是在publish 到频道pubsub 上,您应该会看到一条消息。下面我们将"Hello world!"发布到浏览器。

来自 ./redis-cli

publish pubsub "Hello world!"

【讨论】:

为什么app.js的根目录需要const client = redis.createClient() 你根本不需要使用 const。 var 也可以使用,也许我应该使用,因为 const 仅在较新的 javascript 引擎中可用。此外,这条线确保我们连接到我们在本例中使用的 redis 服务器。 该示例非常陈旧,因此无法与最新的 socket.io/express 模块甚至 node.js 保持同步。我会尝试更新代码。这段代码还有另一个大问题,它为每个连接的用户打开另一个 redis 连接。那应该只打开。我必须先工作,但之后我会尝试更新代码。 非常好。我仍然认为还有一些改进的空间,当我有时间时,我会上网。但是现在我真的很努力:$. 我认为 subscribe.on 应该在 socket.on('connection') 块之外以避免多次订阅/【参考方案2】:

这是一个没有那么多依赖项的简化示例。 你还是需要npm install hiredis redis

节点 JavaScript:

var redis = require("redis"),
    client = redis.createClient();

client.subscribe("pubsub");
client.on("message", function(channel, message)
  console.log(channel + ": " + message);
);

...将其放入 pubsub.js 文件并运行 node pubsub.js

在 redis-cli 中:

redis> publish pubsub "Hello Wonky!"
(integer) 1

应该在终端运行节点中显示:pubsub: Hello Wonky!! 恭喜!

Additional 4/23/2013: 我还想指出,当客户端订阅发布/订阅频道时,它会进入订阅者模式并且仅限于订阅者命令。您只需要创建额外的 redis 客户端实例。 client1 = redis.createClient(), client2 = redis.createClient() 这样一个可以处于订阅者模式,另一个可以发出常规 DB 命令。

【讨论】:

这里当我们向redis添加数据时,我应该运行发布pubsub来获取插入通知吗? @IshaS 如果您需要这样做,是的。如果您需要以原子方式运行多个命令,您还应该查看事务:redis.io/commands/exec @nak 这就像一个 GO 中的魅力 :) 如果尚未安装,某些用户可能需要安装“双端队列”。 还值得一提的是,如果要使用通配符,例如订阅pubsub/*,只需在示例中添加p:将@​​987654330@替换为psubscribemessage pmessage.【参考方案3】:

完成 Redis Pub/Sub 示例(实时聊天使用 Hapi.js 和 Socket.io)

我们试图了解 Redis Publish/Subscribe ("Pub/Sub") 并且所有现有示例要么已过时,要么过于简单,要么没有测试。 因此,我们使用 Hapi.js + Socket.io + Redis Pub/Sub 示例编写了一个Complete实时聊天和端到端测试

https://github.com/dwyl/hapi-socketio-redis-chat-example

Pub/Sub 组件只有几行 node.js 代码: https://github.com/dwyl/hapi-socketio-redis-chat-example/blob/master/lib/chat.js#L33-L40

我们鼓励您检查/尝试示例,而不是将其粘贴到此处(没有任何上下文)。

我们使用Hapi.js 构建它,但chat.js 文件是与Hapi 解耦的,并且可以轻松基本一起使用> node.js http服务器express(等)

【讨论】:

快递有这个例子吗? @Gixty 我们使用 Hapi.js 编写了示例因为所有其他示例都使用 Express.js ...如帖子中所述,移植它很简单到任何其他 Node.js 框架(只需将 express 应用程序/侦听器传递给 chat.js 初始化代码),它的工作原理完全相同。 ps:如果您是 Hapi.js 新手,请参阅:github.com/nelsonic/learn-hapi【参考方案4】:

处理 redis 错误以阻止 nodejs 退出。你可以通过写作来做到这一点;

subcribe.on("error", function()
  //Deal with error
)

我认为您遇到了异常,因为您使用的是订阅发布消息的同一个客户端。创建一个单独的客户端来发布消息,这可以解决您的问题。

【讨论】:

【参考方案5】:

查看acani-node on GitHub,尤其是文件acani-node-server.js。如果这些链接损坏,请在 acani's GitHub public repositories 中查找 acani-chat-server。

【讨论】:

哇,这看起来很甜!【参考方案6】:

如果您想使用 socket.io 0.7 AND 使用您需要更改的外部网络服务器(除了 staticProvider -> 静态问题):

a) 在 index.html 中提供 域名 而不是 localhost(即 var socket = io.connect('http://my.domain.com:3000'); )

b) 在 app.js 中更改 HOST(即 const HOST = 'my.domain.com'; )

c) 并在 app.js 的第 37 行添加 sockets(即 'socket.sockets.on('connection', function(client) ...' )

【讨论】:

【参考方案7】:

更新代码:

静态提供者

现在改名为

静态

见migration guide

【讨论】:

【参考方案8】:

根据@alex 解决。如果您有类似@tyler 提及的错误:

node.js:134
        throw e; // process.nextTick error, or 'error'

event on first tick ^ Error: Redis connection to 127.0.0.1:6379 failed - ECONNREFUSED, Connection refused at Socket.

那么你需要先安装Redis。看看这个:

http://redis.io/download

【讨论】:

以上是关于如何使用 redis PUBLISH/SUBSCRIBE 和 nodejs 在数据值更改时通知客户端?的主要内容,如果未能解决你的问题,请参考以下文章

阿里中间件团队,十分钟带你入门 RocketMQ

如何使用 Nodejs + Redis 获取给定 redis 键的 redis 值

如何连接redis

如何查看redis最近使用的命令

如何使用 Redis aeCreateTimeEvent?

如何使用 Azure Redis 缓存