2
votes

Possibilité de mettre à jour les données en temps réel sur un client

J'ai le scénario suivant que je me demandais s'il est possible / faisable à mettre en œuvre. Je m'excuse si cela est considéré comme une question trop "large", mais je pense que SO serait le meilleur endroit pour la poser.

Supposons que j'ai un site Web et que je souhaite afficher un graphique à un utilisateur final. Pour les besoins de cet exemple, disons que nous voulons leur montrer "Ventes par catégorie" au cours de la dernière heure. Les données seraient affichées dans un graphique, et le SQL pour exécuter la requête pourrait être quelque chose comme ceci:

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

Pour autant que je sache, il existe deux façons générales pour mettre à jour les données de l'utilisateur final:

  1. Effectuez une sorte d'interrogation (ou une technique similaire) à un certain intervalle pour récupérer à nouveau les données de la requête. Cependant, cela peut devenir assez coûteux en fonction de la complexité / durée de la requête et du nombre de personnes connectées simultanément.
  2. La deuxième méthode consisterait à stocker toutes les données en mémoire et à pousser la mise à jour directement dans ce magasin de mémoire (qui pourrait être soit côté client, soit côté serveur, et nous pourrions envoyer une requête ws à l'utilisateur final chaque fois que il y a une mise à jour des données. Un exemple de ceci serait d'utiliser quelque chose comme https://github.com/jpmorganchase/perspective .

Ma question est alors de savoir s'il est possible de faire une mise à jour des données en temps réel (le cas que je décris dans l'exemple 2) lorsque les données sont trop volumineuses pour être stockées en mémoire. Je pense que la réponse est «non», mais il me manque peut-être des moyens de le faire. Par exemple, disons que j'ai 1 To de données stockées dans BigQuery et que je diffuse des mises à jour avec de nouveaux achats de produits - existe-t-il un moyen de transmettre les mises à jour au client final sans avoir à réexécuter la requête à chaque fois que je voulez obtenir une mise à jour? Y a-t-il d'autres technologies qui pourraient être utilisées / utiles pour ce scénario?

Encore une fois, je ne pense pas que ce soit possible, mais je voulais voir ce qui est possible pour un affichage en temps quasi réel pour un client final que possible sur un ensemble de données interrogé.


7 commentaires

Salut David542, peut-être que quelque chose comme Google PubSub pourrait fonctionner? C'est à dire. chaque fois qu'un nouveau produit est acheté, un "message" contenant des informations pertinentes sur l'achat est affiché via le client de publication de messages en parallèle à la base de données en cours de mise à jour. Les messages sont reçus via un abonné qui les traite et compile les informations des dernières heures (disons) de messages dans un format utile et présentable sur un graphique. Je ne sais rien des bases de données, FYI! Plus d'informations ici: cloud.google.com/pubsub/docs/overview


@Paul - d'accord, nous l'utilisons actuellement, mais ma question serait de savoir comment mettre à jour le graphique de l'utilisateur final avec?


Qu'en est-il de webpush - tools.ietf.org/html/draft-ietf- webpush-protocol-10 ? Vous pourriez avoir un déclencheur dans la base de données qui remplirait une table sur laquelle vous auriez un abonnement client, ce qui pousserait le changement au client.


@tukan comment cela fonctionnerait-il avec quelque chose comme bigquery ou une autre base de données exactement?


Qu'en est-il de Cloud Firestore? Vous utilisez déjà pub / sub. Vous pouvez donc créer une fonction cloud pour gérer le message de pub / sub afin de mettre à jour votre base de données Cloud Firestore.


Je pense qu'il y a un problème avec le graphique du client et ses exigences de conception ... les ventes par heure manquent d'informations et sont difficiles à mettre à jour. Les mises à jour doivent déduire les ventes (dates de péremption) et ajouter de nouvelles ventes ... Je considérerais un graphique de 24 heures, ou un graphique de 12 heures divisé par les heures réelles. Cela simplifiera les mises à jour et fournira des mesures plus utiles. Les mises à jour n'auront besoin que d'ajouter de nouvelles ventes (les données ne sont jamais périmées) et les informations sont plus exploitables.


La solution est la même solution de messagerie en temps réel en utilisant une base de données en temps réel? Ou est-ce que je manque quelque chose?


3 Réponses :


