处理 Socket.io 中的服务器故障

Posted

技术标签:

【中文标题】处理 Socket.io 中的服务器故障【英文标题】:Handling server failure in Socket.io 【发布时间】:2019-01-02 02:30:32 【问题描述】:

我正在使用 socket io 的配置,redis 作为缓存,rabbitMQ 用于 pub sub 和 mongo DB 作为聊天应用程序的辅助存储。基本上,redis 用作存储来设置连接的用户状态为在线或离线、用户对话 ID、参与者和更多数据点。在我的用例中,可能有多个用户使用相同的用户 id 连接,但有多个套接字连接,所以我在用户上保留一个计数器作为 redis 上的哈希,并在每次用户连接时使用相同的 id 连接时递增它。

socket.on('disconnect')

事件我正在编写递减计数器逻辑,如果与相同用户 ID 连接的套接字数量为 4,则将其设置为 3,如果为 1,则将其设置为 0,并且将用户设置为脱机。问题是,如果我的服务器停止,则不会触发 on disconnect 事件,并且下次当服务器启动时会建立一个新连接并且计数器会增加,例如它连接了 3 个套接字,那么它将使其变为 4 .我计划通过在 redis 上保留一组所有连接的用户来解决它,当服务器出现故障时,我正在编写一些清理代码

process.on('exit')

它将从 redis 集合中读取所有已连接用户的集合,并将它们设置为离线并计数为 0。这样当服务器恢复时,所有客户端都可以开始增加计数。

问题 - 我计划将它部署在 amazon elastic beanstalk 上,所以当它扩展流量时,我将不得不维护一组特定于机器的用户连接,这样当节点关闭时,它只会设置连接到该用户的状态节点离线,计数为 0。

仅供参考 - 我已经编写了一个回退机制,如果它在 redis 上找不到数据点,它将查询 mongoDB 并将其设置在 redis 上。因此,当服务器出现故障时,我可以清除 redis 并让它自行重新填充。但我不想清除 redis,因为从长远来看,它在大规模重新填充方面效率低下。

非常感谢您抽出宝贵时间。

【问题讨论】:

【参考方案1】:

首先,您的服务器多久停机一次?这应该是一个极端情况。也就是说,我将为每个连接设置一个唯一的 ID,然后跟踪哪些用户有哪些连接。

对于通过redis 共享状态的部分...... redis 是如何设置的?它的实例是否作为 EB 应用程序的一部分在每个 ec2 实例上启动?或者您使用的是 ElastiCache 之类的东西?如果是前者,你不必担心,因为每个服务器都有自己的 redis 实例。如果是后者,您可以让每台服务器在联机时自行注册 - 它可以将条目添加到列表中。然后它应该得到一个唯一的 ID,它可以使用它作为前缀,这样你就可以识别哪些用户和连接绑定到给定的服务器。

【讨论】:

感谢您抽出宝贵时间回答这个问题。我还没有遇到任何停机时间,但我需要建立一个强大的系统。我正在使用 ElasticCache,因为它由所有实例共享。由于用户的在线离线状态是在 redis 上设置的,因此第三个用户会想知道用户是在线还是离线连接到不同的实例。问题是,我可以获取实例 ID 并维护连接到实例的用户列表作为 redis 上的列表。 但是在断开连接时,我必须从列表中拉出用户,每次断开连接都需要 O(n),这不会太多吗? 对不起,我假设了一些事情。您是否知道 socket.io 内置了逻辑,因此客户端在断开连接后重新连接到服务器? socket.io/docs/client-api 您是否测试过只让客户端尝试重新连接? 另外,你使用的是socket.io-redis吗?使用它会隐藏有多个节点服务器,并让您编写逻辑,就好像只有一个 socket.io 进程一样。在这和默认的重新连接行为之间,只要您使用 forever 或 pm2 或其他东西在崩溃时快速重启,似乎您不需要清除一堆连接。

以上是关于处理 Socket.io 中的服务器故障的主要内容,如果未能解决你的问题,请参考以下文章

vSAN永久磁盘故障的处理过程

Linux启动故障处理

案例_XFS文件系统故障处理方法

PC服务器硬盘故障处理

生产环境 SR650服务器硬盘故障应急处理过程

处理coredns Pending故障