使用 BOSH 时处理 JavaScript 中丢失的消息
我们最近对我们的旗舰产品进行了私人测试,并举办了一次小型发布活动。不幸的是,该场地的无线连接很糟糕,数据包从左、右、中心掉落,造成系统严重破坏,基本上根本无法工作!幸运的是,我们能够切换到不同的网络并挽救演示。这凸显了一些我知道已经是一个问题但还没有意识到它可能有多大问题的事情。我们的系统严重依赖 BOSH,并且拥有相当大的 JavaScript 代码库,现在在良好的网络条件下运行得相当好。然而,我们需要让它在恶劣的网络条件下也能正常工作。
由于 XMPP 的工作方式是即发即忘系统,因此很难判断您发送的消息或应该接收的消息实际上是否已发送或已接收。例如,我们有一个报价系统,一个用户将通过 BOSH 向另一个用户发送报价。当服务器收到此消息时,将向提供用户的 Offers_sent PEP 节点发布一条消息,并向接收用户的 Offers_received PEP 节点发布一条类似的消息。虽然发送用户能够(相对)轻松地判断他们的报价是否已发送,但如果从未收到发送给接收用户的通知,则该用户将永远不会知道自己错过了消息。
关于 JavaScript 设置,它有 4 个主要层:
- StropeJS
- 一个 MVC 框架,用于处理低级任务并构建在
- 应用程序层之上,其中包含应用程序逻辑路由、控制器模型等以及浏览器缓存模型数据
- 接收事件并向应用程序层发布事件并从应用程序层发布事件的 UI 层
解决消息丢失问题的一种方法是定期检查 PEP 节点是否有浏览器不知道的新数据。如果发现新消息,浏览器缓存将失效,并且将从服务器请求所有新数据。我不确定这是最好的方法,而且它也不能涵盖所有情况。我们当然不想陷入这样的情况:我们发送消息来确认前一条消息已在其目的地收到,因为这会使网络流量增加一倍。
随着实时网站的数量每天都在增长,这是其他开发人员一定遇到的问题,看看其他人如何解决这个问题将会很有趣。据我所知,有两种情况会导致消息丢失:
- 在连接不良的情况下,由于数据包被丢弃,消息无法发送或接收
- 涉及页面之间的导航,浏览器会收到消息,但未完全处理和存储页面卸载前保存在本地缓存中。或者一条消息被添加到发送队列中,但在页面卸载之前从未发送过。
我怀疑最难解决的问题将是第二个问题。对此主题的任何想法将不胜感激。
We recently went into private beta on our flagship product and had a small launch event. Unfortunately the venue had a terrible wireless connection and packets were being dropped left right and centre causing havoc with out system, basically it wasn't able to work at all! Luckily we were able to switch to a different network and rescue the demo. This highlighted something that I knew was already an issue but hadn't appreciated quite how much of an issue it could be. Our system relies heavily on BOSH and has a rather large JavaScript code base which now works rather well under good network conditions. However we need to make it work well under bad network conditions as well.
Due to the way that XMPP works, a fire and forget system, it's not easy to tell if a message you sent, or were supposed to receive, was actually sent or received. For instance, we have an offer system, one user will send an offer to another over BOSH. When this message is received by the server a message is published to the offering users offers_sent PEP node and a similar message to the receiving users offers_received PEP node. While the sending user is able to tell if their offer was send (relatively) easily, if the notification to the receiving user is never received that user will never know it missed a message.
A little about out JavaScript setup, it has 4 main layers:
- StropheJS
- An MVC framework for dealing with low level tasks and to build on top of
- An application layer which contains the app logic routes, controllers models etc. as well as a browser cache of the model data
- A UI layer that receives events and publishes events to and from the application layer
One way to solve the missing messages issue would be to periodically check the PEP nodes for new data that the browser doesn't know about. If a new message was discovered the browsers cache would be invalidated and all new data would be requested from the server. I'm not sure this is the best way to go and it also doesn't cover all situations. We certainly don't want to get into the situation where we are sending messages to confirm the previous message was received at it's destination as this would double the network traffic.
With the number of real time websites growing daily this is an issue that must have been encountered by other developers, it would be interesting to see how it's been solved by others. As far as I can see there are two situations in which messages go missing:
- On poor connections messages are not sent or received due to the packets being dropped
- Involving navigating between pages, a message is received by the browser but is not fully processed and stored in the local cache before the page is unloaded. Or a message is added to the send queue but never sent before the page is unloaded
I suspect the hardest issue to solve will be number 2. Any thoughts on the subject would be much appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
对此没有好的解决方案,但是有一个可行的解决方案。
BOSH 会话仅在给定时间内保持有效(在大多数实现中,默认情况下为 60 秒)。一旦会话过期,虚假的 c2s 连接就会关闭,用户必须重新登录。
当会话有效时,任何消息都不应丢失或乱序到达。唯一可能发生的丢失是在允许 HTTP 重新打开连接的 60 秒窗口期间,并且如上所述,如果该窗口关闭,则必须创建一个新会话。如果在该窗口内发出新的 HTTP 请求,则不会丢失任何内容或无序到达。
我建议,由于您使用 PEP 作为存储,因此每当创建会话时,客户端中都有一个钩子,您可以从 PEP 节点获取项目来初始化客户端缓存(请参阅 XEP-0060 第 6.5 节)。
如果您的 BOSH 客户端成功接收消息,但在成功处理消息之前网页已关闭或重新加载,消息仍然可能丢失。但是,对于其他情况,您不应再看到任何数据丢失,只会在启动期间由于项目检索而出现额外的延迟。
There's no good solution for this, however there is a workable solution.
BOSH sessions only remain valid for a given time (60 seconds, by default, in most implementations). Once the session expires the fake c2s connection is closed and the user has to log in again.
While the session is valid no messages should be lost or arrive out-of-order. The only potential for loss is during the sixty-second window allowed for HTTP to reopen a connection, and, as mentioned, if that window closes then a new session has to be created. If a new HTTP request is made within that window then nothing will be lost or arrive out-of-order.
I would suggest, since you're using PEP as your store, that you have a hook in the client whenever a session gets created you fetch items from your PEP nodes to initialize your client side cache (see section 6.5 of XEP-0060).
Messages can still be lost if they are successfully received by your BOSH client but the web page is closed or reloaded before they can be successfully processed. However, for other conditions you should no longer see any loss of data, only an additional lag during start up due to the item retrieval.
您应该使用 request &响应确认来解决此问题: http://xmpp.org/extensions/xep-0124.html #acks strope.js 作者提到他将在未来某个时候添加对此的支持。
You should be using request & response acknowledgements to solve this: http://xmpp.org/extensions/xep-0124.html#acks The strophe.js author has mentioned that he will be adding support for this some time in the future.