Mais c’est quoi Apache Kafka ?

0

Apache Kafka est sorti de l’incubateur Apache en 2012. Au fil de ces dernières années, son écosystème s’est beaucoup étoffé et avec lui l’ensemble des cas d’usages pour lesquels Kafka est approprié. Nous avons maintenant une technologie mature, prête à être utilisée non plus seulement sur des projets estampillés « big data », mais sur n’importe quel projet où les données sont cruciales, c’est-à-dire, à mon avis, 100% de l’informatique de gestion.

Au lendemain de l’annonce de KSQL (SQL pour Kafka) et à la veille de la sortie de Kafka 1.0, c’est le moment opportun pour réexaminer ce que cette technologie peut nous apporter.

Un bus de messages

Beaucoup ont en tête que Kafka est un concurrent de RabbitMQ, et que c’est un bus de messages ou message broker. C’est bien l’intention qu’avaient ses concepteurs à sa création chez LinkedIn : un broker très performant (millions de messages par seconde) et très résilient (distribué avec réplication). Cependant, ces contraintes ont sculpté Kafka d’une façon tout à fait unique pour un broker. Kafka est plus simple et plus versatile. Au fait, c’est codé en Scala et en Java.

Une base de données bas niveau

En son cœur, Kafka est un système de stockage de flux de messages (streams of records). Un message est composé d’une valeur, d’une clé (optionnelle, on y reviendra), et d’un timestamp. Kafka organise les messages en catégories appelées topics, concrètement des séquences ordonnées et nommées de messages. Les topics ne sont pas modifiables à l’exception de l’ajout de messages à la fin (à la suite du message le plus récent). Un client Kafka ne peut pas modifier ou supprimer un message, ne peut pas modifier l’ordre des messages ou insérer un message dans un topic ailleurs qu’à la fin. Il ne peut pas non plus créer ou supprimer un topic. Un émetteur ajoute des messages à la fin des topics de son choix, c’est tout.

De son côté, le consommateur lit des topics à partir d’un index ou d’un timestamp donné, toujours dans l’ordre, c’est-à-dire du plus ancien message au plus récent, et sans s’arrêter. Si un consommateur a traité tous les messages d’un topic, il y reste connecté pour recevoir les nouveaux messages insérés par les émetteurs. Bien qu’on parle de consommation d’un message, il s’agit d’une simple lecture qui n’entraîne pas la suppression du message. Comme les topics sont immuables, ils peuvent être lus simultanément par de multiples consommateurs. Chacun d’eux en est à un index différent et lit à une vitesse différente.Schéma d'un topic avec position de l'émetteur et de deux consommateurs

Tout système de gestion de base de données possède un journal des demandes de modification qui lui sont adressées (pour faire de la réplication, de la construction d’index ou de vues matérialisées). Simplement, Kafka fait de ce type de journal son concept central, alors que les autres SGBD ajoutent des couches d’abstraction par dessus (tables, documents, graphes…). C’est l’absence de ces couches qui rend Kafka simple, flexible et performant. Kafka est une base de données bas niveau.

Un framework de stream processing

L’aspect bas niveau a un avantage : il laisse la liberté aux développeurs d’application de créer leurs propres abstractions. Mais il a aussi un inconvénient : il force les développeurs d’application à créer leurs propres abstractions. Par ailleurs, créer des abstractions distribuées et résilientes est difficile. C’est là que les récentes additions à Kafka entrent en jeu : Kafka Streams et Kafka Connect.

Kafka Streams

Kafka Streams est une librairie Java qui expose des API pour développer des unités de traitement de messages au fil de l’eau (streaming). Elle s’occupe de gérer la consommation et l’émission de messages, de gestion de la concurrence,  etc. laissant au développeur uniquement (ou presque) le code de transformation à écrire. C’est aussi vraiment simple à déployer : on compile un JAR exécutable tout à fait ordinaire et on le lance. On peut aussi intégrer le code dans une application Java existante. Si on veut scaler horizontalement, on lance plusieurs instances.

Quand on lit un topic Kafka avec Streams, on a le choix entre les deux abstractions stream et table. Dans un stream, chaque message est considéré indépendant (stateless processing). Dans une table, chaque message est considéré comme une nouvelle version du précédent message de même clé (stateful processing). C’est ainsi qu’on retrouve notre CRUD familier. Le premier message pour une clé donnée forme le create, les messages suivants avec la même clé forment les updates, un message avec la même clé mais de valeur égale à nul forme le delete. On retrouve INSERT, UPDATE, DELETE de SQL.

Transformation d'une table en stream et d'un stream en table

La dualité stream/table : passer de l’un à l’autre.

La table est en fait un tableau associatif (ou map, dict, hash selon votre langage préféré) mis à jour à chaque message. Ce tableau associatif est géré par Kafka Streams. Il est interrogeable (read/retrieve de CRUD) rapidement car stocké en mémoire. Streams le réplique sur Kafka pour la résilience. On peut aller plus loin. Si au lieu d’écraser l’ancienne valeur du tableau associatif avec la nouvelle valeur du dernier message, on utilise une fonction qui calcule un résultat à partir de ces deux valeurs, alors on peut agréger arbitrairement les messages : nombre, somme, minimum, maximum, moyenne, accumulation… On retrouve GROUP BY, SUM, MIN, MAX, et autre AVG de SQL.

