Retour au catalogue
Season 17 12 Épisodes 40 min 2026

Apache Cassandra with Python

Édition 2026. Une série de podcasts techniques explorant l'architecture distribuée d'Apache Cassandra et la manière d'interagir avec elle à l'aide du DataStax Python Driver. Couvre la modélisation des données, les Execution Profiles, les LWTs, les requêtes asynchrones et le cqlengine Object Mapper.

Bases de données Calcul distribué
Apache Cassandra with Python
Lecture en cours
Click play to start
0:00
0:00
1
Vue d'ensemble
Une introduction à Apache Cassandra. Découvrez pourquoi les applications à l'échelle mondiale choisissent cette base de données NoSQL distribuée et en quoi elle diffère des systèmes relationnels traditionnels.
3m 10s
2
Hachage cohérent et l'anneau
Plongez dans l'architecture de Cassandra. Nous explorons le hachage cohérent, le token ring et la manière dont les données sont partitionnées sur plusieurs nœuds sans serveur maître.
3m 15s
3
Modélisation des données orientée requêtes
Oubliez tout ce que vous savez sur les bases de données relationnelles. Découvrez comment la modélisation orientée requêtes de Cassandra nécessite une dénormalisation, ainsi que la différence cruciale entre les partition keys et les clustering keys.
3m 03s
4
Connexion avec Python
Démarrez avec le DataStax Python Driver. Apprenez à instancier un Cluster, à vous connecter à une Session et à établir la communication avec vos nœuds Cassandra.
3m 22s
5
Execution Profiles
Gérez des charges de travail complexes en toute transparence grâce aux Execution Profiles. Apprenez à configurer l'équilibrage de charge, les timeouts et les consistency levels par requête sans polluer la configuration de votre cluster.
3m 43s
6
Prepared Statements
Apprenez à exécuter des commandes CQL depuis Python. Nous abordons les requêtes simples et les avantages critiques en termes de performances liés à l'utilisation des Prepared Statements pour les requêtes fréquentes.
2m 52s
7
Pagination des requêtes volumineuses
Ne faites jamais planter votre application en chargeant un ensemble de données massif en mémoire. Découvrez comment le driver Python pagine automatiquement les résultats des requêtes volumineuses et comment gérer les fetch sizes.
3m 03s
8
Requêtes asynchrones à haut débit
Maximisez le débit de votre application. Apprenez à utiliser execute_async, les ResponseFutures et les callbacks pour exécuter des requêtes concurrentes vers Cassandra.
3m 44s
9
Lightweight Transactions
Implémentez des opérations compare-and-set en toute sécurité. Apprenez comment les Lightweight Transactions (LWTs) fonctionnent dans Cassandra et comment inspecter la colonne spécialisée applied dans vos résultats Python.
3m 13s
10
Les modèles de l'Object Mapper
Évitez les chaînes CQL brutes et modélisez vos données à l'aide de classes Python. Apprenez à utiliser cqlengine pour définir des tables, spécifier des primary keys et synchroniser votre schéma.
3m 53s
11
Faire des requêtes avec cqlengine
Récupérez et filtrez les données de manière fluide à l'aide des objets QuerySet dans le cqlengine Object Mapper. Nous abordons les opérateurs de filtrage, l'immuabilité et les limites de tri.
3m 30s
12
Vector Search pour l'IA
Préparez l'avenir de vos compétences avec le Vector Search de Cassandra 5.0. Découvrez comment stocker et interroger des vecteurs à haute dimension pour propulser les applications modernes d'IA et d'apprentissage automatique.
3m 45s

Épisodes

1

Vue d'ensemble

3m 10s

Une introduction à Apache Cassandra. Découvrez pourquoi les applications à l'échelle mondiale choisissent cette base de données NoSQL distribuée et en quoi elle diffère des systèmes relationnels traditionnels.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apache Cassandra avec Python, épisode 1 sur 12. Les bases de données relationnelles se heurtent à un mur quand tu essaies de les deploy sur plusieurs continents. Tu finis par te battre contre la latence, le downtime, ou une architecture fragile où un seul serveur qui plante fait tomber tes opérations de write. Un scale global massif nécessite un paradigme de base de données complètement différent. Ce paradigme, c'est Apache Cassandra. C'est une base de données NoSQL distribuée et open-source, conçue pour un scale immense. Quand les ingénieurs découvrent Cassandra, ils arrivent souvent avec le bagage des systèmes relationnels. Ils cherchent le primary node qui gère les writes et les read-only replicas qui le suivent. Tu dois oublier ce modèle mental immédiatement. Cassandra n'utilise pas un design primary-replica. Elle fonctionne entièrement sur une architecture masterless et multi-primary. Chaque node du cluster est identique. N'importe quel node peut accepter une read request, et n'importe quel node peut accepter une write request. Pour comprendre pourquoi ça marche comme ça, regarde son histoire. Cassandra a été développé à l'origine en combinant deux avancées majeures de la recherche. Premièrement, il a repris le network design entièrement distribué et masterless d'Amazon Dynamo. C'est ce qui dicte comment les nodes communiquent, se découvrent entre eux et répliquent la data sur le réseau. Deuxièmement, il a adopté le storage engine log-structured de Google Bigtable, qui gère comment la data est physiquement écrite sur le disque. Le résultat, c'est un système conçu spécifiquement pour une disponibilité continue sur plusieurs datacenters. Prends l'exemple d'un réseau social global. Tu as des utilisateurs actifs simultanément à Tokyo, Londres et New York. Si un utilisateur à Londres met à jour son profil, cette opération de write doit se faire instantanément. Router cette request à travers l'Atlantique vers une seule base de données centrale, c'est trop lent. Avec Cassandra, l'utilisateur écrit sur un node local dans le datacenter de Londres. Ce node accepte le write localement et prend immédiatement la responsabilité de le répliquer en background vers Tokyo et New York. Voici l'idée clé. Comme chaque node agit comme un primary, il n'y a pas de single point of failure. Cassandra organise ses nodes dans un ring logique. Quand de la data entre dans le système, un hash mathématique détermine exactement quels nodes dans le ring possèdent cette data spécifique. Si une panne majeure met tout le datacenter de Londres offline, le réseau social ne tombe pas. Tokyo et New York continuent d'accepter les reads et les writes sans interruption. Quand Londres revient online, les autres datacenters synchronisent automatiquement la data manquante vers les nodes rétablis. Tu obtiens une vraie disponibilité globale avec zéro downtime. Ce design masterless signifie aussi que le scaling est prévisible et linéaire. Si tu as besoin de plus de stockage ou de plus de capacité de write, tu branches simplement un autre node dans le ring. Le cluster détecte automatiquement le nouveau hardware et redistribue la data pour équilibrer la charge sur les machines actives. Cassandra te force à échanger le confort des queries de bases de données traditionnelles contre quelque chose de beaucoup plus dur à construire at scale : la garantie absolue que, peu importe le hardware qui plante, ta base de données reste online et tes opérations réussissent. Si tu veux soutenir l'émission, tu peux chercher DevStoriesEU sur Patreon. C'est tout pour cet épisode. Merci pour ton écoute, et continue de build !
2

