可以在客户端上实时更新数据

时间:2019-04-18 04:20:16

标签: websocket google-cloud-platform google-bigquery analytics real-time

我有以下情况,我想知道是否有可能/可行。如果这是一个过于笼统的问题,我深表歉意,但我认为SO是问这个问题的最佳场所。

让我们假设我有一个网站,并且想向最终用户显示图表。就本示例而言,假设我们要在过去一个小时中向他们显示“每个类别的销售额”。数据将显示在图形中,运行查询的SQL可能是这样的:

SELECT SUM(revenue) FROM sales 
WHERE timestamp > NOW() - INTERVAL 1 HOUR
GROUP BY category

据我所知,有两种一般方法可以为最终用户更新数据:

  1. 以一定的间隔进行某种轮询(或类似的技术)以从查询中重新获取数据。但是,这可能会变得非常昂贵,具体取决于查询的复杂性/持续时间以及同时连接的人数。
  2. 第二种方法是将所有数据存储在内存中,并将更新直接推送到该内存存储(可以是客户端或服务器端,并且我们可以在任何时候向最终用户发送一个ws请求)有数据更新,例如使用https://github.com/jpmorganchase/perspective之类的数据。

然后我的问题是,当数据太大而无法存储在内存中时,是否可以完全进行实时数据更新(我在示例2中描述的情况)。我认为答案是“否”,但也许我缺少一些实现此目的的方法。例如,假设我在BigQuery中存储了1TB的数据,并且正在通过购买新产品流式传输更新-是否有一种方法可以将更新推送到最终客户,而不必每次我都重新运行查询想获得更新?在这种情况下还可以使用其他有用的技术吗?

同样,我认为这是不可能的,但我想看看在查询的数据集上尽可能向终端客户近实时显示的可能性。

3 个答案:

答案 0 :(得分:0)

