Approches de partitionnement MySQL?

88

Quelle est la meilleure approche pour le partage des tables MySQL. Les approches auxquelles je peux penser sont:

  1. Partage au niveau de l'application?
  2. Partage au niveau de la couche proxy MySQL?
  3. Serveur de recherche central pour le sharding?

Connaissez-vous des projets ou des outils intéressants dans ce domaine?

sheki
la source

Réponses:

115

La meilleure approche pour partager des tables MySQL est de ne pas le faire à moins qu'il ne soit totalement inévitable de le faire.

Lorsque vous écrivez une application, vous souhaitez généralement le faire d'une manière qui maximise la vitesse, la vitesse du développeur. Vous optimisez la latence (temps jusqu'à ce que la réponse soit prête) ou le débit (nombre de réponses par unité de temps) uniquement lorsque cela est nécessaire.

Vous partitionnez puis attribuez des partitions à différents hôtes (= shard) uniquement lorsque la somme de toutes ces partitions ne tient plus sur une seule instance de serveur de base de données - la raison en est soit des écritures, soit des lectures.

Le cas d'écriture est soit a) la fréquence des écritures surcharge les disques de ce serveur de façon permanente, soit b) il y a trop d'écritures en cours pour que la réplication soit en permanence en retard dans cette hiérarchie de réplication.

Le cas de lecture pour le partitionnement est lorsque la taille des données est si grande que l'ensemble de travail ne tient plus dans la mémoire et que les lectures de données commencent à frapper le disque au lieu d'être servies à partir de la mémoire la plupart du temps.

Ce n'est que lorsque vous devez fragmenter que vous le faites.


Au moment où vous fragmentez, vous payez pour cela de plusieurs façons:

Une grande partie de votre SQL n'est plus déclarative.

Normalement, en SQL, vous indiquez à la base de données quelles données vous voulez et laissez à l'optimiseur le soin de transformer cette spécification en un programme d'accès aux données. C'est une bonne chose, car c'est flexible et parce que l'écriture de ces programmes d'accès aux données est un travail ennuyeux qui nuit à la vitesse.

Avec un environnement partitionné, vous joignez probablement une table sur le nœud A contre des données sur le nœud B, ou vous avez une table plus grande qu'un nœud, sur les nœuds A et B et joignez les données de celui-ci avec les données qui se trouvent sur les nœuds B et C. Vous commencez à écrire manuellement des résolutions de jointure basées sur le hachage côté application afin de résoudre cela (ou vous réinventez le cluster MySQL), ce qui signifie que vous vous retrouvez avec beaucoup de SQL qui n'est plus déclaratif, mais qui exprime la fonctionnalité SQL de manière procédurale (par exemple, vous utilisez des instructions SELECT dans des boucles).

Vous subissez beaucoup de latence réseau.

Normalement, une requête SQL peut être résolue localement et l'optimiseur connaît les coûts associés aux accès au disque local et résout la requête d'une manière qui minimise les coûts pour cela.

Dans un environnement partitionné, les requêtes sont résolues soit en exécutant des accès clé-valeur sur un réseau à plusieurs nœuds (avec un peu de chance avec des accès clés par lots et non des recherches de clé individuelles par aller-retour) ou en poussant des parties de la WHEREclause vers les nœuds où elles peuvent être appliqué (c'est ce qu'on appelle «condition pushdown»), ou les deux.

Mais même dans le meilleur des cas, cela implique beaucoup plus d'allers-retours réseau qu'une situation locale, et c'est plus compliqué. D'autant plus que l'optimiseur MySQL ne sait rien du tout sur la latence du réseau (Ok, le cluster MySQL s'améliore lentement, mais pour MySQL vanille en dehors du cluster, c'est toujours vrai).

Vous perdez beaucoup de puissance expressive de SQL.

Ok, c'est probablement moins important, mais les contraintes de clé étrangère et autres mécanismes SQL pour l'intégrité des données sont incapables de couvrir plusieurs fragments.

MySQL n'a pas d'API qui autorise les requêtes asynchrones en ordre de marche.

Lorsque des données du même type résident sur plusieurs nœuds (par exemple, des données utilisateur sur les nœuds A, B et C), les requêtes horizontales doivent souvent être résolues sur tous ces nœuds ("Rechercher tous les comptes d'utilisateurs qui n'ont pas été connectés depuis 90 jours ou plus"). Le temps d'accès aux données augmente linéairement avec le nombre de nœuds, à moins que plusieurs nœuds ne puissent être demandés en parallèle et que les résultats soient agrégés au fur et à mesure qu'ils arrivent ("Map-Reduce").

La condition préalable pour cela est une API de communication asynchrone, qui n'existe pas pour MySQL en bon état de fonctionnement. L'alternative est beaucoup de bifurcations et de connexions dans les processus enfants, qui visitent le monde du sucer avec un abonnement de saison.