0
votes

Comme vous êtes intéressé par cette option, j'ai décidé d'étendre le commentaire à une réponse. Je prendrai le composant SQL Server et C # - sqltabledependency . Vous pouvez le vérifier s'il répond à vos besoins.

  1. Vous créeriez une table temporaire dans laquelle vous mettriez toutes les modifications de la table sales , par exemple sales_data_watch (vous pourriez avoir là aussi les agrégations de précalcul comme dans votre exemple).

  2. Vous créeriez une tâche horaire qui surveillerait les changements dans la table sales et effectuerait des insertions / mises à jour sur la sales_data_watch

    li >
  3. Vous auriez connecté la dépendance C # sqltabledependency connectée à sales_data_watch (note: tiré de l'exemple pour s'adapter à votre table)

    .NET Core 2
    SignalR Core
    EntityFramework Core
    EntityFramework Core for Sql Server
    SqlTableDependency
    
  4. Une fois que toutes les notifications ont été distribuées, vous pouvez faire tronquer la table sales_data_watch après (si vous ne voulez pas que la table devienne trop grande, ce qui ralentirait finalement l'ensemble du processus.

  5. / p>

Ceci n'utilise que le serveur SQL et le composant C #. Il existe d'autres options, probablement meilleures, par exemple: Détectez le changement de table d'enregistrement avec MVC, SignalR, jQuery et SqlTableDependency pour le faire différemment. Cela dépendra de vos préférences.

Modifier un exemple de lien complet pour Création de graphiques en temps réel avec Angular 5, Google Charts, SignalR Core, .NET Core 2, Entity Framework Core 2 et les dépendances SqlTable (ce lien est la première page sur trois). En haut de la page, vous pouvez voir le graphique en temps réel de Google. Tous les crédits vont à anthonygiretti . Vous pouvez télécharger l'exemple de projet à l'adresse github .

Technologies utilisées

Base de données

Sql Server, localDb avec Visual Studio 2017 est correct pour le faire fonctionner

Technologies frontales p >

Angular 5
Google Charts
Visual Studio Code
SignalR Client

Technologies BackEnd

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);
 }
}

La première consiste à installer les composants nécessaires - service broker, SQL Table, Angular-CLI, projet Angular 5, Client SignalR (VS 2017, .Net Core 2 SDK installé) - le lien est le même part1

Vient ensuite la configuration du backend - part2

Pour le faire fonctionner, ce projet contient:

  • Un DbContext (GaugesContext.cs) pour EntityFramework Core
  • Un concentrateur (GaugeHub.cs) pour SignalR qui diffuse des données
  • Un modèle contenant des données fortement typées à envoyer (Gauge.cs)
  • Un référentiel exposé avec Entity Framework et son interface (GaugeRepository.cs et IGaugeRepository.cs)
  • Un abonnement à une table sql de jauge avec SqlTableDependency et son interface (GaugeDatabaseSubscription.cs et IDatabaseSubscription)
  • Deux méthodes d'extension qui étendent IServiceCollection (AddDbContextFactory.cs) et IApplicationBuilder (UseSqlTableDependency.cs) Et Startup.cs et Program.cs

La dernière partie consiste à configurer le frontend - part3

Nous avons:

  • Un dossier contenant le composant de graphique de jauge (gaugeschart.component.html et gaugeschart.component.ts)
  • Un dossier contenant un service de graphique à jauge et un service de base Google Charts (google-gauges-chart.service.ts et google-charts.base.service.ts)
  • Un dossier contenant des fichiers d'environnement
  • Un dossier contenant un modèle fortement typé pour le graphique de jauge (gauge.ts)
  • Enfin, à la racine du dossier src, les composants et le module des fichiers par défaut (fichiers de composants d'application et fichier de module d'application)

À l'étape suivante, vous devriez le tester pour voir si les données sont correctement projetées dans les graphiques lorsque vous avez modifié les données.


2 commentaires

encore, il s'agit de détecter les changements "d'enregistrement", ce qui n'est pas le problème. Le problème serait que l'utilisateur regarde un graphique avec une requête SQL appliquée - toute modification «enregistrement» ne serait utile que dans la mesure où elle indique au client de «réexécuter la requête SQL», ce qui revient au scénario 1.


