Indexation Cassandra: Le Bon, le Mauvais et le Laid

Au sein de NoSQL, les opérations d’indexation, de récupération et de recherche d’informations sont intimement liées aux mécanismes de stockage physique. Il est important de se rappeler que les lignes sont stockées sur des hôtes, mais qu’une seule ligne est stockée sur un seul hôte. (avec les répliques) Les familles de colonnes sont stockées dans un ordre trié, ce qui rend l’interrogation d’un ensemble de colonnes efficace (à condition que vous couvriez des lignes).

Le Mauvais : Partitionnement

L’une des choses difficiles auxquelles il faut s’habituer au début est que sans index, les requêtes qui couvrent des lignes peuvent (très) être mauvaises. Cependant, en repensant à notre modèle de stockage, ce n’est pas surprenant. La stratégie utilisée par Cassandra pour répartir les lignes entre les hôtes s’appelle le partitionnement.

Le partitionnement est l’acte de découper la plage de clés de ligne en les affectant dans le « token ring », qui attribue également la responsabilité d’un segment (c’est-à-dire une partition) de la plage de clés de ligne à chaque hôte. Vous l’avez probablement vu lorsque vous avez initialisé votre cluster avec un « jeton ». Le jeton donne à l’hôte un emplacement le long de l’anneau à jetons, ce qui attribue la responsabilité d’une section de la plage de jetons. Le partitionnement est l’acte de mapper la clé de ligne dans la plage de jetons.

Il existe deux partitionneurs principaux: Aléatoire et Préservation de l’ordre. Ils sont nommés de manière appropriée. Le RandomPartitioner hache les clés de ligne en jetons. Avec le RandomPartitioner, le jeton est un hachage de la clé de ligne. Cela permet de répartir uniformément vos données sur un ensemble de nœuds, mais rend l’interrogation d’une plage de l’espace rowkey incroyablement difficile. À partir d’une valeur « start rowkey » et d’une valeur « end rowkey », Cassandra ne peut pas déterminer la plage de l’espace de jeton dont vous avez besoin. Il doit essentiellement effectuer une « analyse de table » pour répondre à la requête, et une « analyse de table » dans Cassandra est mauvaise car elle doit aller à chaque machine (très probablement TOUTES les machines si vous avez une bonne fonction de hachage) pour répondre à la requête.

Maintenant, au prix d’une distribution uniforme des données, vous pouvez utiliser le OrderPreservingPartitioner (OPP). Je ne suis * pas * avec OPP. L’OPP préserve l’ordre car il traduit les clés de ligne en jetons. Maintenant, étant donné une valeur de clé de ligne de début et une valeur de clé de ligne de fin, Cassandra * peut * déterminer exactement quels hôtes ont les données que vous recherchez. Il calcule la valeur de début à un jeton la valeur de fin à un jeton, et sélectionne et renvoie simplement tout le reste. MAIS, en préservant l’ordre, à moins que vos clés de ligne ne soient réparties uniformément dans l’espace, vos jetons ne le seront pas non plus et vous obtiendrez un cluster déséquilibré, ce qui augmente considérablement le coût de configuration et d’administration du cluster. (pas la peine)

Le bon: Index secondaires

Cassandra fournit un mécanisme d’indexation natif dans les index secondaires. Les index secondaires fonctionnent à partir des valeurs des colonnes. Vous déclarez un index secondaire sur une famille de colonnes. Datastax a une bonne documentation sur l’utilisation. Sous le capot, Cassandra maintient une « famille de colonnes cachées » comme index. (Voir la présentation d’Ed Anuff pour plus de détails) Puisque Cassandra ne conserve pas les informations de valeur de colonne dans un nœud et que les index secondaires sont sur la valeur des colonnes (plutôt que les clés de ligne), une requête doit toujours être envoyée à tous les nœuds. De plus, les index secondaires ne sont pas recommandés pour les ensembles à haute cardinalité. Je n’ai pas encore regardé, mais je suppose que c’est à cause du modèle de données utilisé dans la « famille de colonnes cachées ». Si la famille de colonnes masquées stocke une ligne par valeur unique (avec des clés de ligne en tant que colonnes), cela signifierait analyser les lignes pour déterminer si elles se trouvent dans la plage de la requête.
Extrait de la présentation d’Ed:

  • Non recommandé pour les valeurs de cardinalité élevées (c’est-à-dire les horodatages, les dates de naissance, les mots-clés, etc.)
  • Nécessite au moins une comparaison d’égalité dans une requêtenot pas génial pour les requêtes inférieures / supérieures à /range
  • Non triées – Les résultats sont dans l’ordre des jetons, pas l’ordre des valeurs de requête
  • Limité à la recherche sur les types de données, Cassandra comprend nativement

