【问题标题】:Building a SignalR / Knockout dashboard with guaranteed messaging构建具有保证消息传递的 SignalR/Knockout 仪表板
【发布时间】:2015-05-17 23:42:54
【问题描述】:

我正在考虑使用实时消息替换我们公司的监控仪表板。

旧概念:

在我们公司,我们有一个仪表板,可以显示 700 多台物理机的(相当详细的)状态,以及添加的元信息。它是大约 1.5 年前由我的一位同事在 ASP.NET Web 窗体(我不喜欢)中构建的,以使调度员能够协调我们的技术人员应该去哪里解决问题(机器位于不同的地理位置)。

不幸的是,该应用程序使用 30 秒的完整页面自动刷新,并在其后进行大查询。它很慢,并且完全重置了您的视图(正如我所说,仪表板包含超过 700 台机器)。我个人想改变这一点。使用起来非常烦人。我们的调度员已经学会忍受这种情况,但我认为他们应该得到更好的待遇。

新概念:

我想在新仪表板上显示相同的内容,但需要实时更新和“消息”日志。在我们公司,我们大约 90% 的工作是在 MS 堆栈上工作,所以我计划使用 ASP.NET MVC、SignalR、SQL Server 和 Knockout。

我目前拥有的

看看这个简单的图表:

 +----+ +----+ +----+ +----+ +----+ +----+ +----+            
 | PC | | PC | | PC | | PC | | PC | | PC | | PC | ... ...    
 +--+-+ +--+-+ +-+--+ +--+-+ +--+-+ +--+-+ +--+-+            
    |      |     |       |      |      |      |              
    |   +--+  +--+  +----+    <-+    <-+    <-+              
    |   |     |     |                                        
+---v---v-----v-----v+         +-----------------------+     
|                    | TCP/IP  |                       |     
| Monitoring Backend +--------->  Data Enrichment App  |     
|                    |         |                       |     
+--------------------+         +---------+-------------+     
                                         |                   
          +------------------------------+        +---------+
          |                                       |         |
          |                +----------------+     |         |
    +-----v-----+---------->    DB Proxy    +----->  S Q L  |
    |           | PUB/SUB  +----------------+     |         |
    |   Redis   |                                 |         |
    |           |          +----------------+     +---------+
    +-----------+          |     TO BE...   |                
                           +----------------+                
  • 我创建了一个小的“数据丰富应用程序”,它通过 TCP/IP 从监控后端接收事件并向事件添加额外的业务数据(例如,设备的位置、主机名旁边的描述性名称、人- 警报的可读翻译等)不包含在监控系统中。
  • 丰富的事件从应用程序发送到 Redis。我这样做是为了让其他应用程序能够以订阅者的身份连接到 Redis,因为我在这里输出的数据比监控后端发送的数据更出色且更具可读性。
  • 目前唯一的 PUB/SUB-ing 到 Redis 是一个 DB 代理,它监听传入事件并将这些事件发送到数据库 (SQL Server),我已经将其用于历史报告目的,但目前只包含相当简单的数据.

这里的想法是在我的 ASP.NET 应用程序中将 SignalR Hub 订阅到 Redis 后端,以将事件发送到客户端。 (那是 TO BE 部分)

问题:

这个想法是,当客户端导航到仪表板 URL 时,初始概览由 SQL 后端中的状态数据填充。之后,通过 SignalR 接收事件,并通过更改 Knockout 属性来更新视图。

但是,如果客户断开连接(例如,在从一个会议室走到另一个会议室时睡着笔记本电脑),他会错过来自 SignalR 集线器的消息,并且他的仪表板视图不再正确!

