Dans cet article, je présente une étude comparant les environnements pour Apache Kafka. L’objectif ultime est de trouver la configuration la plus efficace et d’obtenir le meilleur rapport qualité-prix.
Notre plateforme de données fournit des services gérés pour créer des plateformes analytiques pour de grands ensembles de données, en concurrence avec d'autres solutions du marché. Pour rester compétitifs, nous menons régulièrement des recherches internes pour identifier et améliorer nos points forts, garantissant ainsi de meilleures transactions. Cet article présente une de ces études. Actuellement, notre plateforme prend en charge AWS et GCP en tant que fournisseurs de cloud. Les deux proposent plusieurs générations de calcul et deux architectures de processeur (x86 avec Intel et AMD, et ARM). Je compare ces configurations à l'aide de diverses machines virtuelles Java (JVM) pour évaluer les performances des nouvelles versions sur des processeurs plus récents.
Si vous voulez un TL;DR : ARM est génial. L’architecture moderne et coûteuse ne signifie pas toujours « meilleure ». Vous pouvez accéder directement aux résultats ou en savoir plus sur la méthodologie et la configuration.
J'ai envisagé de tester les performances avec notre propre service, mais je voulais les comparer dans différents environnements que nous n'avons pas encore pris en charge. Je voulais découvrir de nouvelles machines virtuelles, régions et même d'autres fournisseurs de cloud. J'ai donc commencé par implémenter un projet de jouet qui utilise Kafka de base avec différentes images de conteneurs de base. De cette façon, je peux exécuter des outils de référence sur du matériel spécifique et mesurer les performances.
Mon objectif est de tester différentes configurations pour identifier les résultats les plus intéressants. Pour cela, j'utilise l'idée de la matrice de test pour filtrer les premiers résultats. J'analyserai ces résultats en profondeur à l'aide d'outils tels que perf et eBPF pour affiner davantage les performances.
Décrivons d'abord les objectifs des tests. J'ai beaucoup d'expérience avec OpenJDK JVM, mais aujourd'hui, il existe de nombreuses alternatives proposées par Microsoft, Amazon et d'autres sociétés. Amazon Correto, par exemple, inclut des fonctionnalités supplémentaires et des correctifs optimisés pour AWS. Étant donné que la plupart de nos clients utilisent AWS, je souhaitais inclure Amazon Correto dans les tests pour voir comment ces JVM fonctionnent sur cette plate-forme.
J'ai choisi ces versions pour la première comparaison :
Une fois les versions définies, j'ai préparé quelques scripts pour créer des images Kafka en utilisant Amazon Correto et OpenJDK .
Pour les tests d'analyse comparative, j'ai modifié les paramètres de Kafka pour me concentrer sur des mesures de performances spécifiques. Je voulais tester différentes combinaisons de [JVM] x [instance_type] x [architecture] x [cloud_provider] , il était donc important de minimiser les effets de la connectivité réseau et des performances du disque. Je l'ai fait en exécutant des conteneurs avec tmpfs pour le stockage des données :
podman run -ti \ --network=host \ --mount type=tmpfs,destination=/tmp \ kfbench:3.6.1-21.0.2-amzn-arm64
Naturellement, cette configuration n’est pas destinée à la production, mais il était nécessaire d’isoler les goulots d’étranglement du processeur et de la mémoire. La meilleure façon est de supprimer les influences du réseau et du disque des tests. Autrement, ces facteurs fausseraient les résultats.
J'ai utilisé l'outil de référence sur la même instance pour garantir une latence minimale et une reproductibilité plus élevée. J'ai également essayé des tests sans configurations de réseau hôte et avec des réseaux virtuels isolés par groupe de contrôle, mais ceux-ci n'ont fait qu'ajouter une latence inutile et une utilisation accrue du processeur pour le transfert de paquets.
Bien que tmpfs alloue dynamiquement de la mémoire et puisse provoquer une fragmentation et une latence, cela s'est avéré adéquat pour notre test. J'aurais pu utiliser ramdisk à la place, qui alloue de la mémoire de manière statique et évite ces problèmes, mais tmpfs était plus facile à implémenter et fournissait toujours les informations que nous recherchions. Pour nos besoins, cela a trouvé le bon équilibre.
De plus, j'ai appliqué des paramètres Kafka supplémentaires pour supprimer plus fréquemment les données de la mémoire :
############################# Benchmark Options ############################# # https://kafka.apache.org/documentation/#brokerconfigs_log.segment.bytes # Chaged from 1GB to 256MB to rotate files faster log.segment.bytes = 268435456 # https://kafka.apache.org/documentation/#brokerconfigs_log.retention.bytes # Changed from -1 (unlimited) to 1GB evict them because we run in tmpfs log.retention.bytes = 1073741824 # Changed from 5 minutes (300000ms) to delete outdated data faster log.retention.check.interval.ms=1000 # Evict all data after 15 seconds (default is -1 and log.retention.hours=168 which is ~7 days) log.retention.ms=15000 # https://kafka.apache.org/documentation/#brokerconfigs_log.segment.delete.delay.ms # Changed from 60 seconds delay to small value to prevent memory overflows log.segment.delete.delay.ms = 0
Voici un résumé des changements :
Cette configuration n'est pas adaptée à une utilisation en production, mais elle est importante pour nos tests de référence car elle réduit les effets de facteurs non pertinents.
Chez DoubleCloud, au moment de la rédaction de cet article, nous prenons en charge ces principales générations de ressources de calcul :
Pour les processeurs Graviton, nous prenons en charge :
De plus, j'ai testé les instances t2a sur GCP comme alternative à Graviton sur Ampere Altra. Nous ne les proposons pas à nos clients en raison du support régional limité d'AWS, mais je les ai inclus dans les benchmarks pour comparer les performances. Ceux-ci pourraient être une bonne option si vous êtes dans l’une des « bonnes » régions.
Pour le benchmarking, j'ai développé un outil léger basé sur la bibliothèque et l'exemple Franz-go . Cet outil sature efficacement Kafka sans devenir lui-même le goulot d'étranglement.
Bien que librdkafka soit connu pour sa fiabilité et sa popularité, je l'ai évité en raison de problèmes potentiels avec cgo.
Kafka est réputé pour son évolutivité, permettant de diviser les sujets en plusieurs partitions afin de répartir efficacement les charges de travail horizontalement entre les courtiers. Cependant, je me suis concentré sur l'évaluation des performances monocœur pour notre attention particulière sur le rapport performance/prix.
Par conséquent, les tests ont utilisé des sujets avec des partitions uniques pour utiliser pleinement les capacités de base individuelles.
Chaque scénario de test comprenait deux types :
J'ai utilisé des messages de 8 Ko, plus volumineux qu'un cas client moyen, pour saturer complètement les threads de partition de sujet.
Je présente une série de graphiques comparant différents cas de test en utilisant une métrique d'efficacité synthétique pour évaluer différentes architectures. Cette métrique quantifie les millions de lignes que nous pouvons ingérer dans le courtier Kafka pour cent , fournissant ainsi une évaluation simple de la rentabilité architecturale.
Il est important de reconnaître que les résultats réels peuvent varier en raison des remises supplémentaires proposées par les fournisseurs de cloud. Dans la mesure du possible, les tests ont été effectués à Francfort pour les deux fournisseurs de cloud (ou aux Pays-Bas dans les cas où les options de type d'instance étaient limitées).
Sur tous les graphiques, j'utilise des noms conventionnels pour les instances, les mêmes que ceux utilisés par leurs fournisseurs. Les instances sont triées d'abord par fournisseurs de cloud (AWS, puis GCP) puis par génération : de l'ancienne à la plus récente.
Les résultats complets, bien que sous forme brute, sont disponibles dans ma fiche d'analyse comparative complète . Vous y trouverez plus de données que celles présentées dans cet article, notamment les chiffres de latence et de bande passante, ainsi que les performances comparatives des différentes JVM.
Les instances s1 de « 1ère génération » basées sur la génération m5a avec AMD EPYC 7571, datant du troisième trimestre 2019, sont notre option héritée. Ils sont les moins efficaces et les plus lents parmi nos options à Francfort, coûtant environ ~0,2080 €/heure à la demande. La transition vers la nouvelle famille s2, coûtant environ 0,2070 €/h, permet d'obtenir une efficacité deux fois supérieure pour pratiquement le même prix. Nous encourageons les clients à migrer vers ces options plus rentables et plus performantes pour améliorer les temps de requête et la vitesse d'ingestion pour les applications analytiques.
La famille g1 est basée sur Graviton 2 et offre historiquement un bon rapport qualité-prix, mais la nouvelle famille s2 avec processeurs AMD correspond désormais à son niveau d'efficacité pour Apache Kafka. Malgré une bande passante légèrement inférieure et un avantage de prix marginal, la famille g1 est désormais considérée comme obsolète par rapport aux options plus récentes.
La famille g2, alimentée par Graviton 3, se distingue comme notre principale recommandation en raison de son efficacité supérieure. Il surpasse les familles s2 et i2 jusqu'à 39 % dans certains scénarios, offrant une solution rentable dans presque toutes les régions, ce qui le rend idéal pour la plupart des cas d'utilisation d'Apache Kafka. Compte tenu de la nature typiquement liée aux E/S de Kafka, l'optimisation de l'efficacité informatique s'avère cruciale pour réaliser des économies. J'ai observé une tendance croissante à adopter l'architecture arm64, avec près de la moitié de nos clusters tirant déjà parti de cette nouvelle technologie.
Les tests montrent que chaque nouveau processeur AMD ou Intel s'améliore en termes de débit global et de latence. Malgré cela, les gains d’efficacité des nouvelles générations m6 et m7 ont plafonné. Même la génération m7, bien qu'elle offre potentiellement une latence plus faible dans certaines régions, est en deçà de l'efficacité par rapport à la famille g2, selon nos tests.
La famille m7a excelle dans les applications à faible latence, surpassant les générations Intel et AMD précédentes en termes de débit et de latence. Bien qu'elle ne soit pas universellement disponible, cette architecture reflète les progrès d'AMD en matière d'amélioration des performances. S'il est accessible dans votre région, pensez au m7a pour des résultats supérieurs.
Les instances GCP ont généralement une efficacité inférieure à celle de leurs alternatives AWS. Cela a été une excellente idée pour moi, car les clients préfèrent généralement GCP pour sa rentabilité dans les applications analytiques, ce qui se traduit par des factures moins élevées. Notre famille sg1 utilise la génération standard n2, comparable à la famille AWS s2. Cependant, ma tentative d'étendre cette comparaison à d'autres types d'instances a été limitée par la disponibilité régionale, en particulier pour les générations c3 et n2.
Les instances Arm utilisant les processeurs Tau de GCP offrent une amélioration d'efficacité de 5 à 7 % par rapport à Graviton 2, ce qui en fait une option raisonnablement économique, si elle est disponible dans votre région . Bien que la prise en charge de GCP pour les instances arm soit limitée à quatre régions, elle offre des performances et une efficacité comparables à celles de la famille g1.
Étant donné que les clusters Apache Kafka utilisent constamment la machine virtuelle, tirer parti des remises d’utilisation durable permet d’obtenir jusqu’à 20 % de remise. Cela rend les puissances de calcul encore plus anciennes, comme Ampere Altra, compétitives avec Graviton 3 en termes d'efficacité. Les comparaisons directes sont cependant délicates ici, en raison des remises AWS supplémentaires qui peuvent également s'appliquer.
Je pensais voir une amélioration significative avec les nouvelles versions de JVM sur l'architecture ARM. Cependant, il semble que openjdk-11 et corretto-11 soient déjà assez optimisés pour ARM. Étant donné que les versions plus récentes de Kafka nécessitent Java 17 et versions ultérieures, je suis passé à Java 17, ce qui a entraîné un gain de performances d'environ 4 à 8 % dans nos tests de performance.
De plus, la version 21.0.2-amzn semble prometteuse, offrant une amélioration supplémentaire des performances de 10 à 20 % sur les types d'instances les plus récents.
De temps en temps, j'effectue des recherches internes pour trouver des solutions optimales pour nos pôles de production et recueillir des informations utiles. L'évolution vers l'architecture ARM est avantageuse pour les services gérés, car elle permet d'économiser de l'argent et de réduire la consommation d'énergie.
Le recours aux ARM s'est déjà révélé bénéfique, améliorant les performances et la rentabilité du service géré pour Apache Kafka et du service géré pour ClickHouse. Cette recherche a permis d'affiner notre matrice de tests, en identifiant les environnements les plus efficaces et les domaines à optimiser davantage. Nous sommes toujours là-dessus : peaufiner et peaufiner sous le capot, et je suis heureux de partager nos connaissances avec la communauté. Restez à l'écoute!