Contexte :
J'ai créé une application Web que j'aimerais pouvoir évoluer raisonnablement bien. Je sais que je ne suis pas Google ou Twitter, mais mon application utilise une quantité assez importante de données pour chaque utilisateur et a donc des exigences de données assez élevées. Je veux être prêt à évoluer raisonnablement bien sans avoir à tout ré-architecturer plus tard.
Je me considère comme un développeur de logiciels, pas un expert en bases de données. C'est pourquoi je poste ici. J'espère que quelqu'un avec beaucoup plus d'expertise en base de données pourra me donner des conseils.
Avec un nombre d'utilisateurs relativement important, mais rien de tel que les numéros Facebook, je m'attends à avoir une base de données qui ressemble à ceci:
Une "grande table":
- 250 millions d'enregistrements
- 20 colonnes
- Environ 100 Go de données
- Dispose d'une clé étrangère bigint indexée (20)
- A une colonne varchar (500) indexée string_id
- A une colonne int (11) "value"
4 autres tables:
- 10 millions d'enregistrements chacun
- Environ 2 à 4 Go de données chacun
- chacun de ces tableaux comprend 4 à 8 colonnes
- une colonne est datetime date_created
- une colonne est la colonne varchar (500) string_id
- une ou deux colonnes de chacune de ces tables seront sélectionnées dans une jointure
L'une de ces tables est utilisée pour stocker des moyennes - son schéma est bigint (20) id, varchar (20) string_id, datetime date_created, float average_value
Ce que je veux faire - deux requêtes relativement coûteuses:
Calculez de nouvelles valeurs moyennes:
- À l'aide d'une clé étrangère, sélectionnez jusqu'à plusieurs millions d'enregistrements distincts dans la grande table.
- Calculez une nouvelle moyenne, regroupée par string_id.
- Insérez les résultats dans le tableau des moyennes.
- Telle qu'elle est actuellement construite, cette requête utilise deux jointures.
Créez des enregistrements en lecture seule dénormalisés pour les utilisateurs au service:
- Utilisez une clé étrangère pour sélectionner entre 1 000 et 40 000 enregistrements dans la grande table.
- Joignez-vous à chacune des quatre autres tables de l'enregistrement le plus récent avec la colonne id chaîne.
- Insérez les résultats dans un tableau dénormalisé.
- Ces enregistrements sont destinés au front-end pour afficher des informations aux utilisateurs.
- Telle qu'elle est actuellement construite, cette requête utilise quatre jointures.
Je prévois d'exécuter chacune de ces requêtes coûteuses sur une base de données principale par lots qui transmettra ses résultats à un serveur de base de données frontal en temps réel qui gère les demandes des utilisateurs. Ces requêtes seront exécutées à intervalles réguliers. Je n'ai pas décidé combien de fois. La requête moyenne pourrait être effectuée peut-être une fois par jour. La requête de dénormalisation devra être plus fréquente, peut-être toutes les quelques minutes.
Chacune de ces requêtes s'exécute actuellement en quelques secondes dans MySQL sur une machine très bas de gamme avec un ensemble de données avec 100 000 enregistrements dans la «grande table». Je m'inquiète à la fois de ma capacité à évoluer et des coûts de l'évolutivité.
Questions :
- Cette approche semble-t-elle judicieuse? Y a-t-il quelque chose de mal à l'évidence du point de vue global?
- Un SGBDR est-il le bon outil, ou devrais-je envisager d'autres solutions de "big data" comme quelque chose dans la famille Hadoop? Mon inclination est d'utiliser un SGBDR car les données sont structurées et s'intègrent bien dans le modèle relationnel. À un certain moment cependant, je crois comprendre que je ne pourrai peut-être plus utiliser un SGBDR. Est-ce vrai? Quand ce commutateur serait-il nécessaire?
- Est-ce que ça marchera? Ces requêtes peuvent-elles être exécutées dans un délai raisonnable? Je peux attendre peut-être des heures pour la requête # 1, mais la requête # 2 devrait se terminer en quelques minutes.
- Que dois-je considérer du point de vue matériel? Quels sont les goulots d'étranglement RAM et CPU susceptibles d'être? Je suppose que la conservation des index dans la RAM est importante. Y a-t-il autre chose que je devrais considérer?
- À un moment donné, je devrai probablement partitionner mes données et utiliser plusieurs serveurs. Mon cas d'utilisation semble-t-il être déjà dans cette catégorie, ou vais-je être capable de faire évoluer une seule machine verticalement pendant un certain temps? Est-ce que cela fonctionnera avec 10 fois les données? 100x?
Réponses:
Avez-vous essayé d'empiler plus de données et de les comparer? 100K lignes est sans conséquence. Essayez 250M ou 500M comme si vous vous attendiez à devoir gérer et voir où se trouvent les goulots d'étranglement.
Un SGBDR peut faire beaucoup de choses si vous portez une attention particulière aux limites et essayez de travailler avec les points forts du système. Ils sont exceptionnellement bons dans certaines choses et terribles dans d'autres, vous devrez donc expérimenter pour vous assurer que c'est le bon ajustement.
Pour certains travaux de traitement par lots, vous ne pouvez vraiment pas battre des fichiers plats, charger les données dans la RAM, les écraser à l'aide d'une série de boucles et de variables temporaires et vider les résultats. MySQL ne pourra jamais, jamais égaler ce genre de vitesse, mais s'il est réglé correctement et utilisé correctement, il peut entrer dans un ordre de grandeur.
Ce que vous voudrez faire, c'est étudier comment vos données peuvent être partitionnées. Avez-vous un grand ensemble de données avec trop de liens croisés pour pouvoir le diviser, ou y a-t-il des endroits naturels pour le partitionner? Si vous pouvez le partitionner, vous n'aurez pas une table avec une pile entière de lignes, mais potentiellement beaucoup plus petites. Les tables plus petites, avec des index beaucoup plus petits, ont tendance à mieux fonctionner.
Du point de vue matériel, vous devrez tester pour voir comment votre plate-forme fonctionne. Parfois, la mémoire est essentielle. D'autres fois, il s'agit d'E / S disque. Cela dépend vraiment de ce que vous faites avec les données. Vous devrez faire très attention à l'utilisation de votre processeur et rechercher des niveaux élevés d'E / S pour savoir où se situe le problème.
Dans la mesure du possible, divisez vos données sur plusieurs systèmes. Vous pouvez utiliser MySQL Cluster si vous vous sentez courageux, ou simplement créer de nombreuses instances indépendantes de MySQL où chacune stocke une partie arbitraire de l'ensemble de données complet en utilisant un schéma de partitionnement qui a du sens.
la source
Tableaux récapitulatifs.
Chaque jour, calculez des informations agrégées pour les données de la journée. Mettez cela dans le (s) tableau (s) "récapitulatif (s)". Faites vos requêtes contre eux. 10 fois plus rapide.
Pour plus de discussion, veuillez fournir
Quelques choses évidentes ...
"Plus petit -> plus cacheable -> plus rapide
la source
Pour servir vos données frontales, à moins qu'il n'y ait des gobs et des gobs d'inserts tout le temps, vous ne pouvez vraiment pas battre en utilisant des déclencheurs pour insérer dans des vues matérialisées qui sont synchronisées avec le back-end mais optimisées pour servir les données. Bien sûr, vous devez réduire au minimum les jointures, etc., etc. dans ces déclencheurs. Une stratégie que j'ai utilisée consiste à mettre ces insertions / mises à jour en file d'attente dans une table intermédiaire, puis à les envoyer plus tard toutes les minutes environ. Il est beaucoup plus facile d'envoyer un enregistrement que 4 Go d'enregistrements. 4 Go de données prennent beaucoup de temps à diffuser même si vous pouvez trouver rapidement les enregistrements que vous recherchez.
Je suis d'accord avec Tadman. Le mieux est de le profiler avec le type de données que vous attendez sur le type de système que vous recherchez.
la source