Hachage cohérent et l'anneau

3m 15s

Plongez dans l'architecture de Cassandra. Nous explorons le hachage cohérent, le token ring et la manière dont les données sont partitionnées sur plusieurs nœuds sans serveur maître.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apache Cassandra avec Python, épisode 2 sur 12. Le data hashing naïf plante complètement au moment où tu ajoutes un nouveau serveur à ton cluster de base de données. Quand le nombre de serveurs change, presque chaque donnée doit bouger vers un nouvel emplacement. La solution à ce chaos de scaling, c'est le Consistent Hashing et le Ring. Une méthode standard pour distribuer des données sur plusieurs serveurs, c'est le modulo hashing. Si tu as huit nodes, tu prends une partition key comme un user ID, tu la hashes, et tu divises le résultat par huit. Le reste t'indique quel node reçoit le profil utilisateur. Ça marche parfaitement jusqu'à ce que ton stockage soit plein et que tu branches un neuvième node. Maintenant, tu divises par neuf. Les restes changent. Presque chaque profil utilisateur de ton système se retrouve soudainement sur un serveur différent, ce qui provoque une énorme tempête de mouvement de données qui met le cluster à genoux. Cassandra évite ça complètement. Il utilise le Consistent Hashing pour distribuer les données de manière prévisible sur le cluster, sans dépendre d'un coordinateur central. Au lieu d'un simple calcul modulo, Cassandra mappe à la fois les données et les nodes sur un espace circulaire fixe et continu appelé le token ring. Par défaut, Cassandra utilise une fonction de hash qui génère une plage massive de nombres possibles. La valeur de hash la plus basse se connecte directement à la plus haute, formant un cercle fermé. Chaque node physique dans le cluster se voit attribuer un numéro spécifique, ou token, quelque part sur ce ring. Quand tu insères un profil utilisateur, Cassandra hashe le user ID pour produire un token. Pour savoir quel node possède ce profil, le système localise le data token sur le ring et se déplace dans le sens des aiguilles d'une montre. Le premier node qu'il rencontre est le propriétaire. Repense à notre cluster de huit nodes. Si on ajoute un neuvième node physique, on lui attribue un seul nouveau token sur le ring, qui atterrit entre deux nodes existants. Comme la propriété des données est déterminée en avançant dans le sens des aiguilles d'une montre, ce nouveau neuvième node ne récupère qu'une tranche spécifique de données de son voisin immédiat dans le sens des aiguilles d'une montre. Les sept autres nodes ne font rien. Leurs données restent complètement intactes. Voici le point clé. Attribuer exactement un token à un node physique crée des problèmes opérationnels. C'est difficile d'équilibrer parfaitement les données, et quand tu ajoutes un nouveau node, un seul serveur voisin est responsable de transférer les données. Ce seul voisin se retrouve écrasé sous une lourde charge. Pour corriger ça, Cassandra utilise des virtual nodes, ou vnodes. Au lieu de donner à un serveur physique une énorme tranche contiguë du ring, les vnodes découpent le ring en plein de plus petites plages. Un seul node physique se voit attribuer des centaines de tokens différents, répartis aléatoirement sur le ring. Quand tu ajoutes ce neuvième node physique en utilisant des vnodes, il réclame plein de petites tranches du ring à tous les serveurs existants en même temps. Maintenant, au lieu qu'un seul voisin fasse tout le gros du travail, le cluster entier partage équitablement le travail de streaming de données vers la nouvelle machine. Le Consistent Hashing et les virtual nodes découplent le placement des données du nombre brut de serveurs physiques, ce qui permet à un cluster de scaler en douceur et de fonctionner de manière prévisible sans aucun master central pour dicter où les données doivent aller. C'est tout pour cet épisode. À la prochaine !
3

Modélisation des données orientée requêtes

3m 03s