Une fois que vous commencez le partitionnement, la structure des données et la topologie du réseau deviennent visibles en tant que points de performance de votre application. Pour fonctionner raisonnablement bien, votre application doit être consciente de ces éléments, ce qui signifie qu'en réalité, seul le partitionnement au niveau de l'application a du sens.

La question est plus si vous souhaitez effectuer un partitionnement automatique (déterminer quelle ligne va dans quel nœud en hachant les clés primaires par exemple) ou si vous souhaitez fractionner fonctionnellement de manière manuelle ("Les tables liées à la user story xyz vont à ceci master, tandis que les tables liées abc et def vont à ce master ").

Le partitionnement fonctionnel a l'avantage que, s'il est bien fait, il est la plupart du temps invisible pour la plupart des développeurs, car toutes les tables liées à leur user story seront disponibles localement. Cela leur permet de continuer à bénéficier du SQL déclaratif aussi longtemps que possible, et entraînera également moins de latence du réseau car le nombre de transferts inter-réseaux est maintenu au minimum.

Le partitionnement fonctionnel présente l'inconvénient de ne pas permettre à une seule table d'être plus grande qu'une instance, et il nécessite l'attention manuelle d'un concepteur.

Le partitionnement fonctionnel a l'avantage d'être relativement facile à appliquer à une base de code existante avec un certain nombre de modifications qui ne sont pas trop importantes. http://Booking.com l' a fait plusieurs fois au cours des dernières années et cela a bien fonctionné pour eux.


Cela dit, en regardant votre question, je pense que vous posez les mauvaises questions, ou je ne comprends pas du tout votre énoncé de problème.

Isotopp
la source
2
C'est une bonne réponse. Mais je tiens à souligner que le sharding n'est vraiment nécessaire que pour les applications à volume élevé et qu'il y a de fortes chances qu'elles génèrent des revenus. Une application tierce de partitionnement gérera toutes les préoccupations que vous avez avec les jointures, les transactions entre partitions, etc. Et si vous en obtenez une bonne, elle maintiendra l'intégrité d'une base de données «relationnelle». D'autres applications, vous avez raison, transformeront simplement votre base de données en une paire clé-valeur et iront ainsi à l'encontre de l'objectif de SQL.
chantheman
3
Je n'ai pas encore rencontré d'application de partitionnement, commerciale ou non, qui réussisse à cacher le fait que les données sont maintenant dispersées sur le réseau et sujettes à une latence ou à une incohérence en raison du manque d'attentes induites par la latence. Si vous partitionnez, votre application le remarquera et nécessitera des modifications. Vous pourriez tout aussi bien en contrôler vous-même. Il n'y a pas de solution miracle, mais il y a beaucoup d'huile de serpent.
Isotopp
1
Vous devriez vérifier dbShards. Il évolue mieux que linéairement par le nombre de "fragments" que vous ajoutez. Vous aurez besoin de très peu de modifications, voire aucune, du côté de l'application, et oui, votre application ne connaît pas la différence. Il envoie et obtient simplement des transactions comme vous le feriez avec ODBC ou JDBC. dbShards autorise également les indications de partition si vous voulez plus de contrôle sur une transaction. Vous pouvez indiquer à dbShards exactement la partition à partir de laquelle vous voulez lire ou écrire.
chantheman
1
@Gigala Eh bien, passer du temps à composer une réponse bien définie comme celle-ci, quelle que soit sa portée, n'est pas non plus nécessaire, mais je suis heureux que cela ait été fait, car cette réponse s'est avérée utile pour moi. Veuillez ne pas décourager les utilisateurs de ne pas «sortir des sentiers battus» lorsqu'ils répondent.
mewm
12
  1. Partage au niveau de l'application: dbShards est le seul produit que je connaisse qui fasse du «partitionnement sensible aux applications». Il y a quelques bons articles sur le site. Par définition, le partitionnement prenant en charge les applications sera plus efficace. Si une application sait exactement où aller avec une transaction sans avoir à la rechercher ou à être redirigée par un proxy, cela en soi sera plus rapide. Et la vitesse est souvent l'une des principales préoccupations, sinon la seule, lorsque quelqu'un se penche sur le sharding.

  2. Certaines personnes "éclatent" avec un proxy, mais à mes yeux, cela va à l'encontre du but du partage. Vous utilisez simplement un autre serveur pour indiquer à vos transactions où trouver les données ou où les stocker. Grâce au partitionnement prenant en charge les applications, votre application sait par elle-même où aller. Beaucoup plus efficace.

  3. C'est vraiment la même chose que # 2.

