web-dev-qa-db-fra.com

Quelle est la meilleure pratique pour concevoir un modèle de données Cassandra?

Et quels sont les pièges à éviter? Y a-t-il des pauses pour vous? Par exemple, j'ai entendu dire que l'exportation/l'importation des données Cassandra est très difficile, je me demande si cela va entraver la synchronisation des données de production dans l'environnement de développement.

BTW, il est très difficile de trouver de bons tutoriels sur Cassandra, le seul que j'ai http://arin.me/code/wtf-is-a-supercolumn-cassandra-data-model est toujours joli de base.

Merci.

63
Jerry

Pour moi, l'essentiel est de décider d'utiliser le OrderedPartitioner ou le RandomPartitioner.

Si vous utilisez le RandomPartitioner, les analyses de plage ne sont pas possibles. Cela signifie que vous devez connaître la clé exacte de toute activité, Y COMPRIS LE NETTOYAGE DES DONNÉES ANCIENNES.

Donc, si vous avez beaucoup de désabonnement, à moins que vous ayez un moyen magique de savoir exactement pour quelles clés vous avez inséré des trucs, en utilisant le partitionneur aléatoire, vous pouvez facilement "perdre" des trucs, ce qui provoque une fuite d'espace disque et finira par consommer tout le stockage.

D'un autre côté, vous pouvez demander au partitionneur commandé "quelles clés ai-je dans la famille de colonnes X entre A et B"? - et ça vous le dira. Vous pouvez ensuite les nettoyer.

Cependant, il y a aussi un inconvénient. Comme Cassandra ne fait pas d'équilibrage de charge automatique, si vous utilisez le partitionneur ordonné, selon toute vraisemblance, toutes vos données finiront dans un ou deux nœuds et aucun dans les autres, ce qui signifie que vous va gaspiller des ressources.

Je n'ai pas de réponse simple à cela, sauf que vous pouvez obtenir "le meilleur des deux mondes" dans certains cas en mettant une valeur de hachage courte (de quelque chose que vous pouvez énumérer facilement à partir d'autres sources de données) au début de vos clés - pour par exemple un hachage hexadécimal de 16 bits de l'ID utilisateur - qui vous donnera 4 chiffres hexadécimaux, suivis de la clé que vous vouliez vraiment utiliser.

Ensuite, si vous aviez une liste d'utilisateurs récemment supprimés, vous pouvez simplement hacher leurs identifiants et analyser la plage pour nettoyer tout ce qui les concerne.

Le bit le plus délicat est les index secondaires - Cassandra n'en a pas - donc si vous devez rechercher X par Y, vous devez insérer les données sous les deux clés ou avoir un pointeur. De même, ces pointeurs peuvent avoir besoin d'être nettoyés lorsque la chose vers laquelle ils pointent n'existe pas, mais il n'y a pas de moyen facile d'interroger des choses sur cette base, votre application doit donc juste se souvenir.

Et les bogues d'application peuvent laisser des clés orphelines que vous avez oubliées, et vous n'aurez aucun moyen de les détecter facilement, à moins que vous n'écriviez un ramasse-miettes qui analyse périodiquement chaque clé de la base de données (cela va prendre un certain temps - mais vous pouvez le faire en morceaux) pour vérifier ceux qui ne sont plus nécessaires.

Rien de tout cela n'est basé sur une utilisation réelle, juste ce que j'ai découvert pendant la recherche. Nous n'utilisons pas Cassandra en production.

EDIT: Cassandra a maintenant des index secondaires dans le tronc.

41
MarkR