Oubliez tout ce que vous savez sur les bases de données relationnelles. Découvrez comment la modélisation orientée requêtes de Cassandra nécessite une dénormalisation, ainsi que la différence cruciale entre les partition keys et les clustering keys.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apache Cassandra avec Python, épisode 3 sur 12. Dans une base de données relationnelle, tu crées d'abord tes tables, tu définis tes relations, et ensuite tu écris tes queries. Dans Cassandra, si tu ne connais pas tes queries exactes avant de commencer, ta base de données va planter. C'est le principe fondamental du Query Driven Data Modeling. Beaucoup de développeurs arrivent sur Cassandra avec de fortes habitudes relationnelles. Naturellement, tu cherches des moyens de normaliser tes données, de configurer des foreign keys, et d'éviter la duplication. Tu dois complètement abandonner cet état d'esprit. Cassandra ne supporte pas les joins. Si tu essaies de normaliser tes données sur plusieurs tables, tu vas finir par faire des joins dans ton code applicatif, ce qui détruit les gains de performance pour lesquels tu as choisi Cassandra au départ. Cassandra impose le Query Driven Data Modeling. Tu commences par mapper les questions exactes que ton application doit poser à la base de données. Dans ce modèle, une query correspond généralement à une table. Si tu as besoin d'accéder aux mêmes données de trois manières différentes, tu crées trois tables différentes qui contiennent les mêmes données. Ça nous amène à la dénormalisation. Dupliquer la donnée n'est pas une erreur ici, c'est la stratégie fondamentale. L'espace disque ne coûte rien, mais les reads distribués sur un réseau coûtent cher. En écrivant les données ensemble, exactement dans le format de ta read query, Cassandra peut les récupérer en une seule opération sans chercher dans tout le cluster. Pour que ça marche, tu dois comprendre la primary key. Ce n'est pas juste un identifiant unique. Elle contrôle exactement où et comment tes données sont stockées sur le disque. La primary key a deux parties distinctes : la partition key et la clustering key. La partition key dicte quel node physique de ton cluster contient la donnée. Toutes les rows qui partagent la même partition key sont stockées ensemble sur le même node. La clustering key détermine l'ordre de tri de ces rows sur le disque, à l'intérieur de cette partition spécifique. Prends le scénario de publication de magazines de la documentation. Supposons que ton application doive fetcher tous les magazines sortis par un éditeur spécifique. Ta partition key doit être le nom de l'éditeur. Quand la query arrive, Cassandra hashe le nom de l'éditeur, identifie le node exact qui contient les données de cet éditeur, et y va directement. Pour organiser les résultats naturellement, tu pourrais utiliser la date de publication comme clustering key. Maintenant, non seulement tous les magazines de cet éditeur sont regroupés sur un seul node, mais ils sont stockés physiquement par ordre chronologique. La base de données streame simplement les données pré-triées. Voici le point clé. Tu échanges la complexité de write contre une vitesse de read massive. Tu écris les mêmes données dans plusieurs tables pour satisfaire différentes vues de l'application, mais quand un utilisateur demande ces données, elles reviennent en quelques millisecondes parce que la base de données fait zéro calcul pour les assembler. Merci d'avoir écouté. Prenez soin de vous, tout le monde.
4

Connexion avec Python

3m 22s

Démarrez avec le DataStax Python Driver. Apprenez à instancier un Cluster, à vous connecter à une Session et à établir la communication avec vos nœuds Cassandra.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apache Cassandra avec Python, épisode 4 sur 12. Quand tu te connectes à une base de données traditionnelle, tu pointes ton application vers une seule adresse hôte. Quand tu te connectes à une base de données distribuée, tu pourrais penser que tu dois gérer manuellement des dizaines d'adresses de serveurs dans tes fichiers de configuration. Eh bien non, parce que ton driver de base de données agit en fait comme un routeur intelligent. Aujourd'hui, on regarde comment se connecter avec Python. Imagine un microservice Python qui démarre. Il doit établir la communication avec un cluster Cassandra local de trois nœuds. Pour commencer, tu importes la classe Cluster du module cassandra point cluster. Tu initialises cette classe en lui passant une liste d'adresses IP, qu'on appelle des contact points. Si tes nœuds utilisent un port non standard, tu peux aussi spécifier un argument port ici, sinon, c'est 9042 par défaut. Les développeurs confondent souvent cette étape avec la création d'une connection string standard avec un seul DSN, où tu dois lister explicitement exactement à quoi tu veux te connecter. Avec Cassandra, tu n'as pas besoin de lister chaque nœud de ton infrastructure. Si tu as un énorme cluster de trente nœuds, passer juste deux ou trois adresses IP comme contact points, c'est parfait. Voici le truc important. Quand le driver Python démarre, il contacte l'un de ces contact points pour faire son bootstrap. Il interroge les tables système pour télécharger la topologie actuelle du cluster. En faisant ça, il découvre automatiquement les adresses IP du reste des nœuds. Le driver maintient dynamiquement cette carte réseau en background. Si tu fais un scale out et que tu ajoutes des nœuds plus tard, le driver détecte le changement et ajuste son routage automatiquement sans avoir besoin de redémarrer l'application. Une fois que tu as instancié ton objet Cluster avec ces contact points initiaux, tu appelles sa méthode connect. Cette action te retourne un objet Session. La Session gère le connection pooling vers les nœuds qu'elle vient de découvrir. Quand tu appelles connect, tu peux optionnellement passer un nom de keyspace. Un keyspace fonctionne comme un namespace pour tes données. S'il est fourni, le driver le définit par défaut pour toutes les futures opérations sur cette Session. Parce que la Session gère des connection pools complexes en arrière-plan, elle est conçue pour avoir une longue durée de vie et être thread-safe. En général, tu crées une seule Session au démarrage de l'application et tu la réutilises. Maintenant, la deuxième partie, c'est la connexion à un service cloud managé comme DataStax Astra. Astra fonctionne différemment et n'expose pas d'adresses IP brutes pour les contact points. À la place, tu télécharges un secure connect bundle. C'est un fichier zip qui contient les certificats requis et les détails de la connexion mutual TLS. Dans ton code Python, tu ignores la liste d'adresses IP. À la place, tu fournis un dictionnaire de configuration cloud à l'objet Cluster. Ce dictionnaire contient une clé appelée secure connect bundle, qui pointe vers le chemin local de ton fichier zip. Tu combines ça avec un objet plaintext authentication provider configuré avec ton client ID et ton secret. Appeler connect te retourne ensuite un objet Session standard, qui fonctionne exactement comme la configuration du cluster local. Ce qu'il faut retenir, c'est que, que tu passes quelques adresses IP locales ou un secure connect bundle cloud, le driver Python prend ton point d'entrée initial, mappe le réseau de la base de données distribuée, et abstrait complètement la logique de routage de ton code applicatif. C'est tout pour cet épisode. Merci d'avoir écouté, et continue de développer !
5