由于您对此选项感兴趣,因此我决定将注释扩展为答案。我将使用 SQL Server C#组合-sqltabledependency。您可以检查出它是否符合您的需求。

  1. 您将创建一个临时表,您可以在其中放置sales表中的所有更改,例如sales_data_watch(您也可以像示例中那样进行预计算聚合)。

  2. 您将创建一个每小时的工作,该工作将监视sales表中的更改并在sales_data_watch

  3. 上执行插入/更新
  4. 您将已经连接了连接到sales_data_watch的C#sqltabledependency(注意:摘自该示例以适合您的表)

    public class SaleData
    {
       public int revenue{ get; set; }
    }
    
    public class Program
    {
     private static string _con = "data source=.; initial catalog=MyDB; integrated security=True";
    
     public static void Main()
     {
      // The mapper object is used to map model properties 
      // that do not have a corresponding table column name.
      // In case all properties of your model have same name 
      // of table columns, you can avoid to use the mapper.
      var mapper = new ModelToTableMapper<SaleData>();
      mapper.AddMapping(s => s.revenue, "Aggregated revenue");
    
      // Here - as second parameter - we pass table name: 
      // this is necessary only if the model name is different from table name 
      // (in our case we have Sale vs Sales). 
      // If needed, you can also specifiy schema name.
      using (var dep = new SqlTableDependency<SaleData>(_con, "sales_data_watch", mapper: mapper));
      {
       dep.OnChanged += Changed;
       dep.Start();
    
       Console.WriteLine("Press a key to exit");
       Console.ReadKey();
    
       dep.Stop();
      } 
     }
    
     public static void Changed(object sender, RecordChangedEventArgs<SaleData> e)
     {
      var changedEntity = e.Entity;
    
      Console.WriteLine("DML operation: " + e.ChangeType);
      Console.WriteLine("Revenue: " + changedEntity.Revenue);
     }
    }
    
  5. 在分发所有通知之后,您可以在truncate table sales_data_watch之后执行(如果您不希望表过大,这最终会减慢整个过程。

这仅使用SQL Server和C#组件。还有其他可能更好的选择,例如:Detect record table change with MVC, SignalR, jQuery and SqlTableDependency以不同的方式进行。这将取决于您的偏好。

编辑Building real time charts with Angular 5, Google Charts, SignalR Core, .NET Core 2, Entity Framework Core 2 and SqlTable dependency的完整示例链接(此链接为第一页,共3页)。在页面顶部,您可以看到实时Google的gaugeschart。所有学分都归anthonygiretti。您可以从github下载示例项目。

使用的技术

数据库

Sql Server,带有Visual Studio 2017的localDb是正确的使其能够正常工作

前端技术

Angular 5
Google Charts
Visual Studio Code
SignalR Client

后端技术

.NET Core 2
SignalR Core
EntityFramework Core
EntityFramework Core for Sql Server
SqlTableDependency

首先是安装所需的组件-服务代理,SQL Table,Angular-CLI,Angular 5项目,SignalR客户端(VS 2017,已安装.Net Core 2 SDK)-链接相同part1

接下来是后端设置-part2

为使其正常运行,该项目包含:

  • 用于EntityFramework Core的DbContext(GaugesContext.cs)
  • 用于SignalR的集线器(GaugeHub.cs),用于广播数据
  • 包含要发送的强类型数据(Gauge.cs)的模型
  • 使用实体框架及其接口(GaugeRepository.cs和IGaugeRepository.cs)公开的存储库
  • 具有SqlTableDependency及其接口(GaugeDatabaseSubscription.cs和IDatabaseSubscription)的量表sql表的订阅
  • 两个扩展方法,用于扩展IServiceCollection(AddDbContextFactory.cs)和IApplicationBuilder(UseSqlTableDependency.cs) 还有Startup.cs和Program.cs

最后一部分是设置前端-part3

我们有:

  • 一个包含量表图表组件(gaugeschart.component.html和gaugeschart.component.ts)的文件夹
  • 包含仪表盘图表服务和Google Charts基本服务(google-gauges-chart.service.ts和google-charts.base.service.ts)的文件夹
  • 包含环境文件的文件夹
  • 一个包含规格表(gauge.ts)的强类型模型的文件夹
  • 最后,在src文件夹的根目录下,默认文件组件和模块(应用程序组件文件和应用程序模块文件)

下一步,您应该对其进行测试,以查看更改数据后数据是否正确投影到图形中。

答案 1 :(得分:0)

如果每个客户端的数据都是唯一的,并且实时变化很大,那么使用任何数据库或缓存作为交换都不会有任何挽救。您必须直接发送数据更新。

如果您不能直接从执行数据库更新的过程中将数据推送到客户端,则可以通过消息代理将进行更新的过程中的数据传递到进行推送的过程中(我将使用Rabbitmq例如)。

此设置的最佳配置是topic model,其中的主题是客户端ID或密钥,并为该主题的每个连接的客户端创建一个侦听器-或者,为所有客户端使用一个侦听器,但注册/注销动态主题。

让websocket处理程序收听其客户端的主题。设置更新数据库的过程,以同时将更新流式传输到客户端的主题ID。代理将丢弃所有不发送给已连接客户端的更新,从而使侦听器端的负载更易于管理。

没有任何存储或轮询,此解决方案的延迟很短。而且即使有1000个并发客户,我也怀疑经纪人是否会耗尽内存。

答案 2 :(得分:0)

我认为问题可能源于客户图表及其设计要求。

“过去一小时的销售”图表既缺乏信息,又难以更新。

随着“最新时间”的进行(从下午1:05变为下午1:06),更新需要扣除销售,并增加新的销售。

此外,这些信息可能看起来很令人兴奋,但是它提供的信息很少,营销可以用来提高销售(即应在何时添加更多广告)。

我会考虑使用24小时图表或12小时图表除以实际小时数。

这可以简化更新,并可能提供更多有用的指标。​​

这样,对图的更新始终是累加的,因此不需要内存中的数据存储(并且该信息更具可操作性)。

例如,每笔新交易都可以发布到"new_sale"频道。已发布的销售数据可能包括确切的时间。

这将允许订阅的客户将新销售额添加到图中的正确时间,而无需调用额外的数据库调用,也不需要内存中的数据存储。