Development

Journaux des communications

Ce système stocke tous les journaux de paires de requête / réponse qui ont été émises lors du traitement de tout message A2P SMS. Par Milan Mimica

December 11 2015

Scope

La plate-forme de messagerie Infobip traite environ 250M transactions par jour, ce qui représente 250M de messages SMS reçus par le client, facturés, acheminés, adaptés si nécessaire, soumis à un opérateur de télécommunications, rapport de remise traité et soumis au client. Voilà au moins 6 types de requêtes/réponses sur le réseau à l'aide de différentes API sur (parfois) 4 protocoles totalement différents juste pour traiter un seul message. Si tout va bien et qu’aucunes tentatives de relance ne sont pas nécessaires, c’est tout ce dont vous avez besoin. Et cela n’est que la communication externe - nous ne tenons pas en compte la communication inter-services. Par ailleurs, certains messages sont liés, et regarder les messages de façon individuelle ne donne pas une image complète.

Le défi de garder la trace de toutes les opérations de réseau est énorme. Notre département Support Technique doit résoudre les demandes à la fois du client et de l’opérateur et ce, rapidement. Les techniciens ont besoin d'un outil pour déterrer toutes les paires requête/réponse qui ont été émise lors du traitement d'un message. Savoir exactement ce qui a été présenté par le client et comment, exactement cela a été transmis à l'opérateur, est le point de départ de tout débogage ou résolution de problème.

Enregistrement distribué

Maintenant, "distribué" sonne bien. C’est un mot à la mode. D'une certaine manière nous voulons instinctivement que tout soit distribué. Mais regardons de plus près à quoi ressemble réellement un système d’enregistrements réparti.

Ce que nous avons ici est un service distinct pour chaque protocole de messagerie du côté du client et de l'opérateur. Chaque service gère ses propres journaux, les stocke dans la mémoire généralement, les rédige sur le disque dans un tampon circulaire. Depuis que les services sont développés par des équipes différentes, il faut un certain effort pour unifier l'apparence des interfaces web pour la gestion des journaux. Pour rendre la vie des techniciens du support un peu plus facile, les services exposent les journaux à travers leurs API et une interface d'administration centralisée est introduit où l'on peut regarder tous les journaux de tous les services. Faire que tous les services poussent les journaux à un système de stockage des journaux, comme Graylog est une étape vers l'unification - et la centralisation. Graylog est agréable (plaisant). Bien situé, il fait le travail. Il se trouve au sommet d'un pôle d’ elasticsearch. Enregistre un message du journal avec des métadonnées indexées valeur-clé. L'interface Web est un peu maladroite au début, mais on s'y habitue. Il y a également une certaine substance analytique à portée de main.

Le problème c’est que ces journaux ne rapportent pas. Les 6 paires requête/réponse sont totalement indépendantes les unes des autres. Il faut une analyse lourde, l'extraction manuelle des identifiants de corrélation de la base de données interne de la plateforme de traitement juste pour connecter plusieurs journaux de communication d'un message unique. Sans parler qu’il faut trouver les journaux de communication pour les messages connexes. En effet, le “côté client” est découplé du côté de l'opérateur. Ils ne partagent pas un identifiant unique de corrélation.

De plus, en ayant des limites bien définies entre les domaines d’application de service, les services du côté opérateur ne savent rien sur le côté client et vice-versa. Autrement dit, les services secondaires de l'opérateur ne savent pas de quel client vient le message traité. Cela s’appelle la séparation de préoccupation, et c’est généralement une bonne chose. Il ne fonctionne tout simplement pas bien pour l'enregistrement parce que les services côté opérateur ne peuvent pas enrichir les journaux avec des métadonnées de client qui aiderait à relier les journaux. En outre, ces services ne savent rien sur les relations de message - parce qu'ils ne doivent. Seule la plate-forme de traitement interne fait, mais il n'a pas de communication externe, par conséquent, il ne produit pas de journaux. Il signifie que nos journaux ne peuvent pas avoir toutes les métadonnées de relation associée avec eux.

Une façon de résoudre cela serait que les services produisent les journaux et les greffer sur la communication interne en direction de la plate-forme de traitement interne. La plate-forme peut alors enrichir les journaux avec toutes les métadonnées et les pousser sur un stockage de journaux. Cela fonctionne, mais ce n’est clairement pas la bonne chose à faire. Il faut de précieuses ressources de traitement et cela "distrait" la plate-forme à partir de ses tâches d'affaires.

Présentation UUID

Bien, il n’y a rien de révolutionnaire. Nous avons pensé que chaque message a besoin d'un identifiant unique - UUID (identificateur unique universel) associé au tout début, quand il entre dans le système, et nous devons adopter cet ID avec le message au service suivant dans la chaîne de traitement. Ensuite, chaque service produisant les journaux peuvent joindre cet ID au journal des métadonnées. Maintenant c’est facile! Nous pouvons porter un tas d'enregistrements de journal à un seul message. Si seulement...