Execution Profiles

3m 43s

Gérez des charges de travail complexes en toute transparence grâce aux Execution Profiles. Apprenez à configurer l'équilibrage de charge, les timeouts et les consistency levels par requête sans polluer la configuration de votre cluster.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apache Cassandra avec Python, épisode 5 sur 12. À mesure que ton application grandit, appliquer un timeout ou un consistency level unique à toutes tes queries de base de données devient un énorme goulot d'étranglement opérationnel. Tu finis par faire planter tes background jobs prématurément ou par bloquer ton interface utilisateur en attendant un heavy read. Les Execution Profiles sont le mécanisme qui résout ce problème. Beaucoup de développeurs confondent la configuration d'exécution avec l'ancienne configuration au niveau du cluster. Dans les anciens paradigmes, tu définissais des paramètres globaux directement sur l'objet cluster, ce qui veut dire que chaque query partageait exactement le même timeout. Les Execution Profiles remplacent ce pattern rigide. Ils te permettent de maintenir simultanément plusieurs configurations distinctes au sein d'une seule session active. Prends l'exemple d'une application web multi-tenant. Ton interface front-end nécessite un timeout strict d'une seconde pour garantir que les pages web restent réactives. Pendant ce temps, tes background jobs de reporting ont besoin de trente secondes pour agréger de grosses partitions en toute sécurité. Un Execution Profile est un ensemble autonome et nommé de paramètres de request, taillé sur mesure pour ces différents workloads. Pour construire ça, tu commences par créer des instances d'un objet Execution Profile. Pour la tâche de reporting, tu instancies un profil et tu définis le paramètre request timeout sur trente secondes. Tu peux aller plus loin et attacher une load balancing policy spécifique à cet objet, par exemple pour router ces heavy analytical reads exclusivement vers un data center dédié à l'analytique. Ensuite, tu crées un deuxième objet profil distinct pour ton interface utilisateur, en lui assignant un timeout d'une seconde et une load balancing policy locale. Tu peux aussi regrouper des retry policies ou des consistency levels distincts dans ces profils, selon ce que la query exige. Voici le point clé. Tu enregistres ces profils une seule fois, lors du setup initial de ton cluster, plutôt que de les construire pendant l'exécution de la query elle-même. Lors de l'instanciation du cluster, tu passes un dictionnaire à l'argument execution profiles. Ce dictionnaire associe de simples noms en string aux objets profil que tu viens de créer. Le driver gère ces configurations sous le capot. Il y a toujours un profil de fallback intégré, que tu peux surcharger en associant une configuration à une constante spécifique appelée execution profile default. Si tu exécutes une query sans nommer explicitement un profil, le driver applique automatiquement ces paramètres par défaut. Quand tu as vraiment besoin de lancer une query, tu utilises les méthodes standard session execute ou execute async. En plus de ta query string ou de ton prepared statement, tu passes un argument execution profile en utilisant le simple nom en string que tu as enregistré plus tôt. Le driver intercepte ce nom, récupère les paramètres regroupés qui y sont liés, et les applique à cette request spécifique. Ta query d'interface utilisateur est strictement plafonnée à une seconde, et le background job tourne tranquillement pendant trente secondes. Les deux queries s'exécutent simultanément, multiplexées sur exactement la même session et exactement le même connection pool. Déplacer ta configuration dans des Execution Profiles découple le comportement de ta query de ta connexion physique à la base de données. Ça permet à une seule application de modeler dynamiquement son trafic de base de données en fonction des besoins spécifiques de chaque fonction, sans jamais avoir besoin d'établir des sessions séparées. Merci d'avoir passé ce moment avec moi. J'espère que tu as appris quelque chose de nouveau.
6

Prepared Statements

2m 52s

Apprenez à exécuter des commandes CQL depuis Python. Nous abordons les requêtes simples et les avantages critiques en termes de performances liés à l'utilisation des Prepared Statements pour les requêtes fréquentes.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apache Cassandra avec Python, épisode 6 sur 12. Si tu utilises un simple string formatting pour tes requêtes à haut débit, tu forces ta base de données à brûler de précieux cycles CPU en re-parsant exactement la même structure des milliers de fois par seconde. Le moyen d'arrêter ce gaspillage, et d'améliorer considérablement les performances de ton application, c'est d'utiliser les Prepared Statements. Quand tu te connectes à Cassandra, la façon la plus directe d'interagir avec la base de données, c'est de passer une string à la méthode session point execute. Tu lui passes une query, et elle te retourne un result set. Par défaut, chaque ligne de ce résultat revient sous la forme d'un namedtuple Python. Ça veut dire que tu peux accéder aux valeurs de tes colonnes en utilisant une simple dot notation, comme row point name ou row point age. C'est propre, et ça marche bien pour des opérations ponctuelles. Mais envoyer une raw string est très inefficace pour les queries que tu lances constamment. Tu penses peut-être que tu fais déjà les choses bien si tu utilises des paramètres positionnels. Si tu passes une query string qui contient des marqueurs pourcent s avec une séquence de valeurs, le driver Python formate cette query de manière sécurisée. Ça empêche les attaques par injection, mais architecturalement, ça ne change rien aux performances. Tu envoies toujours la query string complète sur le réseau à Cassandra à chaque fois. Cassandra doit toujours recevoir le texte, parser la syntaxe, et calculer le query plan depuis zéro. Voici le point clé. Tu n'as pas besoin de parser la même structure deux fois. C'est là qu'intervient la méthode session point prepare. Au lieu d'exécuter la query immédiatement, tu passes ta query string à la méthode prepare. Dans cette string, tu remplaces les valeurs dynamiques par des points d'interrogation. Le driver envoie ce template à Cassandra. Cassandra le parse, le valide, calcule le plan d'exécution le plus efficace, puis génère un identifiant unique pour ce statement spécifique. Elle renvoie cet ID à ton application Python. À partir de ce moment-là, chaque fois que tu as besoin de lancer cette query, ton application n'envoie pas de string. Elle bind tes variables spécifiques à l'objet prepared statement et n'envoie que l'ID unique avec les raw bytes des valeurs. Pense à un service d'authentification à fort trafic. Tu dois chercher un utilisateur par son ID pendant le login. La query c'est select star from users where user id égal point d'interrogation. Si ton service gère dix mille logins par seconde, envoyer la query string complète dix mille fois gaspille de la bande passante réseau et du CPU de la base de données. En préparant le statement une seule fois quand ton application démarre, tu réduis considérablement le network payload. Cassandra voit l'ID, récupère instantanément le plan d'exécution précalculé, et extrait les données immédiatement. Les Prepared Statements déplacent le gros du travail de parsing de la query, d'une taxe récurrente par requête à un coût de setup unique. C'est tout pour cet épisode. À la prochaine !
7

