node.js - 使用 node.js 应用程序和套接字 io 进行水平缩放

标签 node.js redis socket.io high-availability

我和我的团队正在开发数字标牌平台。

我们在世界各地有大约 2000 个 Raspberry Pi 使用 Socket IO 连接到 Nodejs 服务器。树莓派正在启动连接。

我们希望能够在多个服务器上水平扩展我们的应用程序,但我们有一个无法解决的问题。

基本上,应用程序将连接的 Raspberry 的套接字存储在一个数组中。 我们有一个外部程序调用服务器内的 API,结果是服务器搜索哪些套接字将受到 API 调用的“影响”并向它们发送信息。

经过大量搜索,我们假设我们必须将套接字(或其 ID)存储在其他地方(Redis?),以使应用程序无状态。然后,任何服务器都可以响应 API 调用并在中心位置查找套接字。

不幸的是,我们找不到任何有关如何执行此操作的详细示例。

你能帮助我们吗?

谢谢

最佳答案

(您无法将来自多个服务器实例的套接字存储在像 redis 这样的共享数据存储中:它们仅在启动它们的服务器上下文中才有意义)。

您将需要一个 Node.js 服务器集群来处理此问题。有多种方法可以创建集群。它们都涉及将来自 RP 的传入连接定向到“通用”主机名,例如 server.example.com。 server.example.com 主机名后面将是多个 Node.js 服务器。

来自每个 RPi 的每个传入连接仅连接到这多个服务器之一。 (我相信你知道这一点。)这意味着集群中的一台 Node.js 服务器“拥有”每个单独的 RPi。

(告诉您如何安装 Node.js 服务器集群超出了本答案的范围。提示:循环 DNS 或反向代理 nginx 前端。)

然后,您希望将来自每个 API 调用的传入数据路由(扇出)到集群中的每个服务器,以便服务器可以将其路由到它拥有的 RP。

这是处理这个问题的好方法:

  1. 设置 Redis 缓存或其他共享数据存储。它可以非常小。
  2. 当每个 Node.js 服务器启动时,将其自身注册为事件状态。也就是说,让它将自己的用于处理 API 调用的特定地址放入共享服务器中。具体地址可能采用 12.34.56.78:3000 的形式:即 IP 地址和端口。
  3. 让每台服务器经常更新该地址(大约一分钟一次),以表明它仍然有效。
  4. 当 API 调用到达 server.example.com 时,它将到达或多或少随机选择的 Node.js 服务器实例。
  5. 让该服务器从 Redis 缓存中读取服务器地址列表
  6. 让该服务器向除自身之外的所有服务器重复 API 调用。将 repeated=yes 等参数添加到重复的 API 调用中。
  7. 然后,每个服务器都会查看其已连接套接字列表并执行您的应用程序所需的操作。
  8. 在服务器关闭时,让服务器自行取消注册 - 从 redis 中删除其地址 - 如果可能的话。

换句话说,构建一种将 API 调用分散到集群中所有事件 Node.js 服务器的方法。

如果必须扩展到大量(超过一百个左右)node.js 服务器,或者每分钟数百个 API 调用,您可能应该使用消息队列软件进行研究。

保护您的 REDIS 服务器免受互联网上随机网络攻击的影响。

关于node.js - 使用 node.js 应用程序和套接字 io 进行水平缩放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57973825/

相关文章:

linux - 在 Linux 上运行 node.js 时如何解决 "Server terminated early with status 127"?

node.js - 需要了解一些关于socket.io和redis和nginx的知识

node.js - 检查redis是否正在运行-> node js

ruby-on-rails - Resque 工作人员无法识别 Rails Mongoid 模型

javascript - Node.js 中的 Python 多处理

javascript - GraphQL:为构建模式提供的一种类型缺少名称

data-structures - Redis : Pros and Cons for following two approaches

node.js - Socket.io 和 Express3 - 客户端请求 404/socket.io/socket.io.js

ios - 我正在使用 socket.io 客户端进行快速连接,但在发出消息时,node.js 日志中有 ERCONNRESET

ember.js - 如何通过 ES6 模块使用 Socket.IO 客户端?