可能的解决方案是:

  1. 在每次事件更改时通过 SignalR 发送每个设备的完整状态:这是不可能的,因为我必须通过网络发送大量数据。 (我猜至少有 12,000 条 JSON 数据记录)

  2. 检测到超时连接后强制完全刷新:我不知道如何使用 SignalR 来实现这一点:(

  3. ... ?

处理基于推送的实时数据和保证数据到达的推荐方法是什么?或者我将如何处理从超时连接中恢复?还是让这个实时变得疯狂?

免责声明:我是系统工程师,而不是专业程序员。这是我的第一个实时网络应用程序。关于 SignalR 的其他问题通常不会像这样处理大量数据。

【问题讨论】:

  • 最近看到的最好的 ASCII 图片。
  • 实现一个简单的机制,使您可以确定是否丢失了消息(例如,在每条消息中发送一个消息号。如果上一条消息和当前消息之间的差异更大比 1 你会知道你错过了一些消息)。如果有消息丢失,请刷新页面。
  • @Pawel 你的意思是实现一个(方轮)消息队列?
  • @Aron - 不。我正在考虑对 SignalR 消息进行编号,以便您可以检测到您错过了一条消息,在这种情况下,您将使用不同的方式(例如 HTTP 请求)获取内容。
  • @Pawel 它是一种被称为消息队列的编程模式的幼稚实现。它是一个东西,查一下。

标签: c# asp.net knockout.js signalr real-time


【解决方案1】:

spender 的回答很好,但我想在 SignalR 的上下文中解决解决方案 2;您可以为此使用 SignalR 生命周期事件:OnConnectedOnReconnectedOnDisconnected。你可以阅读更多about the events here 以及如何use them in a hub here

当客户端首次连接(调用 OnConnected)时,您将完全初始化视图。如果客户端暂时断开连接(默认少于 30 秒,请参阅relevant settings hereOnReconnected 被调用),您无需执行任何其他操作;只要标准排队机制中有足够的空间,排队的消息就会被传递。

如果客户端 PC 进入睡眠状态,OnDisconnected 最终会被调用,客户端必须建立新连接。那时,最简单的实现就是再次加载所有数据。如果你想重用客户端已经拥有的(过时的)数据,那么你需要

  • 一种检索数据/消息子集的方法(例如,基于序列号或时间戳;由于您已经将事件流存储到数据库,听起来应该可以集成它)李>
  • 在客户端收到消息时将此号码存储在客户端上
  • 在建立连接时将其发送到服务器(例如通过query string),以便服务器可以在OnConnected 中读取它并知道是初始化完整视图还是仅初始化变更集

使用 SignalR 消息进行实时更新应该没问题,但是我建议使用常规 MVC / WebAPI 控制器来提供初始化视图所需的完整数据集(来自OnConnected)。

也就是说,如果您想要保证送达,您必须确认您的消息,并且可能还需要实施排队机制。 SignalR 默认只缓冲大约 1000 条消息,然后开始丢弃它们。您可以增加该值,但根据您的要求构建一个可能更有意义。

【讨论】:

  • 感谢 Lars,这是一些有用的信息。我实际上不知道 OnReconnected。将此标记为答案,因为您停留在 SignalR 的上下文中。
【解决方案2】:

SignalR 不是为“可靠消息传递”而设计的。它是为“实时通信”而设计的。

问题在于可靠性实际上与实时不兼容。可靠的消息传递意味着消息将至少传递一次。但是,如果数据链路断开,则消息将延迟传递。然而,实时意味着消息“立即”传递,而不是半小时后。

如果您需要可靠性,我会切换到“消息队列”。您应该会发现它们对于您的目的来说“足够快”(RTC 通常意味着您需要毫秒范围内的延迟,而 MQ 应该提供秒范围内的典型延迟)。

您的问题是,如何通过 SignalR 实现消息队列。

试试 RabbitMQ,我只听说过它的优点。还有一个 Javascript 客户端。

【讨论】:

  • 是的,我相信您对我的问题的措辞更好。实际上,我当时正在考虑使用 RabbitMQ(Redis 主要在那里,因为我正在尝试构建 MS 保存在其 GitHub 存储库中)。但我不确定这是否是一个好主意,所以尽管使用直接 JS 客户端到 MQ。 JS 客户端如何处理消息队列的处理?它什么时候决定我实际上是在处置?
【解决方案3】:

所以,我认为这个问题有点过于宽泛且没有重点,但我想说的比评论还多。

为了简单起见,我不会使用 websocket 来传递消息本身,而只是作为通知通道让客户知道有更多数据可用。

首先,我将专注于通过标准 HTTP 通过 JSON 请求一组有限消息的方法。我假设所有消息都有某种序列号或时间戳,因此已经有带有标记n 的消息的客户端将需要能够请求带有标记&gt;n 的所有消息。我们称之为消息服务。

现在连接 websocket 并使用它向客户端传达简单的“更多可用数据”事件。每次客户端接收到事件时,都向消息服务发出新的请求,以获取所有标记 > 的消息,而不是客户端拥有的最新消息。

如果 websocket 断开连接,当它重新连接时,向消息服务发出单独的请求以确保同步,然后再次等待事件,如上所述。

【讨论】:

  • 您对我的问题的质量是正确的。我认为 Aron 的措辞“如何通过 SignalR 实现消息队列”更好。无论如何,感谢您提供有用的信息,这很有意义。不过,我仍然不确定如何实施一种跟踪每个客户可用信息的方法。
猜你喜欢
  • 2014-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-06
  • 1970-01-01
  • 2018-09-05
  • 1970-01-01
相关资源
最近更新 更多