Pagination des requêtes volumineuses

3m 03s

Ne faites jamais planter votre application en chargeant un ensemble de données massif en mémoire. Découvrez comment le driver Python pagine automatiquement les résultats des requêtes volumineuses et comment gérer les fetch sizes.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apache Cassandra avec Python, épisode 7 sur 12. Tu exécutes une simple select query sur une table massive, et soudain ton application plante avec une erreur out-of-memory. Ou du moins, c'est ce qui se passerait si ton driver de base de données essayait de tout charger d'un coup. Au lieu de ça, le driver gère ça en douceur en arrière-plan. Aujourd'hui, on parle du paging des grandes requêtes. Quand tu exécutes une requête avec le driver Python pour Cassandra, il n'essaie pas de charger des millions de lignes dans la mémoire de ton application. Par défaut, le driver fait automatiquement le paging des résultats, en récupérant exactement 5000 lignes à la fois. Le result set qu'il te renvoie se comporte comme un iterator Python standard. Pendant que tu boucles sur les lignes, le driver interroge la base de données de manière transparente pour récupérer le batch suivant juste avant que tu sois à court. Ton code ressemble exactement à une boucle standard, mais en dessous, le driver garantit la sécurité de la mémoire en ne gardant qu'une seule page de données en mémoire à un instant donné. Tu n'es pas bloqué avec la valeur par défaut de 5000 lignes. Tu peux contrôler ça en définissant la propriété fetch size sur ton objet statement avant de le passer à la méthode execute. Si tu réduis le fetch size à 100, le driver gardera moins de données en mémoire, mais fera des allers-retours réseau plus fréquents vers la base de données. Ne confonds pas ce mécanisme avec la pagination SQL traditionnelle qui utilise les commandes limit et offset. La pagination SQL avec offset force la base de données à scanner et à ignorer des lignes avant de renvoyer tes données, ce qui devient de plus en plus lent à mesure que tu avances dans les pages. Cassandra utilise une approche basée sur un curseur. Le driver utilise un marqueur interne pour suivre l'emplacement physique exact dans la base de données où la dernière lecture s'est terminée. Le paging automatique est parfait pour le traitement de données en background, mais ça ne marche pas pour construire des applications web stateless. Prends l'exemple d'un endpoint web qui fournit une liste à défilement continu de milliers de logs d'audit à une interface utilisateur. Tu ne peux pas garder une connexion à la base de données et un iterator actif ouverts sur ton serveur en attendant que l'utilisateur scrolle. Tu as besoin d'un moyen d'arrêter la requête, de fermer la request et de la reprendre plus tard. Voici le point clé. Le driver fournit une propriété sur le result set appelée le paging state. C'est une byte string opaque qui représente la position exacte du curseur de ta requête. Pour construire une API stateless, tu exécutes une requête, tu récupères une seule page de logs d'audit, et tu récupères ce paging state. Tu convertis les bytes en une simple hex string et tu l'envoies à ton frontend avec les données. Quand l'utilisateur scrolle tout en bas de l'interface, le frontend renvoie cette même hex string à ton serveur. Ton backend décode la string et la passe à la méthode execute comme paramètre paging state. Cassandra reprend instantanément la requête exactement là où elle s'était arrêtée. Utiliser le paging state te permet de déconnecter la durée de vie en mémoire de ton application de la taille massive de tes tables de base de données, ce qui te permet de streamer des données infinies aux clients en utilisant une quantité strictement finie de RAM sur le serveur. C'est tout pour aujourd'hui. Merci d'avoir écouté, et continue de développer !
8

Requêtes asynchrones à haut débit

3m 44s

