nodeJS 中的发布/订阅实现

Posted

技术标签:

【中文标题】nodeJS 中的发布/订阅实现【英文标题】:Pub/sub implementation in nodeJS 【发布时间】:2011-08-19 16:29:41 【问题描述】:

我一直在尝试不同的 nodeJS 发布/订阅实现,并且想知道哪一个最适合特定应用程序。该应用程序的要求涉及在多通道、多用户 3D 环境中实时同步对象。

我开始使用 socket.io,创建了一个基本的通道数组,当用户发送消息时,它会循环通过该通道中的用户并向用户的客户端发送消息。这很好用,我没有遇到任何问题。

对于对象持久性,我使用 node_redis 添加了对 Redis 的支持。然后我用 Redis pub/sub 替换了通道数组上的 client.send 循环作为抽象层。但我注意到我需要为每个订阅的用户创建一个新的 Redis 客户端。而且我仍然需要存储 socket.io 客户端信息以在发布时向其发送消息。那可扩展性如何?还有其他(更好的)实现或我可以做的进一步优化吗?你会怎么做?

【问题讨论】:

【参考方案1】:

为了对象持久化,我添加了 Redis 支持使用 node_redis。然后我 替换了 client.send 循环 带有 Redis 发布/订阅的频道数组 作为抽象层。但是我 注意到我需要创建一个新的 每个用户的 Redis 客户端 订阅。我仍然需要 将 socket.io 客户端信息存储到 在发布时发送消息。如何 可扩展是什么?有没有其他 (更好的)实现或进一步 我可以做的优化?什么会 你会吗?

是的,您必须为每个 io 请求创建一个新的 redis 客户端。它很重且不可扩展。但是创建一个新的redis客户端连接并不会消耗太多内存。因此,如果您的系统用户数不超过 5000,则可以。为了扩展,您可以添加从 Redis 服务器来解决繁重的发布和订阅问题,如果您担心创建大量连接,那么您可以增加您的操作系统 uLIMIT。

您不需要将 socket.io 客户端存储在发送的消息中。一旦 redis 收到订阅的频道消息。它将向特定的 io 客户端发送消息。

subscribe.on("message",function(channel,message)  
 var msg =  message: [client.sessionId, message] ; 
 buffer.push(msg);
 if (buffer.length 15) buffer.shift(); 
 client.send(msg); > );

订阅多频道。我建议你预先存储多个频道的所有用户(你可以使用存储 Mongodb 或 redis)。

var store = redis.createClient();
var subscriber= redis.createClient()

store.hgetall(UID, function(e, obj)
     subscriber.subscribe(obj.ChannelArray.toArray());
 )

【讨论】:

这是很好的反馈。我会接受这些建议。谢谢。【参考方案2】:

我使用Faye.js。说真的,我能找到的最简单的发布/订阅实现。也许这会有所帮助!

【讨论】:

这看起来很有希望。我能看到的唯一缺点是支持的传输数量。两个(WebSocket 和轮询)与 socket.io 的六个支持的传输。【参考方案3】:

尝试查看this 有关 redis pub/sub 和 socket.io 的问题。

【讨论】:

这适用于单个频道,但不确定是否适用于多个频道?也许如果您跟踪消息中的频道名称并且确认用户在消息中的频道中,但似乎多余且效率低下。 @Detect:它可能看起来多余且效率低下,但您仍然可以胜过其他解决方案,因为 redis 原生针对高级并发连接进行了优化。找出答案的唯一方法是对每个解决方案进行基准测试。【参考方案4】:

或者你可以试试主宰。它使用 socket.io + redis pub sub 中间件 + node.js。支持所有传输。它可以帮助您处理客户端和 redis 之间的所有频道订阅或发布。 Juggernaut 是可扩展的,但只关心 redis 的开销,它不支持身份验证(你可以对它做一些技巧)。但是,redis 每秒可以写入/读取 >150 k,因此对于您的情况应该没问题。

https://github.com/maccman/juggernaut

【讨论】:

【参考方案5】:

仅供参考 Socket.io v0.7 将支持通道,并应简化您现有的代码(不再依赖 pub/sub lib)

见:http://cl.ly/0B0C3f133K1m3j422n0K

【讨论】:

这是一个改进。我担心如果不使用共享内存解决方案,将 socket.io 客户端信息保存在内存中将无法扩展。这就是为什么我使用 Redis 作为替代方案。

以上是关于nodeJS 中的发布/订阅实现的主要内容,如果未能解决你的问题,请参考以下文章

nodejs/vanilla 中的 Apollo-client 未触发订阅

ZeroMQ Python 订阅有效,NodeJS 订阅不在同一个发布者上

nodejs redis的发布与订阅

发布-订阅模式

如何使用 NodeJS mqtt、emqx 订阅所有主题/消息

如何使用 nodejs 在服务总线主题中创建新订阅?