用过的
NodeJS,Socket.io
问题
假设有两个用户U1和U2通过Socket.io连接到应用程序。该算法如下:
- U1完全失去Internet连接(例如,关闭Internet)
- U2向U1发送消息。
- U1尚未收到消息,因为Internet断开
- 服务器通过心跳超时检测到U1断开连接
- U1重新连接到socket.io
- U1从不接收来自U2的消息-我猜它在步骤4中丢失了。
可能的解释
我想我明白为什么会这样:
- 第4步服务器杀死Socket实例和消息队列U1以及
- 此外,在步骤5 U1和服务器上创建新连接(不重用),因此,即使消息仍在排队中,仍然会丢失先前的连接。
需要帮忙
如何防止这种数据丢失?我必须使用心跳,因为我没有人永远挂在应用程序上。另外,我仍然必须提供重新连接的可能性,因为当我部署新版本的应用程序时,我希望停机时间为零。
PS我称之为“消息”的东西不仅是我可以存储在数据库中的文本消息,而且是有价值的系统消息,必须保证其传递或UI搞砸。
谢谢!
加法1
我已经有一个用户帐户系统。而且,我的应用程序已经很复杂。添加离线/在线状态将无济于事,因为我已经有了这种东西。问题不同。
签出第2步。从技术上讲,我们无法说出U1是否脱机,他只是失去了连接状态,说了2秒钟,这可能是因为互联网状况不佳。因此,U2向他发送了一条消息,但是U1没有收到该消息,因为互联网对他来说仍然不可用(步骤3)。需要步骤4来检测脱机用户,可以说超时为60秒。最终在另外10秒钟内,U1的互联网连接建立,他重新连接到socket.io。但是来自U2的消息在空间中丢失,因为服务器U1上的超时已将其断开连接。
那就是问题,我不会100%交货。
解
- 收集{}用户中的发射(发射名称和数据),由随机的emitID标识。发送发射
- 在客户端确认发射(将发射发送回带有emitID的服务器)
- 如果已确认-从{}中删除由emitID标识的对象
- 如果用户重新连接-为该用户检查{}并遍历该用户,则对{}中的每个对象执行步骤1
- 断开连接或/和/或连接时,如有必要,请向用户冲洗{}
// Server
const pendingEmits = {};
socket.on('reconnection', () => resendAllPendingLimits);
socket.on('confirm', (emitID) => { delete(pendingEmits[emitID]); });
// Client
socket.on('something', () => {
socket.emit('confirm', emitID);
});
解决方案2(种类)
添加2020年2月1日。
尽管这并不是Websockets的真正解决方案,但仍然有人可以使用。我们从Websockets迁移到SSE + Ajax。SSE允许您从客户端进行连接,以保持持久的TCP连接并实时接收来自服务器的消息。要将消息从客户端发送到服务器-只需使用Ajax。存在诸如延迟和开销之类的缺点,但是SSE由于是TCP连接,因此可以保证可靠性。
由于我们使用Express,因此我们将该库用于SSE https://github.com/dpskvn/express-sse,但是您可以选择适合您的库。
IE和大多数Edge版本不支持SSE,因此您需要使用polyfill:https : //github.com/Yaffle/EventSource。