Cassandre. Comment ne pas mourir si l'on connaît seulement Oracle

Hé Habr.

Je m'appelle Misha Butrimov, je voudrais vous parler un peu de Cassandra. Mon histoire sera utile à ceux qui n'ont jamais rencontré de bases de données NoSQL - elle comporte de nombreuses fonctionnalités d'implémentation et pièges que vous devez connaître. Et si vous n’avez rien vu d’autre qu’Oracle ou toute autre base de données relationnelle, ces éléments vous sauveront la vie.

Qu'est-ce qu'il y a de si bien chez Cassandra ? Il s'agit d'une base de données NoSQL conçue sans point de défaillance unique et qui évolue bien. Si vous devez ajouter quelques téraoctets pour une base de données, vous ajoutez simplement des nœuds à l'anneau. L'étendre à un autre centre de données ? Ajoutez des nœuds au cluster. Augmenter le RPS traité ? Ajoutez des nœuds au cluster. Cela fonctionne également dans le sens inverse.

Cassandre. Comment ne pas mourir si l'on connaît seulement Oracle

Dans quoi d'autre est-elle douée ? Il s'agit de traiter beaucoup de demandes. Mais combien ça fait beaucoup ? 10, 20, 30, 40 100 requêtes par seconde, ce n'est pas grand-chose. 2 XNUMX requêtes par seconde pour l'enregistrement - également. Certaines entreprises déclarent conserver XNUMX millions de requêtes par seconde. Ils devront probablement y croire.

Et en principe, Cassandra a une grande différence par rapport aux données relationnelles : elle ne leur ressemble pas du tout. Et c’est très important à retenir.

Tout ce qui se ressemble ne fonctionne pas de la même manière

Un jour, un collègue est venu me voir et m'a demandé : « Voici un langage de requête CQL Cassandra, et il a une instruction select, il a où, il a et. J'écris des lettres et ça ne marche pas. Pourquoi?". Traiter Cassandra comme une base de données relationnelle est le moyen idéal de se suicider violemment. Et je n’en fais pas la promotion, c’est interdit en Russie. Vous allez simplement concevoir quelque chose de mal.

Par exemple, un client vient nous voir et nous dit : « Construisons une base de données pour les séries télévisées, ou une base de données pour un répertoire de recettes. Nous y proposerons des plats de nourriture ou une liste de séries télévisées et d’acteurs. On dit joyeusement : « Allons-y ! » Envoyez simplement deux octets, quelques signes et le tour est joué, tout fonctionnera très rapidement et de manière fiable. Et tout va bien jusqu'à ce que les clients viennent dire que les femmes au foyer résolvent également le problème inverse : elles ont une liste de produits et veulent savoir quel plat elles veulent cuisiner. Tu es mort.

En effet, Cassandra est une base de données hybride : elle fournit simultanément une valeur clé et stocke les données dans de larges colonnes. En Java ou Kotlin, cela pourrait être décrit ainsi :

Map<RowKey, SortedMap<ColumnKey, ColumnValue>>

C'est-à-dire une carte qui contient également une carte triée. La première clé de cette carte est la clé de ligne ou la clé de partition – la clé de partitionnement. La deuxième clé, qui est la clé d'une carte déjà triée, est la clé de clustering.