Maximisez le débit de votre application. Apprenez à utiliser execute_async, les ResponseFutures et les callbacks pour exécuter des requêtes concurrentes vers Cassandra.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apache Cassandra avec Python, épisode 8 sur 12. Attendre une réponse de la base de données avant d'envoyer ta requête suivante est le moyen le plus simple de brider ta propre application. Si ton script Python reste inactif pendant les allers-retours réseau, tu passes à côté d'énormes performances en écriture. Pour corriger ça, tu as besoin de requêtes async à haut débit. Quand tu utilises la méthode execute standard sur une session Cassandra, ton code bloque. Il envoie la requête, attend que la base de données la traite, et attend que le réseau ramène la réponse. Pour un pipeline d'ingestion de données, ce temps d'inactivité est fatal pour ton throughput global. Pour débloquer la vraie vitesse, le driver Python DataStax propose la méthode execute async. D'abord, on doit dissiper une confusion courante. Si tu entends le mot async en Python, tu penses probablement au module asyncio de la standard library et aux mots-clés async await. Ce n'est pas ça. Le driver Cassandra s'appuie sur sa propre event loop légère qui tourne dans un background thread. Quand tu appelles execute async, tu utilises le mécanisme custom du driver, et pas les fonctionnalités asynchrones natives de Python. Quand tu passes une requête à execute async, il n'attend pas de réponse de la base de données. Il rend le contrôle à ton programme instantanément. Ce qu'il te renvoie, c'est un objet appelé ResponseFuture. Cet objet est une promise. Il représente une opération de base de données qui a été envoyée au cluster mais qui n'est pas encore terminée. Comme ton main thread n'est plus en attente, tu as besoin d'un moyen de savoir quand la requête se termine vraiment ou si elle échoue. Tu gères ça en attachant des callbacks directement au ResponseFuture. D'abord, tu définis une fonction de succès qui prend le result set comme argument. Ensuite, tu définis une fonction d'erreur qui prend une exception comme argument. Enfin, tu lies ces deux fonctions à la future en utilisant une méthode add callbacks. Quand la base de données répond, le background thread reçoit le paquet réseau et déclenche automatiquement la bonne fonction. Voici l'idée clé. Ce mécanisme te permet de pipeliner des centaines d'opérations simultanément. Prends l'exemple d'un pipeline IoT qui reçoit des centaines de relevés de température par seconde. En utilisant la méthode synchrone, tu traites un relevé, tu attends la base de données, puis tu traites le suivant. En utilisant execute async, tu boucles sur tes relevés entrants sans t'arrêter. Pour chaque relevé, tu lances une requête d'insert, tu récupères le ResponseFuture, tu attaches tes callbacks de succès et d'erreur, et tu passes immédiatement au relevé suivant. Tu pousses des centaines de requêtes sur le réseau en une fraction de seconde. Le driver multiplexe ces requêtes sur tes connexions de base de données existantes. Le cluster Cassandra les gère en parallèle et te streame les résultats en retour. Tes callbacks de succès et d'erreur se déclenchent à mesure que les réponses arrivent, de manière complètement indépendante de l'ordre dans lequel tu les as envoyées. Cette approche augmente considérablement ton throughput parce qu'elle superpose le temps d'attente réseau pour toutes ces requêtes. Tu n'es limité que par ta bande passante réseau et la capacité de la base de données, plutôt que d'être limité par le thread blocking. Tu dois quand même garder une trace du nombre de requêtes que tu as in flight pour ne pas surcharger la queue du driver, mais le principe de base est de garder le pipeline réseau plein. La chose la plus importante à retenir ici, c'est que le throughput de la base de données consiste à minimiser le temps d'inactivité, et en utilisant massivement execute async avec des callbacks attachés, tu forces ton application à passer son temps à pousser des données au lieu d'attendre sur le réseau. Si tu as trouvé ça utile et que tu veux soutenir l'émission, tu peux chercher DevStoriesEU sur Patreon. C'est tout pour cet épisode. Merci pour ton écoute, et continue à développer !
9

Lightweight Transactions

3m 13s

Implémentez des opérations compare-and-set en toute sécurité. Apprenez comment les Lightweight Transactions (LWTs) fonctionnent dans Cassandra et comment inspecter la colonne spécialisée applied dans vos résultats Python.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apache Cassandra avec Python, épisode 9 sur 12. Dans un système distribué sans global locks, deux utilisateurs essaient d'enregistrer exactement le même username à la milliseconde près. Comment tu garantis qu'un seul d'entre eux l'obtienne vraiment ? Le mécanisme qui résout ça s'appelle une Lightweight Transaction. Avant de t'expliquer comment les implémenter, on doit clarifier le nom. Une Lightweight Transaction dans Cassandra n'est pas une transaction ACID multi-tables classique. Tu ne peux pas ouvrir un bloc de transaction, écrire dans trois tables différentes, et faire un rollback de tout si une étape échoue. Une Lightweight Transaction est strictement limitée à une seule partition. C'est une opération conditionnelle, en gros un compare and set distribué. Pour réserver un username unique sans race conditions, tu écris une requête insert standard, mais tu ajoutes la clause spécifique IF NOT EXISTS à la fin. Cassandra va vérifier dans le cluster si cette partition key existe déjà. Si elle est absente, le write passe. Pour une opération d'update, tu utilises la clause IF suivie d'un nom de colonne et d'une valeur attendue. Tu peux demander à la base de données de faire un update sur le statut d'un compte uniquement IF le statut actuel correspond à une string spécifique. Exécuter ces requêtes depuis Python demande de gérer la réponse différemment d'un write normal. Un write standard dans Cassandra soit réussit silencieusement, soit lève une erreur de timeout. Mais quand tu ajoutes une clause IF, la base de données doit dire à ton application si la condition a vraiment été remplie. Le driver Python gère ça en renvoyant un result set spécialisé. Quand tu exécutes une Lightweight Transaction, la première row des données renvoyées contient une colonne système booléenne spéciale. Le driver expose cette colonne sous le nom applied, entouré de crochets. Tu exécutes ta requête insert et tu récupères la première row du résultat. Tu évalues ensuite cette colonne crochet applied crochet. Si tu récupères des dictionary rows depuis le driver, tu accèdes à la clé comme à une string. Si la valeur est évaluée à true, la condition a été remplie, et ton nouvel utilisateur a bien réservé le username. L'opération est terminée. Voici le point clé. Tu dois comprendre exactement ce qui se passe quand cette colonne crochet applied crochet est évaluée à false. Si l'insert échoue parce que le username est déjà pris, Cassandra ne se contente pas de renvoyer un simple flag de rejet. Le driver remplit la result row avec les données réelles qui ont fait échouer ta condition. Parce que ta condition a été rejetée, la base de données lit la row existante et la renvoie à ton application Python dans la même réponse. Tu reçois le flag applied à false, et avec, tu reçois l'état actuel du record en conflit. Si tu essayais de faire un update sur un solde basé sur un solde précédent attendu, tu récupères immédiatement le solde actuel réel. Ton code Python sait exactement quelles données ont bloqué la transaction, ce qui élimine complètement le besoin de lancer une requête select de suivi pour savoir pourquoi le write a été rejeté. Les Lightweight Transactions te donnent un contrôle de concurrence strict au niveau de la partition, et le driver Python rend ça super efficace en te fournissant gratuitement le blocking state chaque fois qu'une condition échoue. Merci d'avoir écouté. Prenez soin de vous, tout le monde.
10