Enfin, on peut faire des jointures entre deux tables, une table et un stream, ou deux streams. On retrouve JOIN de SQL.

Mes parallèles avec SQL ne sont pas dus au hasard. SQL est le langage de transformation de données le plus connu, et les technologies de transformation de données finissent par le supporter tôt ou tard (voir Spark, Flink, Storm). La developer preview de KSQL, SQL pour Kafka, a été annoncée le 28 août 2017. On devrait donc, dans un avenir proche, pouvoir remplacer en (grande ?) partie Kafka Streams par KSQL, ce qui promet de diminuer les coûts de développement.

Kafka Connect

Kafka Streams est un outil très puissant, mais rarement suffisant. Par exemple, notre application métier peut avoir besoin de fonctionnalités avancées de recherche. Dans ce type de cas on peut s’appuyer sur des technologies spécialisées. Pour notre exemple, Elasticsearch ou Solr feraient l’affaire. Kafka Connect permet de mettre en place ce type d’architecture facilement. En lui fournissant uniquement de la configuration, Kafka Connect lie des sources de données en amont, et des bases de données cibles en aval de Kafka. C’est très utile à une époque où on sait qu’une seule technologie de base de données ne peut pas répondre à tous les besoins.

Cas d’utilisation

Cas classiques

  • Il reste bien sûr pertinent d’utiliser Kafka comme un bus de message, surtout si on a des besoins particuliers en termes de performance.
  • Kafka est un excellent choix pour faire de l’ETL (extract-transform-load) : Connect fournit le E et le L, Streams le T, et Kafka lui-même offre un tampon de stockage qui assure la scalabilité, la résilience et la rejouabilité du processus. De plus, l’ETL devient temps réel !
  • Kafka est tout à fait adapté pour de l’analyse temps réel (puisque c’est finalement un cas particulier d’ETL, avec un grand T et un L absent ou petit).

Moins classique : la source de vérité

Comme résumé en introduction de la documentation de Kafka, on a une technologie qui stocke des données de manière distribuée et résiliente, capable de transformer ces données au fil de l’eau, capable de distribuer ces données au fil de l’eau.

Architecture autour de Kafka : Producers, Consumers, Processors, Connectors

Quel meilleur endroit pour stocker les données essentielles d’une application ?

Prenons un peu de recul. En informatique de gestion, une application reçoit des signaux externes (des commandes de l’utilisateur via une interface graphique, ou provenant d’autres applications), prend des décisions en suivant une logique métier, puis modifie son état courant pour refléter les conséquences des décisions prises. Ce système perd fondamentalement de la donnée, puisque nulle part n’ont été enregistrées les commandes reçues, ni l’état précédent ! Au lieu de sauvegarder les données essentielles, on sauvegarde des données dérivées.

Et si on faisait l’inverse ? Certains reconnaissent peut-être ici les principes de l’event sourcing. Si toutes les commandes/événements reçus par l’application sont sauvegardés dans Kafka, alors on dispose d’un historique complet qu’on peut rejouer à loisir pour reconstruire l’état courant, un ancien état, de nouveaux états etc. Kafka devient alors la source de vérité de l’application.

La logique métier peut maintenant s’appuyer sur l’historique complet de l’application et en dériver de nouvelles données. Grâce à Kafka Streams la logique métier travaille en temps-réel, de manière résiliente et unitairement scalable. Les décisions en sortie sont à nouveau conservées dans Kafka. Kafka Streams prépare aussi les données et les formate pour qu’elles soient facilement consommables en aval (interfaces graphiques ou systèmes externes). Ceci remplace les index, vues et vues matérialisées d’une base classique. Enfin, Streams expose les données, soit directement via web service ou autre, soit en les déposant dans un topic Kafka que Connect déverse dans un SGBD tiers, qui sert de vue des données pour l’aval.

L’avenir de la gestion des données ?

Il me semble que l’architecture que je viens de présenter fournit des éléments qui permettent de se rapprocher de l’utopie proposée dans Out of the Tar Pit. Pourrait-on mettre en place une telle architecture à l’échelle des données de l’entreprise toute entière ? Le New York Times vient justement de publier un billet sur leur utilisation de Kafka pour stocker l’historique complet de leurs publications. Je pense que Apache Kafka a le potentiel de devenir la pierre angulaire de la gestion et de l’intégration des données dans les organisations.

Si le sujet vous intéresse, sachez que Zenika dispense les formations officielles Kafka pour développeurs et ops.

Partagez cet article.

A propos de l'auteur

Développeur autodidacte depuis 12 ans, professionnel depuis 4, je n'ai de cesse d'apprendre de nouvelles techniques pour améliorer mon savoir-faire. J'aime étudier les langages, de C# à Haskell. Au quotidien, ce sont Java et JavaScript qui m'accaparent : je suis consultant et formateur chez Zenika. Enfin, j'apprécie les jeux de code : vous me retrouverez par exemple sur CodinGame, et là, c'est Python 3.

Ajouter un commentaire