Pour illustrer la distribution de la base de données, dessinons trois nœuds. Vous devez maintenant comprendre comment décomposer les données en nœuds. Parce que si nous regroupons tout en un seul (d'ailleurs, il peut y en avoir mille, deux mille, cinq - autant que vous le souhaitez), il ne s'agit pas vraiment de distribution. Par conséquent, nous avons besoin d’une fonction mathématique qui renverra un nombre. Juste un nombre, un long entier qui se situera dans une certaine plage. Et nous aurons un nœud responsable d’une plage, le second de la seconde, le nième de la nième.

Cassandre. Comment ne pas mourir si l'on connaît seulement Oracle

Ce numéro est pris à l'aide d'une fonction de hachage, qui est appliquée à ce que nous appelons la clé de partition. Il s'agit de la colonne spécifiée dans la directive Clé primaire, et c'est la colonne qui sera la première et la plus basique clé de la carte. Il détermine quel nœud recevra quelles données. Une table est créée dans Cassandra avec presque la même syntaxe qu'en SQL :

CREATE TABLE users (
	user_id uu id,
	name text,
	year int,
	salary float,
	PRIMARY KEY(user_id)

)

La clé primaire dans ce cas se compose d’une colonne et constitue également la clé de partitionnement.

Quelles seront les performances de nos utilisateurs ? Certains iront vers un nœud, certains vers un autre et certains vers un troisième. Le résultat est une table de hachage ordinaire, également connue sous le nom de carte, également connue sous le nom de dictionnaire en Python, ou une simple structure de valeurs clés à partir de laquelle nous pouvons lire toutes les valeurs, lire et écrire par clé.

Cassandre. Comment ne pas mourir si l'on connaît seulement Oracle

Sélectionnez : quand autoriser le filtrage se transforme en analyse complète, ou quoi ne pas faire

Écrivons une instruction select : select * from users where, userid = . Cela se passe comme dans Oracle : on écrit select, on précise les conditions et tout fonctionne, les utilisateurs comprennent. Mais si vous sélectionnez, par exemple, un utilisateur avec une certaine année de naissance, Cassandra se plaint de ne pas pouvoir répondre à la demande. Parce qu'elle ne sait rien du tout sur la façon dont nous distribuons les données sur l'année de naissance - elle n'a qu'une seule colonne indiquée comme clé. Puis elle dit : « D'accord, je peux toujours répondre à cette demande. Ajoutez autoriser le filtrage." On ajoute la directive, tout fonctionne. Et à ce moment-là, quelque chose de terrible se produit.

Lorsque nous exécutons des données de test, tout va bien. Et lorsque vous exécutez une requête en production, où nous avons, par exemple, 4 millions d'enregistrements, alors tout ne va pas très bien pour nous. Parce que permettre le filtrage est une directive qui permet à Cassandra de collecter toutes les données de cette table à partir de tous les nœuds, de tous les centres de données (s'il y en a beaucoup dans ce cluster), et ensuite seulement de les filtrer. Il s'agit d'un analogue du Full Scan, et presque personne n'en est ravi.

Si nous n’avions besoin que d’utilisateurs par identifiant, cela nous conviendrait. Mais parfois, nous devons écrire d’autres requêtes et imposer d’autres restrictions sur la sélection. Par conséquent, rappelons-nous : tout cela est une carte qui a une clé de partitionnement, mais à l'intérieur se trouve une carte triée.

Et elle possède également une clé, que nous appelons la clé de clustering. Cette clé, qui, à son tour, est constituée des colonnes que nous sélectionnons, à l'aide desquelles Cassandra comprend comment ses données sont physiquement triées et seront situées sur chaque nœud. Autrement dit, pour certaines clés de partition, la clé de clustering vous indiquera exactement comment pousser les données dans cette arborescence, quelle place elles y occuperont.

Il s'agit en réalité d'un arbre, un comparateur y est simplement appelé, auquel nous transmettons un certain ensemble de colonnes sous la forme d'un objet, et il est également spécifié comme une liste de colonnes.