Les modèles de l'Object Mapper

3m 53s

Évitez les chaînes CQL brutes et modélisez vos données à l'aide de classes Python. Apprenez à utiliser cqlengine pour définir des tables, spécifier des primary keys et synchroniser votre schéma.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apache Cassandra avec Python, épisode 10 sur 12. Écrire des strings CQL brutes directement dans le code de ton application Python peut vite devenir un bazar ingérable. Tu te retrouves avec des strings multilignes pleines d'interpolation de variables, ce qui rend les fautes de frappe faciles et le refactoring de schéma très pénible. Tu as besoin d'un moyen de représenter tes tables de base de données comme des objets Python natifs. C'est exactement ce qu'offrent les Models de l'Object Mapper. Le driver Python de Datastax inclut un object mapper appelé cqlengine. Il te permet de définir des tables Cassandra en utilisant des classes Python standards. Si tu as déjà utilisé Django ORM ou SQLAlchemy, la syntaxe va te paraître très familière. Mais il y a une différence majeure à clarifier tout de suite. Dans ces mappers relationnels, tu déclares des foreign keys pour lier les tables entre elles. Cassandra n'est pas une base de données relationnelle, donc les liaisons relationnelles n'existent tout simplement pas ici. Un model dans cqlengine mappe exactement à une table Cassandra indépendante. Créons un model Comment pour une application photo. On veut regrouper tous les commentaires d'une photo spécifique, et on veut qu'ils soient triés chronologiquement. D'abord, tu crées une classe Python appelée Comment qui hérite de la classe de base Model de cqlengine. À l'intérieur de cette classe, tu définis tes colonnes comme des attributs de classe. On commence avec l'attribut photo underscore id. Tu l'assignes à un type de colonne UUID et tu passes l'argument primary underscore key égal True. Comme c'est la toute première primary key que tu déclares dans la classe, cqlengine l'assigne automatiquement comme partition key. Ensuite, on a besoin d'un moyen d'identifier de façon unique et d'ordonner chaque commentaire au sein de cette partition de photo. Tu définis un deuxième attribut appelé comment underscore id. Tu l'assignes à un type de colonne TimeUUID, et tu passes aussi primary underscore key égal True. C'est là que ça devient intéressant. Dans cqlengine, toute primary key définie après la partition key devient automatiquement une clustering key. Tu n'as pas besoin d'un bloc de configuration de clustering spécial. L'ordre littéral, de haut en bas, dans lequel tu définis les attributs de colonne à l'intérieur de ta classe Python dicte la structure de la primary key dans Cassandra. Une fois que les primary keys sont définies, tu ajoutes les colonnes de données réelles. Tu définis un attribut body et tu lui assignes un type de colonne Text. Ce sont juste des données normales, donc aucun argument de primary key n'est nécessaire. Maintenant, tu as une classe Python déclarative qui décrit le schéma de ta table. Mais la table n'existe pas encore dans ta base de données. Pour pousser ce schéma vers Cassandra, tu utilises une fonction appelée sync underscore table. Tu passes ta classe de model Comment directement dans cette fonction. Le mapper lit la structure de ta classe, la traduit en un statement CQL brut correct, et l'exécute. Si la table n'existe pas, sync underscore table la crée. Si la table existe déjà, elle vérifie si tu as ajouté de nouvelles colonnes à ta classe Python et modifie la table pour qu'elle corresponde. Il est important de savoir que sync underscore table ne va jamais drop de données ou modifier les primary keys existantes, gardant ainsi la structure de tes données de base en sécurité pendant les mises à jour. La vraie puissance de définir des models de cette façon n'est pas juste de cacher la syntaxe de la base de données, mais de verrouiller la définition de ton schéma directement dans la couche applicative où se trouve la logique métier. C'est tout pour cet épisode. Merci d'avoir écouté, et continue de développer !
11

Faire des requêtes avec cqlengine

3m 30s