Couplage des rapports de livraison

Cela ne prend pas longtemps pour réaliser que vous avez un problème. Tout ce qu'il faut c’est regarder dans les journaux si il y a une notification que les rapports de livraison sont manquants. Encore une fois, le problème est dans la séparation des préoccupations, mais nous sommes toujours d'accord que cette séparation est une bonne chose. Les services qui manipulent un protocole spécifique peuvent soumettre un message qu'ils ont reçu de la plate-forme et gérer un rapport de livraison. Le couplage d'un rapport de livraison à un message est un travail plus complexe que l'on ne se l’imagine. Et c’est clairement la préoccupation de la plate-forme. Pourtant, nous voulons que le service qui reçoit le rapport de remise produise un enregistrement de journal. Au moment de la réception de la livraison nous ne savons toujours pas à quel message, il sera couplé (si il va être couplé tout court!) car le service ne sait pas quelle UUID attacher le journal.

Connexion des messages liés

Comme nous l’avons vu précédemment, certains messages sont liés. Typiquement, ce sont des messages SMS longs qui sont transférés individuellement, mais traités et éventuellement affichés sur le téléphone portable en un seul message. Parfois, le fractionnement et la fusion sont impliqués, nous avons donc one-to-many, many-to-one, et many-to-many relations. Ce serait bien d'avoir aussi des journaux pour ces messages liés parce que parfois nous avons besoin de regarder tous ces messages en un seul. Le problème est que seule la plate-forme de traitement interne est consciente de la relation entre les messages, et c’est là que le fractionnement et la fusion interviennent. Les services gérant la communication interne ne savent rien sur les relations. Ils gérer les messages individuellement et chaque message a son propre UUID.

Une autre source de relations est le traitement en masse. Le client peut tout simplement présenter plusieurs messages dans une requête HTTP. Le service gérant la manipulation HTTP va analyser la demande et transmettre plusieurs messages dans la plate-forme, mais il faudra connecter une seule demande et une seule réponse. Il va générer un UUID pour connecter la requête HTTP et un nouvel UUID pour chaque message généré par cette demande.

Les graphiques viennent à la rescousse

Il est clair que nous avons besoin de stocker les relations entre les UUID quelque part. Nous devons être en mesure d'aller chercher tous les journaux associés lors de la requête pour les journaux d'un seul message. Essayons de visualiser une relation plus complexe, mais pas si rare. Nous avons une demande du client (UUID-100) contenant deux longs messages (UUID-200 et UUID-210) qui ont ensuite été divisés en plusieurs messages et soumis à l'opérateur (UUID-201, UUID-202, UUID-211, UUID-212). Puis, une livraison en masse est arrivée, contenant des rapports de livraison pour toutes les parties de message demandées (UUID-300).

Sans surprise, c’est un graphique. Bien sûr, on pourrait investir un peu d'effort et le stocker dans une base de données relationnelle, ou le transformer en un JSON pour une base de données de documents, mais nous avons les bases de données graphiques de nos jours. Nous allons utiliser le bon outil pour le travail! Partout où de nouvelles relations se passent et de la division ou de la fusion se produit, nous poussons un petit graphique à une base de données graphique. Nous avons choisi Neo4j parce qu'il a un super marketing - ils sont sympas lors des conférences, donnent des livres et des t-shirts gratuits. Le logiciel n’est pas mal non plus. Vous devez payer pour le regroupement et la HA (Disponibilité élevée), mais pour les journaux, même la version gratuite fonctionne. Seule l’instance Neo4j sur une machine 16 CPU prend soin de 100M de nœuds avec 150M relations qui prennent juste 15 Go de stockage. Le problème avec Neo4j ici c’est que la suppression de nœuds ne libère pas de la mémoire ou de l'utilisation du disque, vous devez donc purger les données de temps en temps.

Maintenant, quand nous avons besoin d'aller chercher les journaux d'un message, nous prenons cet UUID du message, récupérons tous les UUID associés à partir de Neo4j et ensuite récupérons les journaux de Graylog par ces UUID. Il est important de chercher seulement les UUID pertinents, pas tout le graphique. Par exemple, si nous voulons les journaux de communication pour le message UUID-200, nous avons seulement besoin d'aller chercher les enregistrements du journal UUID-100, UUID-200, UUID-201, UUID-202 et UUID-300. La branche UUID-21x est hors de propos. L'astuce consiste à utiliser différents types de relation lors de la connexion au message en masse et lors de la connexion des parties de message. Ensuite, une requête simple à cypher Neo4j est utilisée pour extraire les UUID associés.

Le résultat est que chaque service pousse ses propres journaux de communication qu'il gère. En outre, selon la partie du système créé une nouvelle relation est responsable de la publication de cette information. Les préoccupations sont bien séparées, les journaux et les relations sont stockés sur des systèmes dédiés où ils peuvent éventuellement être récupérés. (Par Milan Mimica, Ingénieur en informatique / Chef d’équipe)