Cela dit, les index secondaires fonctionnent immédiatement et nous avons eu beaucoup de succès en les utilisant sur des valeurs simples.

Le moche : À faire soi-même (BRICOLAGE) / Rangées larges

Maintenant, la beauté est dans l’œil du spectateur. L’une des belles choses à propos de NoSQL est la simplicité. Les constructions sont simples : Espaces de clés, Familles de Colonnes, Lignes et Colonnes. Garder les choses simples signifie cependant parfois que vous devez prendre les choses en main.

C’est le cas des index à grandes lignes. En utilisant le modèle de stockage de Cassandra, il est facile de créer vos propres index où chaque clé de ligne devient une colonne dans l’index. C’est parfois difficile à comprendre, mais imaginons que nous ayons un cas dans lequel nous voulons sélectionner tous les utilisateurs dans un code postal. La famille de colonnes principale des utilisateurs est saisie sur l’ID utilisateur, le code postal est une colonne sur chaque ligne utilisateur. Nous pourrions utiliser des index secondaires, mais il y a pas mal de codes postaux. Au lieu de cela, nous pourrions maintenir une famille de colonnes avec une seule ligne appelée « idx_zipcode ». Nous pourrions alors écrire des colonnes dans cette ligne de la forme « zipcode_userid ». Étant donné que les colonnes sont stockées dans un ordre trié, il est rapide d’interroger toutes les colonnes qui commencent par « 18964 » (par exemple, nous pourrions utiliser 18964_ et 18964_ZZZZZZ comme valeurs de début et de fin).

Un inconvénient évident de cette approche est que les lignes sont autonomes sur un hôte. (encore une fois à l’exception des répliques) Cela signifie que toutes les requêtes vont frapper un seul nœud. Je n’ai pas encore trouvé de bonne réponse à cela.

De plus, et à mon humble avis, la partie la plus laide de l’indexation à grande rangée de BRICOLAGE est du point de vue du client. Dans notre implémentation, nous avons fait de notre mieux pour être indépendants de la langue côté client, permettant aux utilisateurs de choisir le meilleur outil pour le travail afin d’interagir avec les données de Cassandra. Avec cette mentalité, les indices de bricolage présentent des problèmes. Les lignes larges utilisent souvent des clés composites (imaginez si vous aviez un idx_state_zip, ce qui vous permettrait d’interroger par état puis zip). Bien qu’il existe un support  » natif » pour les clés composites, toutes les bibliothèques clientes en implémentent leur propre version (Hector, Astyanax et Thrift). Cela signifie que le client qui a besoin d’interroger des données doit avoir la logique ajoutée pour interroger d’abord l’index, et que tous les clients doivent en outre construire la clé composite de la même manière.

Pour L’Améliorer…

Pour cette raison même, nous avons décidé de publier deux projets open source qui aident à pousser cette logique côté serveur. Le premier projet est Cassandra-Triggers. Cela vous permet de joindre des activités asynchrones aux écritures dans Cassandra. (une de ces activités pourrait être l’indexation) Nous avons également publié Cassandra – Indexation. C’est chaud sur les presses et en est encore à ses balbutiements (par exemple, il ne prend en charge que les UT8Types dans l’index), mais l’intention est de fournir un mécanisme générique côté serveur qui indexe les données telles qu’elles sont écrites dans Cassandra. En utilisant la même technique côté serveur que nous avons utilisée dans l’indexation Cassandra, vous configurez simplement les colonnes que vous souhaitez indexer, et le code AOP fait le reste lorsque vous écrivez dans le CF cible. Comme toujours, les questions, commentaires et réflexions sont les bienvenus. (surtout si je suis quelque part hors de la base)

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.