@ David542 sqltabledependency pousse les informations sur le client, sans qu'il soit nécessaire de les recharger. Ce serait à vous de le configurer correctement. J'ai essayé de créer un exemple de vitrine minimal où vous devrez choisir la notification poussée. J'inclus, en édition, un exemple complet, via des liens. Où vous pouvez voir la configuration complète d'un graphique en temps réel mis à jour lors de la modification des données.



1
votes

Si vos données sont uniques par client, en gros et en temps réel, il n'y a pas de salut à utiliser une base de données ou un cache comme échange. Vous devez envoyer la mise à jour des données directement.

Si vous ne pouvez pas envoyer directement les données au client à partir du processus effectuant la mise à jour de la base de données, vous pouvez probablement transmettre les données du processus effectuant la mise à jour au processus effectuant les push via un courtier de messages (j'utiliserai Rabbitmq à titre d'exemple).

La configuration optimale pour cette configuration est un modèle de sujet , où un sujet est un ID client ou une clé, et créer un écouteur par client connecté pour ce sujet - ou bien, un écouteur pour tous les clients, mais en enregistrant / désenregistrant les sujets de manière dynamique.

Demandez au gestionnaire websocket d'écouter le sujet de son client. Configurez le processus de mise à jour de la base de données pour diffuser également les mises à jour de l'ID de rubrique du client. Le courtier supprimera toutes les mises à jour qui ne seront pas envoyées à un client connecté, ce qui rendra la charge plus gérable dans la fin de l'auditeur.

Sans stockage ni interrogation, cette solution est à faible latence. Et même avec un millier de clients simultanés, je doute que le courtier n'épuise jamais la mémoire.


4 commentaires

merci pour cette réponse. Hmm ... qu'est-ce que ce qui précède accomplirait autre que pousser la "requête toutes les 5 secondes" du client au serveur? Dans tous les cas, vous interrogeriez toujours toutes les 5 secondes ...


@ David542 Interroger une fois toutes les 5 s par client est très différent de l'interroger une fois toutes les 5 s au total . Les solutions que je propose atteignent ce dernier.


non pas forcément. Dans tous les cas, nous ferions une demande à notre API, la somme de contrôle de la requête, et si c'est la même chose, nous renvoyons la requête en cache et sinon, nous interrogeons notre magasin de données et nous renvoyons les nouveaux résultats de la requête. Donc, dans ce sens, s'il y a 100 requêtes différentes parmi les clients (que ce soit 100 clients ou 10 000), une requête toutes les 5 secondes produirait 20 requêtes par seconde. Ou est-ce que je manque quelque chose dans votre réponse?


@ David542 Il manque à votre message d'origine, vos données sont uniques par client. J'ai supposé à partir de l'exemple de requête que ce n'était pas le cas. De toute évidence, je ne connais aucun moyen de générer 100 résultats uniques à partir de 100 ensembles de données uniques sans exécuter 100 requêtes uniques. Je vais réécrire la réponse avec des éléments plus pertinents.



0
votes

Je pense que la question pourrait être enracinée dans un problème avec le graphique du client et ses exigences de conception.

Un graphique "Ventes dans la dernière heure" manque à la fois d'informations et est difficile à mettre à jour.

Les mises à jour doivent déduire les ventes à mesure que la "dernière heure" progresse (13 h 05 passe à 13 h 06) et ajouter de nouvelles ventes.

En outre, les informations peuvent sembler intéressantes, mais elles fournissent très peu d'informations que le marketing peut utiliser pour améliorer les ventes (c'est-à-dire à quelles heures faut-il ajouter plus d'annonces).

Je considérerais un graphique de 24 heures ou un graphique de 12 heures divisé par les heures réelles.

Cela pourrait simplifier les mises à jour et fournirait probablement des métriques plus utiles.

De cette façon, les mises à jour du graphique sont toujours additives, donc aucun stockage de données en mémoire n'est requis (et les informations sont plus exploitables).

Par exemple, chaque nouvelle vente pourrait être publiée sur un canal "new_sale" . Les données de vente publiées peuvent inclure l'heure exacte.

Cela permettrait aux clients abonnés d'ajouter de nouvelles ventes à l'heure correcte du graphique sans jamais appeler un appel de base de données supplémentaire et sans avoir besoin d'un magasin de données en mémoire.


0 commentaires