C'était trop long pour ajouter un commentaire, donc pour clarifier certaines idées fausses de la réponse à la liste des problèmes:

  1. Tout client peut se connecter à n'importe quel nœud; si le premier nœud que vous choisissez (ou auquel vous vous connectez via un équilibreur de charge) tombe en panne, connectez-vous simplement à un autre. De plus, une API "gros client" est disponible où le client peut diriger les écritures lui-même; un exemple est sur http://wiki.Apache.org/cassandra/ClientExamples

  2. La temporisation lorsqu'un serveur ne répond pas plutôt que de se bloquer indéfiniment est une fonctionnalité que la plupart des gens qui ont traité avec des systèmes rdbms surchargés ont souhaité. Le délai Cassandra RPC est configurable; si vous le souhaitez, vous êtes libre de le régler sur plusieurs jours et de gérer la suspension indéfiniment à la place. :)

  3. Il est vrai qu'il n'y a pas encore de support de suppression multiple ou de troncature, mais il y a des correctifs pour les deux en cours de révision.

  4. Il y a évidemment un compromis à maintenir la charge équilibrée entre les nœuds de cluster: plus vous essayez de garder les choses parfaitement équilibrées, plus vous ferez de mouvements de données, ce qui n'est pas gratuit. Par défaut, les nouveaux nœuds d'un cluster Cassandra se déplaceront vers la position optimale dans l'anneau à jetons pour minimiser les irrégularités. En pratique, il a été démontré que cela fonctionne bien et plus votre cluster est grand est, moins il est vrai que le doublement est optimal. Ceci est couvert plus en http://wiki.Apache.org/cassandra/Operations

17
jbellis

Y a-t-il des pauses pour vous? Pas forcément des disjoncteurs mais quelque chose à savoir

  1. Un client se connecte à un nœud le plus proche, adresse qu'il doit connaître à l'avance, toutes les communications avec tous les autres nœuds Cassandra mandatés à travers lui. A. Le trafic de lecture/écriture n'est pas réparti également entre les nœuds - certains nœuds proxy plus de données que l'hôte lui-même b. Si le nœud tombe en panne, le client est impuissant, ne peut pas lire, ne peut écrire nulle part dans le cluster.

  2. Bien que Cassandra prétend que "les écritures échouent", elles échouent, du moins au moment où elles parlent. Si le nœud de données cible devient lent, la demande expire et l'écriture échoue. Il existe de nombreux raison pour laquelle un nœud ne répond plus: le garbage collector entre en action, le processus de compactage, peu importe… Dans tous ces cas, toutes les demandes d'écriture/lecture échouent. Dans une base de données conventionnelle, ces demandes seraient devenues proportionnellement lentes, mais en Cassandra ils échouent.

  3. Il y a multi-get mais pas de multi-suppression et on ne peut pas non plus tronquer ColumnFamily

  4. Si un nouveau nœud de données vide entre dans le cluster, une partie des données d'un nœud voisin sur le trousseau de clés sera transférée uniquement. Cela entraîne une répartition inégale des données et une charge inégale. Vous pouvez y remédier en doublant toujours le nombre de nœuds, il faut également garder une trace manuelle des jetons et les sélectionner judicieusement.

7
Igor Katkov
7
Alice

Je pense que cela mérite une mise à jour depuis Cassandra 1.2 est sorti récemment.

J'utilise Cassandra en production depuis 18 mois pour les jeux sociaux.

Mon bien est que vous devez utiliser Cassandra pour ses points forts. Donc une bonne compréhension de quoi et comment il est nécessaire de voir quel modèle de données utiliser ou même d'identifier si une autre solution de base de données est plus utile pour vous.

OrderedPartitioner n'est utile que si votre application s'appuie sur des requêtes de plage clés, MAIS vous abandonnez l'une des fonctionnalités les plus puissantes de Cassandra pour cela: partitionnement et équilibrage de charge automatiques. Au lieu de requêtes de plage de clés de ligne, essayez d'implémenter la même fonctionnalité dont vous avez besoin en utilisant des plages de noms de colonnes dans la même ligne. TL; DR read/l'écriture NE SERA PAS équilibrée entre les nœuds utilisant ceci.

RandomPartioner (hachage md5) et MurmurPartitioner (hachage Murmur, meilleur et plus rapide ) sont la voie que vous DEVEZ emprunter si vous souhaitez prendre en charge les mégadonnées et les fréquences d'accès élevées. La seule chose à laquelle vous renoncez est les requêtes de plage clés. Tout ce qui se trouve dans la même ligne se trouve toujours sur le même nœud dans le cluster et vous pouvez utiliser les requêtes de plage de noms de comparateur et de colonne sur celles-ci. TL; DR: UTILISEZ-LE pour un ÉQUILIBRAGE APPROPRIÉ, vous n'abandonnerez rien de majeur.


Ce que vous devez savoir sur la cassandre:

Cassandra est ÉVENTUELLEMENT cohérente. Cassandra a choisi d'échanger la cohérence pour une haute disponibilité et un excellent partitionnement ( http://en.wikipedia.org/wiki/CAP_theorem ). MAIS vous pouvez obtenir une cohérence à partir de cassandra, tout dépend de vous Politique de cohérence lorsque vous lisez et écrivez dessus. C'est un sujet assez important et complexe lorsque vous parlez d'utiliser cassandra mais vous pouvez le lire en détail ici - http://www.datastax.com/docs/1.2/dml/data_consistency .

En règle générale (et pour faire simple), je lis et j'écris sur QUORUM ConsistencyLevel (car dans mes applications, les lectures ont tendance à être du même ordre de fréquence que les écritures). Si votre application est extrêmement lourde en écriture et que les lectures se produisent beaucoup moins souvent, utilisez alors write at ONE et read at ALL. Ou si votre cas d'utilisation est le contraire (les écritures sont beaucoup moins fréquentes que les lectures), vous pouvez essayer de lire sur UN et d'écrire sur TOUS. L'utilisation de ANY comme niveau de cohérence pour les écritures n'est pas une bonne idée si la cohérence est ce que vous essayez de résoudre, car elle garantit que la mutation a atteint le cluster mais pas qu'elle a été écrite n'importe où. C'est le seul cas où j'ai obtenu des écritures pour échouer en silence sur cassandra.

Ce sont des règles simples pour faciliter le démarrage du développement cassandra. Pour obtenir autant de cohérence et de performances que possible à partir d'un cluster de production, vous devez étudier ce sujet attentivement et vraiment le comprendre vous-même.

Si vous avez besoin d'un modèle de données lisible par l'homme avec des relations complexes entre Entités (tables), je ne pense pas que Cassandra est pour vous. MySQL et peut-être NewSQL pourraient être plus utiles pour votre cas d'utilisation.

Une bonne chose à savoir est de savoir comment, en gros, cassandra enregistre et lit les données. Chaque fois que vous écrivez (les suppressions sont en fait des écritures d'une valeur "tombstone" dans cassandra), le système mettra la nouvelle valeur et son horodatage dans un nouvel emplacement physique.

Lorsque vous lisez, cassandra essaie de tirer toutes les écritures pour un certain emplacement clé/nom_colonne et vous renvoie le plus récent qu'il a pu trouver (celui avec l'horodatage le plus élevé, qui a été donné par le Ainsi, la mémoire nécessaire à un nœud dépend directement des fréquences d'écriture. Il existe un processus de compactage dans cassandra qui s'occupe du nettoyage des anciennes mutations. Cassandra possède un cache interne qui est mis à jour lors des lectures avec la dernière valeur de l'emplacement.

La fusion/compactage sur disque des SSTables (les structures de données qui conservent les données) peut être provoquée par des lectures, mais il vaut mieux ne pas compter dessus. Le nettoyage des pierres tombales et des colonnes expirées (en utilisant la fonctionnalité de durée de vie) est un mécanisme différent géré par le garbage collector (voir le paramètre de délai de grâce du GC pour plus de détails).


Cela m'amène au dernier point que je veux souligner: assurez-vous que vos écritures et vos lectures seront équilibrées dans votre cluster!

Supposons que tous vos utilisateurs doivent mettre à jour un emplacement unique très fréquemment.
NE mappez PAS cet emplacement théorique unique à une seule clé de ligne! Cela ferait tomber toutes vos écritures sur un seul nœud de votre cluster. S'il ne fait pas tout tomber (parce que vous avez des sysops rockstar), il paralysera au moins fortement les performances du cluster.
Mon conseil est de regrouper vos écritures dans suffisamment de clés de ligne différentes pour répartir vos écritures sur tous les nœuds du cluster. Pour récupérer toutes les données de cet emplacement théorique unique, utilisez un multi_get sur toutes les "clés de sous-ligne".

Exemple :
Je veux avoir une liste de toutes les sessions http actives (auxquelles uuid leur a été attribué). N'enregistrez pas tout dans une seule touche de ligne "session". Ce que j'utilise comme clé de ligne pour mon cassandra cluster de 6 nœuds est: _sessions. Ensuite, j'ai un petit multi_get de 16 clés pour récupérer toutes les sessions actives, ou je peux toujours dire si une session est actif en utilisant simplement un simple get (si je connais son uuid bien sûr). Si votre cluster est beaucoup plus grand, vous voudrez peut-être utiliser une fonction de hachage pour générer des clés de compartiment.