CREATE TABLE users_by_year_salary_id (
	user_id uuid,
	name text,
	year int,
	salary float,
	PRIMARY KEY((year), salary, user_id)

Faites attention à la directive Clé primaire ; son premier argument (dans notre cas, l'année) est toujours Clé de partition. Il peut être composé d'une ou plusieurs colonnes, cela n'a pas d'importance. S'il y a plusieurs colonnes, il faut à nouveau la supprimer entre parenthèses pour que le préprocesseur du langage comprenne qu'il s'agit de la clé primaire et que derrière elle, toutes les autres colonnes sont la clé de clustering. Dans ce cas, ils seront transmis dans le comparateur dans l'ordre dans lequel ils apparaissent. Autrement dit, la première colonne est plus significative, la seconde est moins significative, et ainsi de suite. La façon dont nous écrivons, par exemple, est égale aux champs pour les classes de données : nous listons les champs, et pour eux nous écrivons lesquels sont plus grands et lesquels sont plus petits. Dans Cassandra, ce sont, relativement parlant, les champs de la classe de données, auxquels seront appliqués les égaux écrits pour celle-ci.

Nous définissons le tri et imposons des restrictions

Vous devez vous rappeler que l'ordre de tri (décroissant, croissant, peu importe) est défini au même moment lors de la création de la clé et qu'il ne peut pas être modifié ultérieurement. Il détermine physiquement comment les données seront triées et comment elles seront stockées. Si vous devez modifier la clé de clustering ou l'ordre de tri, vous devrez créer une nouvelle table et y transférer des données. Cela ne fonctionnera pas avec un existant.

Cassandre. Comment ne pas mourir si l'on connaît seulement Oracle

Nous avons rempli notre tableau d'utilisateurs et avons vu qu'ils tombaient dans un anneau, d'abord par année de naissance, puis à l'intérieur de chaque nœud par salaire et ID utilisateur. Nous pouvons désormais sélectionner en imposant des restrictions.

Notre travail apparaît à nouveau where, and, et nous obtenons des utilisateurs, et tout va à nouveau bien. Mais si nous essayons d'utiliser seulement une partie de la clé de clustering, et une clé moins significative, alors Cassandra se plaindra immédiatement de ne pas trouver l'endroit sur notre carte où se trouve cet objet, qui a ces champs pour le comparateur nul, et celui-ci c'était juste réglé, - là où il repose. Je devrai récupérer à nouveau toutes les données de ce nœud et les filtrer. Et c'est un analogue du Full Scan au sein d'un nœud, c'est mauvais.

Dans toute situation peu claire, créez un nouveau tableau

Si nous voulons pouvoir cibler les utilisateurs par identifiant, par âge ou par salaire, que devons-nous faire ? Rien. Utilisez simplement deux tables. Si vous devez atteindre les utilisateurs de trois manières différentes, il y aura trois tableaux. Il est révolu le temps où nous économisions de l'espace sur la vis. C'est la ressource la moins chère. Cela coûte bien moins cher que le temps de réponse, ce qui peut être préjudiciable à l’utilisateur. Il est bien plus agréable pour l'utilisateur de recevoir quelque chose en une seconde qu'en 10 minutes.

Nous échangeons de l'espace inutile et des données dénormalisées contre la capacité d'évoluer correctement et de fonctionner de manière fiable. Après tout, en fait, un cluster composé de trois centres de données, chacun comportant cinq nœuds, avec un niveau de préservation des données acceptable (lorsque rien n'est perdu), est capable de survivre complètement à la mort d'un centre de données. Et deux nœuds supplémentaires dans chacun des deux autres. Et c’est seulement après cela que les problèmes commencent. Il s'agit d'une assez bonne redondance, qui vaut quelques disques SSD et processeurs supplémentaires. Par conséquent, pour utiliser Cassandra, qui n'est jamais SQL, dans lequel il n'y a pas de relations, de clés étrangères, vous devez connaître des règles simples.

Nous concevons tout selon votre demande. L'essentiel n'est pas les données, mais la manière dont l'application va fonctionner avec elles. S'il doit recevoir des données différentes de différentes manières ou les mêmes données de différentes manières, nous devons les présenter d'une manière qui convient à l'application. Sinon, nous échouerons dans l'analyse complète et Cassandra ne nous donnera aucun avantage.

La dénormalisation des données est la norme. On oublie les formulaires normaux, on n'a plus de bases de données relationnelles. Si nous posons quelque chose 100 fois, il se couchera 100 fois. C'est quand même moins cher que de s'arrêter.

Nous sélectionnons les clés à partitionner afin qu'elles soient distribuées normalement. Nous ne voulons pas que le hachage de nos clés tombe dans une plage étroite. Autrement dit, l’année de naissance dans l’exemple ci-dessus est un mauvais exemple. Plus précisément, c'est bien si nos utilisateurs sont normalement répartis par année de naissance, et mauvais si nous parlons d'élèves de 5e année - le cloisonnement n'y sera pas très bon.

Le tri est sélectionné une fois lors de l’étape de création de la clé de clustering. S'il doit être modifié, nous devrons mettre à jour notre table avec une clé différente.

Et le plus important : si nous devons récupérer les mêmes données de 100 manières différentes, alors nous aurons 100 tables différentes.

Source: habr.com

Ajouter un commentaire