La demande de magasins de fonctionnalités d'apprentissage automatique à faible latence est plus élevée que jamais, mais la mise en œuvre d'un magasin de fonctionnalités à faible latence reste un défi.Cela est devenu évident lorsque les ingénieurs ShareChat Ivan Burmistrov et Andrei Manakov ont pris la phase P99 CONF 23 pour partager comment ils ont construit un magasin de fonctionnalités ML à faible latence basé sur ScyllaDB. Ce n'est pas une étude de cas ordonnée où l'adoption d'un nouveau produit sauve la journée.C'est une histoire de "leçons apprises", un regard sur la valeur de l'optimisation des performances sans relâche - avec quelques étapes d'ingénierie importantes. L’objectif ultime était de supporter 1 milliard de fonctionnalités par seconde, mais le système a échoué sous une charge de seulement 1 million.Avec une résolution intelligente des problèmes, l’équipe l’a cependant retirée.Voyons comment leurs ingénieurs ont réussi à se détourner de l’échec initial pour atteindre leur objectif de performance élevé sans évoluer la base de données sous-jacente. Obsédé par l’optimisation des performances et l’ingénierie à faible latence ? rejoignez vos pairs au P99 24 CONF, une conférence virtuelle gratuite hautement technique sur la « performance de toutes choses ». Michael Stonebraker, créateur de Postgres et professeur au MIT Bryan Cantrill, co-fondateur et CTO de Oxide Computer Avi Kivity, créateur de KVM, co-fondateur et CTO de ScyllaDB Liz Rice, Chief Open Source Officer avec les spécialistes d’eBPF Isovalent Andy Pavlo, professeur de CMU Ashley Williams, fondateur/directeur général d’Axo, ancienne équipe principale de Rust, fondateur de la Fondation Rust Carl Lerche, créateur de Tokyo, contributeur de Rust et ingénieur chez AWS Inscrivez-vous dès maintenant – c’est gratuit Inscrivez-vous dès maintenant – c’est gratuit Inscrivez-vous dès maintenant – c’est gratuit En plus d'une autre grande conversation par Ivan de ShareChat, attendez-vous à plus de 60 discussions d'ingénierie sur l'optimisation des performances chez Disney / Hulu, Shopify, Lyft, Uber, Netflix, American Express, Datadog, Grafana, LinkedIn, Google, Oracle, Redis, AWS, ScyllaDB et plus. ShareChat : la première plateforme de médias sociaux en Inde To understand the scope of the challenge, it’s important to know a little about ShareChat, the leading social media platform in India. On the ShareChat app, users discover and consume content in more than 15 different languages, including videos, images, songs and more. ShareChat also hosts a TikTok-like short video platform (Moj) that encourages users to be creative with trending tags and contests. Entre les deux applications, ils servent une base d'utilisateurs en croissance rapide qui compte déjà plus de 325 millions d'utilisateurs actifs mensuels. Appareils de fonctionnalités d'apprentissage automatique sur ShareChat Cette histoire se concentre sur le système derrière les boutiques de fonctionnalités ML pour l'application vidéo à court format Moj. Il offre des flux entièrement personnalisés à environ 20 millions d'utilisateurs actifs quotidiens, 100 millions d'utilisateurs actifs mensuels. Les flux servent 8 000 demandes par seconde, et il y a en moyenne 2 000 candidats de contenu classés sur chaque demande (par exemple, pour trouver les 10 meilleurs articles à recommander). Ivan Burmistrov, ingénieur logiciel principal de ShareChat, a expliqué : « Nous calculons les fonctionnalités pour différentes « entités ». Post est une entité, Utilisateur est un autre et ainsi de suite. Du point de vue du calcul, ils sont assez similaires. Cependant, la différence importante est dans le nombre de fonctionnalités que nous devons collecter pour chaque type d’entité. Lorsqu’un utilisateur demande un flux, nous collections les fonctionnalités utilisateur pour cet utilisateur unique. Cependant, pour classer tous les messages, nous devons collecter les fonctionnalités pour chaque candidat (post) classé, de sorte que la charge totale sur le système générée par les fonctionnalités postales est beaucoup plus grande que celle générée par les fonctionnalités utilisateur. Cette différence joue un rôle important dans notre histoire. » Ce qui a mal tourné Au début, l’accent était mis sur la création d’un magasin de fonctionnalités utilisateur en temps réel car, à ce moment-là, les fonctionnalités utilisateur étaient les plus importantes.L’équipe a commencé à construire le magasin de fonctionnalités avec cet objectif à l’esprit.Mais ensuite les priorités ont changé et les fonctionnalités postales sont aussi devenues le focus.Ce changement s’est produit parce que l’équipe a commencé à construire un tout nouveau système de classement avec deux différences majeures par rapport à son prédécesseur: Les caractéristiques de post en temps réel étaient plus importantes Le nombre de postes à classer a augmenté de centaines à des milliers Ivan a expliqué : « Lorsque nous sommes allés tester ce nouveau système, il a malheureusement échoué. À environ 1 million de caractéristiques par seconde, le système est devenu non réactif, les latences ont traversé le toit et ainsi de suite. » En fin de compte, le problème a découlé de la façon dont l'architecture du système a utilisé des boîtes de données préagrégées appelées carreaux. Par exemple, ils peuvent agréger le nombre de likes pour un message dans une minute donnée ou une autre plage de temps. Cela leur permet de calculer des mesures telles que le nombre de likes pour plusieurs messages au cours des deux dernières heures. Voici un regard de haut niveau sur l'architecture du système.Il y a quelques sujets en temps réel avec des données brutes (j'aime, cliques, etc.). Un travail Flink les agrégue en carreaux et les écrit à ScyllaDB. Ensuite, il y a un service de fonctionnalités qui demande des carreaux à ScyllaDB, les agrégue et renvoie les résultats au service de flux. Le schéma de base de données initial et la configuration de carrelage ont entraîné des problèmes d'évolutivité. À l'origine, chaque entité avait sa propre partition, avec des timestamps de lignes et des noms de fonctionnalités ordonnés par des colonnes de regroupement. [ ]. Les carreaux ont été calculés pour les segments d'une minute, 30 minutes et un jour. Rechercher une heure, un jour, sept jours ou 30 jours a nécessité la collecte d'environ 70 carreaux par fonction en moyenne. Apprenez-en plus dans ce masterclass de modélisation de données NoSQL Si vous faites les mathématiques, il devient clair pourquoi il a échoué. Le système a dû traiter environ 22 milliards de lignes par seconde. Cependant, la capacité de la base de données était seulement 10 millions de lignes/sec. Optimisation initiale À ce moment-là, l'équipe a entrepris une mission d'optimisation. Le schéma de base de données initial a été mis à jour pour stocker toutes les lignes de fonctionnalités ensemble, sérialisées en buffers de protocole pour un timestamp donné. Parce que l'architecture utilisait déjà Apache Flink, la transition vers le nouveau schéma de carrelage a été assez facile, grâce aux capacités avancées de Flink dans la construction de pipelines de données. Avec cette optimisation, le multiplicateur "Fonctions" a été supprimé de l'équation ci-dessus, et le nombre de lignes requises à récupérer a été réduit de 100X: d'environ 2 milliards à 200 millions de lignes/sec. L’équipe a également optimisé la configuration du carrelage en ajoutant des carreaux supplémentaires pendant cinq minutes, trois heures et cinq jours à une minute, 30 minutes et une journée. Pour gérer plus de lignes/sec sur le côté de la base de données, ils ont changé la stratégie de compression de ScyllaDB d'incrémental à nivellé. Cette option a mieux adapté leurs modèles de requêtes, en gardant les lignes pertinentes ensemble et en réduisant la lecture I/O. Le résultat: la capacité de ScyllaDB a effectivement été doublée. En savoir plus sur les stratégies de compactage La façon la plus facile d'accueillir la charge restante aurait été d'échelonner ScyllaDB 4x. Cependant, les clusters plus / plus grands augmenteraient les coûts et cela n'était tout simplement pas dans leur budget. Améliorer la localisation du cache L’un des moyens potentiels de réduire la charge sur ScyllaDB était d’améliorer le taux de succès du cache local, de sorte que l’équipe a décidé d’étudier comment cela pourrait être réalisé. Le choix évident était d’utiliser une approche de hachage cohérente, une technique bien connue pour diriger une demande à une certaine réplique du client en fonction de certaines informations sur la demande. Étant donné que l’équipe utilisait NGINX Ingress dans leur configuration Kubernetes, l’utilisation des capacités de hachage cohérent de NGINX semblait être un choix naturel. Cette configuration simple n'a pas fonctionné. en particulier: Le sous-ensemble du client a conduit à un remapage de clés énorme - jusqu'à 100% dans le pire des cas. Puisque les clés de nœuds peuvent être changées dans un anneau de hachage, il était impossible d'utiliser des scénarios de la vie réelle avec l'autoscalage. [Voir la mise en œuvre ingress] Il était difficile de fournir une valeur de hachage pour une demande car Ingress ne prend pas en charge la solution la plus évidente: un en-tête gRPC. La latence a subi une dégradation grave, et il n'était pas clair ce qui provoquait la latence de la queue. Pour soutenir un sous-ensemble des pods, l’équipe a modifié leur approche. Ils ont créé une fonction de hachage en deux étapes : d’abord hachage d’une entité, puis ajout d’un préfixe aléatoire. Ce qui a distribué l’entité sur le nombre souhaité de pods. En théorie, cette approche pourrait provoquer une collision lorsqu’une entité est cartographiée sur le même pod plusieurs fois. Ingress ne prend pas en charge l'utilisation de l'en-tête gRPC en tant que variable, mais l'équipe a trouvé un outil: utiliser la réécriture du chemin et fournir la clé de hachage requise dans le chemin lui-même. Malheureusement, la détermination de la cause de la dégradation de la latence aurait nécessité un temps considérable, ainsi que des améliorations de l'observabilité. Pour respecter le délai, l’équipe a divisé le service Feature en 27 services différents et a divisé manuellement toutes les entités entre eux sur le client. Ce n’était pas l’approche la plus élégante, mais, il était simple et pratique – et il a obtenu d’excellents résultats. Le taux de hit du cache s’est amélioré à 95% et la charge de ScyllaDB a été réduite à 18,4 millions de lignes par seconde. Avec ce design, ShareChat a élargi son magasin de fonctionnalités à 1B de fonctionnalités par seconde d’ici mars. Cependant, cette approche de déploiement de « vieille école » n’était toujours pas la conception idéale. Maintenir 27 déploiements était ennuyeux et inefficace. De plus, le taux de hit du cache n’était pas stable, et l’évolutivité était limitée par la nécessité de maintenir un nombre de pods minimum élevé dans chaque déploiement. La prochaine phase d’optimisation : hashing cohérent, service de fonctionnalités Prêt pour un autre cycle d'optimisation, l'équipe a revu l'approche de hashing cohérente en utilisant un sidecar, appelé Envoy Proxy, déployé avec le service de fonctionnalité. Envoy Proxy a fourni une meilleure observabilité qui a aidé à identifier le problème de la queue de latence. Le problème: les modèles de requête différents au service de la fonctionnalité ont causé une énorme charge sur la couche et le cache gRPC. L’équipe a ensuite optimisé le service Feature. Forked la bibliothèque de mise en cache (FastCache de VictoriaMetrics) et mis en œuvre batch writes et meilleure expulsion pour réduire le contention de mutex de 100x. Forked gprc-go et mis en œuvre buffer pool sur différentes connexions pour éviter la controverse pendant le parallélisme élevé. Le poolage d'objets et les paramètres du collecteur de déchets (GC) sont utilisés pour réduire les taux d'allocation et les cycles de GC. Avec Envoy Proxy gérant 15% du trafic dans leur proof-of-concept, les résultats étaient prometteurs: un taux de hit de cache de 98%, ce qui a réduit la charge sur ScyllaDB à 7,4M rangées/sec. Ils pourraient même évoluer le magasin de fonctionnalités plus: de 1 milliard de caractéristiques/sec à 3 milliards de caractéristiques/sec. Les leçons apprises Voici à quoi ressemblait ce voyage d'un point de vue chronologique: Pour conclure, Andrei a résumé les principales leçons de l’équipe tirées de ce projet (jusqu’à présent): Même si l’équipe de ShareChat a radicalement changé la conception de leur système, ScyllaDB, Apache Flink et VictoriaMetrics ont continué à fonctionner bien. Chaque optimisation est plus difficile que la précédente – et a moins d’impact. Des solutions simples et pratiques (comme la division de la boutique de fonctionnalités en 27 déploiements) fonctionnent vraiment. La solution qui fournit les meilleures performances n’est pas toujours conviviale. Par exemple, leur schéma de base de données révisé donne de bonnes performances, mais est difficile à maintenir et à comprendre. Parfois, vous devrez peut-être forger une bibliothèque par défaut et l'ajuster pour votre système spécifique pour obtenir les meilleures performances. Regardez leur conversation complète P99 CONF! Regardez leur conversation complète P99 CONF! Regardez leur conversation complète P99 CONF! À propos de Cynthia Dunlop Cynthia est directrice générale de la stratégie de contenu chez ScyllaDB. Elle écrit sur le développement de logiciels et l'ingénierie de la qualité depuis plus de 20 ans.