La donnée est aujourd’hui un moteur de croissance pour beaucoup d’entreprises.

Si collecter de la donnée est devenu quelque chose de naturel, des problématiques se posent au moment d’effectuer un traitement pertinent sur celles-ci.

Quel workflow adopter ? Quels outils ? Comment imbriquer cela à une architecture existante ? Comment les agréger ?

Ces questions peuvent sembler généralistes, mais la réalité démontre que chaque projet a sa spécificité et qu’il n’existe pas une réponse « toute faite » à mettre en place, même si les apparences peuvent le laisser croire.

Chez Poool, l’analyse de la donnée est une priorité car elle est au cœur de notre savoir-faire et de notre métier.

Savoir détecter les comportements et proposer la meilleure solution pour engager et monétiser un visiteur sur un site média passe par un workflow pertinent et scalable. Trouver des solutions adéquates a été une préoccupation importante ainsi qu’un sujet à approfondir pour ne pas laisser cet aspect au hasard. Le but est in fine de gagner en pertinence et en performance.

L’objectif de cet article n’est pas de dire qu’une solution est meilleure qu’une autre, mais plutôt de partager un retour d’experience.

« On utilise Redash ? »

Chose à retenir : Redash fonctionne bien et est simple à installer avec Docker.

Le soft permet d’exploiter des données qui proviennent de plusieurs sources différentes et d’en faire des dashboards en trois clics.

Mauvais côté : il s’agit de requêtes MongoDB (dans notre cas) et selon le volume à traiter, les performances peuvent largement diminuer.

Nous nous en servons temporairement pour des requêtes basiques, car nous sommes passés d’une architecture standard à une architecture en shards, et il n’est plus possible d’utiliser des aggregations.

« Bon, ben on fait des requêtes avec Python et Pymongo, non ? »

Naturellement, par facilité et simplicité, faire un script Python « qui va bien » avec différentes méthodes et un KPI par méthode nous a — naïvement — paru être la solution la plus simple.

Alors certes, c’est effectivement la plus simple, mais pas la plus efficace en terme de temps de traitement. Sur 100k entrées, nous avions des performances correctes, sur 1M, cela devenait plus compliqué.

Au moment de croiser une table de 15M d’entrées et une autre de 5M, ça a explosé (nous arrivions à un temps de traitement de 30 minutes). À partir de là, tout devient exponentiel, même en utilisant des libs bas niveau (type Monary), le temps de traitement ne faisait qu’augmenter.

Nous n’aurions pas eu de souci pour un rapport hebdomadaire ou mensuel, mais, dans notre cas, il s’agit d’être réactif sur les activités en cours. Nous devions donc trouver une solution différente, et garder cette option en back-up.

« ElasticSearch, ça a l’air cool »

Solr, Elasticsearch , Hadoop… Des solutions différentes mais avec un but commun : faciliter le traitement de gros volumes de données.

Même si à l’instant ’T’ nous n’entrions pas dans la case ‘Big Data’ (ni medium data, d’ailleurs), force était de constater que nous allions y arriver. Première approche : collecter une copie de la base de production et la synchroniser en local avec ElasticSearch grâce à un connecteur.

« Mongo-connector, c’est génial ! »

Après avoir fouillé pour trouver une solution, nous sommes rapidement tombés sur un outil bien conçu, Mongo-connector.

Le but de cet outil est d’avoir un « all in one » qui fait le pont entre une base MongoDB et ElasticSearch, Solr ou une autre base Mongo. Premier test concluant, premier index ES rempli des données de production.

Mongo-connector faisait le job et les requêtes étaient extrêmement rapides. Nous découvrions au passage Kibana.

« Vous avez dit scalable ? »

À ce moment précis, nous étions sur un volume raisonnable, l’index mettait à peu près 2 heures à se construire et l’idée de faire tourner cela avec un CRON la nuit semblait plutôt cool.

Seulement, après une nouvelle étape de notre déploiement et un changement d’architecture, le volume de données s’est accentué de manière notable et le mongo-restore demandait plus de paramètres qu’auparavant pour ne pas planter lamentablement à 90%. Après avoir un peu travaillé là-dessus et relancé la synchro avec mongo-connector, le comportement de ce dernier est devenu … aléatoire. Aléatoire au sens : j’indexe l’ensemble des données dans ElasticSearch, par contre je supprime tout une fois que c’est terminé. Oui, cela n’a aucun sens. Aucun cas similaire, des issues ouvertes sur Github sans réponse… Si vous avez déjà été confrontés à ce genre de situation, vous savez à quel point cela sent « mauvais » .

Pour finir, nous avons essayé de le brancher directement sur le serveur de production. Deux problèmes à cela : la potentielle montée en charge que cela peut causer, et un problème de compatibilité entre notre architecture et la manière dont fonctionne mongo-connector.

Nous ne sommes pas allés voir plus loin.

« Bon, ok, c’est sûrement pas adapté. Et Logstash ? »

Étape suivante, essayer Logstash. L’outil avait l’air vraiment cool, et pouvait, a priori, répondre à la problématique à laquelle nous étions confrontés.

Le soft permet de récupérer, parser et conserver des données pour une analyse a posteriori. Le fonctionnement peut rester simple, avec un fichier de configuration précisant “l’input” (d’où viennent les données) et “l’output” (où elles vont en sortie).

Il fallait donc trouver un “input plugin” pour MongoDB, ce format d’entrée n’étant pas géré nativement par Logstash. Le plus utilisé n’était plus maintenu depuis 11 mois, nous partions sur de bonnes bases.

Après plusieurs recherches, nous avons réussi à le faire fonctionner, à un détail près : impossible d’identifier à quelle collection (équivalent d’une table en SQL) appartenait une entrée d’un index, à cause d’une spécificité de traitement coté plugin.

Beaucoup d’essais, un peu d’acharnement, pas de résultat concluant à 100%. Nous aurions pu nous en contenter mais vu l’importance du sujet, nous voulions essayer de faire les choses correctement.

« Ok, c’est bon, j’ai un truc.”

Si vous êtes un développeur, vous devriez connaître la théorie du canard en plastique. Le principe est de parler à un tiers à voix haute pour que la solution apparaisse de manière évidente.

C’est donc en discutant qu’un élément important nous est apparu : nous n’étions peut-être pas sur la bonne approche. La logique dominante était de brancher une solution X sur une infrastructure existante. En réalité, ne fallait-il pas revoir l’infrastructure ?

C’est à ce moment-là, et après avoir épluché beaucoup de documentation que nous sommes tombés sur ce schéma :

L’infrastructure est complexe, mais la logique est simple : envoyer les données dans deux endroits différents, en même temps.

La mise en place n’a pas été extrêmement coûteuse et nous permet d’atteindre les objectifs de performance que nous nous étions fixés.

Chaque approche est possible

L’ensemble des méthodes que nous avions expérimentées auraient pu fonctionner : nous aurions pu mettre le script Python sur plusieurs threads, éventuellement distribuer la charge via un rabbitMQ… La réalité est que nous voulions éviter de rentrer dans un cadre trop spécifique.

Rester générique dans la méthode permet deux choses : ne pas partir dans une solution trop complexe à maintenir et à prendre en main pour l’équipe existante et à venir.

C’est aussi une garantie pour nos clients de savoir que nous utilisons des méthodes éprouvées et viables. Sur un sujet aussi clé que la data, nous ne voulions pas nous reposer sur un “bricolage”.

Et vous, quelle est votre approche ?