chantheman
la source
dbShards est-il utilisé en production quelque part? ce n'est pas non plus open source.
sheki le
Les approches 2 et 3 peuvent également être différentes si le proxy recherche sur la base d'un hachage au lieu de la base de données ou d'un magasin.
sheki le
1
dbShards est en production avec une variété de clients, mais non, ce n'est pas open source. Je ne pense pas que vous trouverez un bon produit de partitionnement open source. Et oui, vous avez raison de dire qu'un hachage pourrait être utilisé comme une recherche, mais dans ce cas, vous devez encore faire un «arrêt» de plus pour obtenir votre transaction dans la base de données. C'est pourquoi le sharding "compatible avec les applications" sera presque toujours plus rapide.
chantheman
Mais comme je l'ai dit, si vous pouvez obtenir une application de partitionnement qui maintient l'intégrité des relations, vous serez en bonne forme. Je mentionne dbShards car c'est le seul que je connaisse à ce sujet. Et comme c'est le cas, il met à l'échelle vos vitesses d'écriture et de lecture de manière linéaire. Vous ajoutez 4 "fragments" ou vous divisez votre serveur MySQL en 4 et il fonctionnera 4 fois plus vite.
chantheman
7

Connaissez-vous des projets ou des outils intéressants dans ce domaine?

Plusieurs nouveaux projets dans cet espace:

  • citusdata.com
  • spockproxy.sourceforge.net
  • github.com/twitter/gizzard/
btcbb
la source
5

Shard-Query est une solution de partitionnement basée sur OLAP pour MySQL. Il vous permet de définir une combinaison de tables fragmentées et de tables non fragmentées. Les tables non éclatées (comme les tables de recherche) peuvent être jointes librement à des tables partitionnées, et les tables partitionnées peuvent être jointes les unes aux autres tant que les tables sont jointes par la clé de partition (pas de partition croisée ou d'auto-jointures qui traversent les limites de partition). Étant une solution OLAP, Shard-Query a généralement des temps de réponse minimum de 100 ms ou moins, même pour les requêtes simples, donc cela ne fonctionnera pas pour OLTP. Shard-Query est conçu pour analyser des ensembles de Big Data en parallèle.

Des solutions de partitionnement OLTP existent également pour MySQL. Les solutions de source fermée incluent ScaleDB , DBShards . Les solutions OLTP open source incluent JetPants , Cubrid ou Flock / Gizzard (infrastructure Twitter).

Justin Swanhart
la source
3

Niveau d'application bien sûr.

Meilleure approche que j'ai jamais trouvée dans ce livre

MySQL hautes performances http://www.amazon.com/High-Performance-MySQL-Jeremy-Zawodny/dp/0596003064

Brève description: vous pouvez diviser vos données en plusieurs parties et stocker environ 50 parties sur chaque serveur. Cela vous aidera à éviter le deuxième plus gros problème de sharding: le rééquilibrage. Déplacez simplement certains d'entre eux vers le nouveau serveur et tout ira bien :)

Je vous recommande fortement de l'acheter et de lire la partie "mysql scaling".

Andrey Frolov
la source
Le livre que vous avez recommandé a 8 ans ... couvre-t-il le sharding pertinent pour les technologies d'aujourd'hui?
raffian
1
Il couvre quelques approches de base pour mettre à l'échelle mysql. AFAIK rien n'a changé dans la mise à l'échelle de mysql. Les mêmes techniques de partitionnement et de réplication au niveau de l'application sont largement utilisées de nos jours.
Andrey Frolov
Je peux me tromper, mais j'ai fait une tonne de recherches à ce sujet au cours de la semaine dernière et il semble que mySQL lui-même a fait beaucoup de changements au cours des 8 dernières années, en particulier en ce qui concerne le partitionnement et la mise en cache. Une nouvelle version est sortie cette année: amazon.com/High-Performance-MySQL-Optimization-Replication/dp/ ... Je ne l'ai pas lu mais je pense qu'elle couvre les nouveaux modèles de réplication disponibles.
NateDSaint
4
Livres ... pourquoi ne pas simplement l'expliquer ici.
DDD
2

À partir de 2018, il semble y avoir une solution native MySql à cela. Il y en a en fait au moins 2 - InnoDB Cluster et NDB Cluster (il existe une version commerciale et une version communautaire).

Étant donné que la plupart des utilisateurs de l'édition communautaire MySql sont plus familiers avec le moteur InnoDB, c'est ce qui devrait être exploré en priorité. Il prend en charge la réplication et le partitionnement / partitionnement hors de la boîte et est basé sur MySql Router pour différentes options de routage / d'équilibrage de charge.

La syntaxe pour la création de vos tables devrait changer, par exemple:

    CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATETIME) PARTITION BY HASH ( YEAR(col3) );

(ce n'est que l'un des quatre types de partitionnement )

Une limitation très importante:

Les clés étrangères InnoDB et le partitionnement MySQL ne sont pas compatibles. Les tables InnoDB partitionnées ne peuvent pas avoir de références de clé étrangère, ni de colonnes référencées par des clés étrangères. Les tables InnoDB qui ont ou qui sont référencées par des clés étrangères ne peuvent pas être partitionnées.

yuranos
la source
Sachez que toutes les partitions PARTITION BY HASH(YEAR...)seront analysées si vous avez une plage de dates. Beurk.
Rick James