Récupérez et filtrez les données de manière fluide à l'aide des objets QuerySet dans le cqlengine Object Mapper. Nous abordons les opérateurs de filtrage, l'immuabilité et les limites de tri.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apache Cassandra avec Python, épisode 11 sur 12. Filtrer les enregistrements d'une base de données avec un object mapper, c'est généralement super simple, ça te permet de chercher par n'importe quel champ. Mais dans Cassandra, si tu essaies de filtrer sur une colonne qui n'est pas explicitement indexée ou qui ne fait pas partie d'une primary key, la base de données refusera tout simplement d'exécuter ta query. La solution, c'est de comprendre comment construire des queries valides, ce qui nous amène à faire des queries avec cqlengine. Dans cqlengine, quand tu veux récupérer des données d'un modèle, tu interagis avec un QuerySet. Si tu as un modèle qui représente une table de base de données, tu peux accéder aux enregistrements en appelant l'attribut objects suivi de la méthode all. Ça te retourne un QuerySet qui représente chaque ligne de cette table. Récupérer toutes les lignes, c'est rarement ce que tu veux dans une base de données distribuée, donc tu as besoin d'un moyen de restreindre les résultats. Pour restreindre les données retournées, tu utilises la méthode filter. Un point de confusion fréquent ici, c'est la façon dont ce filtrage se passe réellement. Les développeurs qui viennent d'autres frameworks supposent parfois que l'object mapper rapatrie toutes les données dans le client Python et filtre la liste en mémoire. C'est complètement faux. La méthode filter correspond directement à une clause WHERE stricte en CQL. Ça veut dire que les colonnes que tu passes à la méthode filter doivent respecter les règles de query de Cassandra. Tu peux uniquement filtrer sur des partition keys, des clustering columns, ou des colonnes avec un secondary index. Si tu essaies de filtrer sur un champ texte standard non indexé, cqlengine ne va pas cacher l'erreur ou la traiter localement. Il va passer la query directement à Cassandra, et Cassandra va la rejeter. Prenons un scénario concret. Tu as un modèle Automobile et tu veux trouver toutes les voitures de la marque Tesla fabriquées après l'année 2012. Tu commences par appeler objects point filter. Tu passes le keyword argument manufacturer défini sur la string Tesla. Pour gérer la condition sur l'année, cqlengine fournit des opérateurs de filtrage spéciaux. Tu les appliques en ajoutant un double underscore et une abréviation d'opérateur directement au nom de la colonne. Pour strictement supérieur à, tu utilises double underscore g t. Donc tu ajoutes un deuxième keyword argument à ton appel filter : year double underscore g t égal 2012. Le mapper traduit ça sans problème en une query CQL valide. Il y a plusieurs autres opérateurs disponibles pour différentes conditions. Si tu voulais vérifier des modèles de voitures spécifiques au lieu d'une année, tu pourrais utiliser l'opérateur double underscore in. Tu passerais model double underscore in, défini sur une liste Python contenant les noms Model S et Model 3. La base de données va retourner les enregistrements qui correspondent à n'importe quelle valeur de cette liste. Voici le point essentiel. Les QuerySets sont complètement immuables. Quand tu appelles la méthode filter sur un QuerySet existant, ça ne modifie pas cet objet sur place. À la place, ça retourne un tout nouveau QuerySet avec les filtres supplémentaires appliqués. Tu peux créer un QuerySet de base qui filtre uniquement sur le constructeur Tesla et l'assigner à une variable. Ensuite, tu peux utiliser cette seule variable pour générer plusieurs QuerySets filtrés différents pour différentes années ou modèles, juste en appelant à nouveau filter sur la variable de base. La query de base originale reste complètement inchangée. Parce que les QuerySets sont immuables, tu peux construire programmatiquement des queries complexes et très spécifiques, étape par étape, en réutilisant en toute sécurité des conditions de base à travers ton application avant même qu'un appel réseau ne soit fait. Merci d'avoir écouté. J'espère que tu as appris quelque chose de nouveau.
12

Vector Search pour l'IA

3m 45s

Préparez l'avenir de vos compétences avec le Vector Search de Cassandra 5.0. Découvrez comment stocker et interroger des vecteurs à haute dimension pour propulser les applications modernes d'IA et d'apprentissage automatique.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apache Cassandra avec Python, épisode 12 sur 12. Les Large Language Models changent notre façon de développer des applications, mais ils posent un défi majeur en matière de stockage. Quand un modèle d'intelligence artificielle a besoin de contexte, les requêtes de base de données traditionnelles échouent parce qu'elles cherchent des correspondances exactes de caractères, passant complètement à côté de l'intention réelle derrière un prompt. Les workloads modernes d'intelligence artificielle exigent une approche fondamentalement différente pour interroger les données. C'est là qu'intervient le Vector Search, introduit nativement dans Cassandra 5.0. C'est facile de confondre le Vector Search avec une simple recherche lexicale full-text. Un index full-text standard, comme Lucene, est strictement basé sur les mots-clés. Si un utilisateur cherche l'expression database backup dans ta base de données, une recherche lexicale va scanner ces strings exactes. Le Vector Search fonctionne différemment. Au lieu de mots-clés littéraux, les vecteurs capturent le sens sémantique sous-jacent des données. Un Vector Search comprend que sauvegarder un snapshot de données ou archiver des tables correspond exactement au même concept qu'un backup de base de données, même si les mots n'ont aucune lettre en commun. Pour que ça marche, Cassandra s'appuie sur les vector embeddings. Un embedding est un array de nombres à virgule flottante généré par un modèle de machine learning. Ces arrays servent de coordonnées mathématiques qui représentent le sens profond de ton texte. Tu stockes ces arrays directement dans Cassandra, avec les données standard de ton application. Quand tu as besoin de trouver du contenu pertinent dans d'immenses collections de documents, tu fais un Vector Search. La base de données compare le vecteur de la requête entrante aux vecteurs stockés dans tes tables. Elle calcule la distance mathématique entre eux. Plus la distance est courte, plus la similarité sémantique est forte. Imagine que tu crées un chatbot interne pour une grande équipe d'ingénieurs. Tu as des milliers de pages de documentation technique. Un ingénieur tape une question pour savoir comment décommissionner un cluster de staging. D'abord, ton application passe cette question à un modèle d'embedding, qui traduit la phrase en un array de floats. Ensuite, tu envoies cet array numérique à Cassandra sous forme de requête de Vector Search. Cassandra scanne instantanément l'espace multidimensionnel et récupère les documents internes dont les embeddings sont les plus proches de la question. Elle renvoie le bon manuel pour mettre hors service les environnements de test, parce que le sens sémantique correspond parfaitement, malgré les différences de terminologie. Cette fonctionnalité est conçue spécifiquement pour les applications d'intelligence artificielle. La plupart de ces applications s'appuient sur la récupération d'un contexte très pertinent pour alimenter le modèle de langage avant qu'il ne génère une réponse. En intégrant le Vector Search directement dans Cassandra 5.0, tu élimines le besoin de faire tourner une base de données vectorielle distincte et autonome. Tu conserves tes enregistrements opérationnels principaux et leurs embeddings sémantiques dans la même architecture distribuée, en t'appuyant sur la haute disponibilité et le scaling offerts par Cassandra. Puisque ça conclut notre série sur Apache Cassandra, je t'encourage à explorer la documentation officielle et à essayer de générer des embeddings pour tes propres données. Si tu as des suggestions sur les technologies qu'on devrait aborder ensuite, va sur devstories dot eu et dis-le-nous. Le Vector Search comble le fossé entre le langage et le stockage, transformant l'intention humaine complexe en un problème de géométrie que Cassandra peut résoudre à grande échelle. C'est tout pour cet épisode. Merci d'avoir écouté, et continue de développer !