MariaDB
 sql >> Base de données >  >> RDS >> MariaDB

Gestion de grands volumes de données avec MySQL et MariaDB

La plupart des bases de données grossissent avec le temps. La croissance n'est pas toujours assez rapide pour avoir un impact sur les performances de la base de données, mais il y a certainement des cas où cela se produit. Lorsque c'est le cas, nous nous demandons souvent ce qui pourrait être fait pour réduire cet impact et comment assurer le bon fonctionnement des bases de données lorsque nous traitons des données à grande échelle.

Essayons tout d'abord de définir ce que signifie un « grand volume de données » ? Pour MySQL ou MariaDB, il s'agit d'InnoDB non compressé. InnoDB fonctionne de manière à bénéficier fortement de la mémoire disponible - principalement le pool de mémoire tampon InnoDB. Tant que les données y tiennent, l'accès au disque est réduit à la gestion des écritures uniquement - les lectures sont servies à partir de la mémoire. Que se passe-t-il lorsque les données dépassent la mémoire ? De plus en plus de données doivent être lues à partir du disque lorsqu'il est nécessaire d'accéder à des lignes, qui ne sont pas actuellement mises en cache. Lorsque la quantité de données augmente, la charge de travail passe de l'UC à l'E/S. Cela signifie que le goulot d'étranglement n'est plus le CPU (ce qui était le cas lorsque les données tiennent en mémoire - l'accès aux données en mémoire est rapide, la transformation et l'agrégation des données est plus lent) mais plutôt le sous-système d'E/S (les opérations du CPU sur les données sont bien plus rapide que l'accès aux données à partir du disque.) Avec l'adoption accrue du flash, les charges de travail liées aux E/S ne sont plus aussi terribles qu'elles l'étaient à l'époque des disques en rotation (l'accès aléatoire est bien plus rapide avec le SSD), mais les performances sont toujours là. .

Une autre chose que nous devons garder à l'esprit est que nous ne nous soucions généralement que de l'ensemble de données actif. Bien sûr, vous pouvez avoir des téraoctets de données dans votre schéma, mais si vous n'avez accès qu'aux derniers 5 Go, c'est en fait une très bonne situation. Bien sûr, cela pose toujours des défis opérationnels, mais en termes de performances, cela devrait toujours être correct.

Supposons simplement pour les besoins de ce blog, et ce n'est pas une définition scientifique, que par grand volume de données, nous entendons le cas où la taille des données actives dépasse considérablement la taille de la mémoire. Il peut être de 100 Go lorsque vous avez 2 Go de mémoire, il peut être de 20 To lorsque vous avez 200 Go de mémoire. Le point de basculement est que votre charge de travail est strictement liée aux E/S. Restez avec nous pendant que nous discutons de certaines des options disponibles pour MySQL et MariaDB.

Partitionnement

L'approche historique (mais parfaitement valable) pour gérer de gros volumes de données consiste à implémenter le partitionnement. L'idée derrière cela est de diviser la table en partitions, une sorte de sous-tables. Le fractionnement se produit selon les règles définies par l'utilisateur. Examinons quelques exemples (les exemples SQL sont tirés de la documentation de MySQL 8.0)

MySQL 8.0 est fourni avec les types de partitionnement suivants :

  • GAMME
  • LISTE
  • COLONNES
  • HAS
  • CLÉ

Il peut également créer des sous-partitions. Nous n'allons pas réécrire la documentation ici, mais nous aimerions tout de même vous donner un aperçu du fonctionnement des partitions. Pour créer des partitions, vous devez définir la clé de partitionnement. Il peut s'agir d'une colonne ou, dans le cas de RANGE ou LIST, de plusieurs colonnes qui seront utilisées pour définir comment les données doivent être divisées en partitions.

Le partitionnement HASH nécessite que l'utilisateur définisse une colonne, qui sera hachée. Ensuite, les données seront divisées en un nombre de partitions défini par l'utilisateur en fonction de cette valeur de hachage :

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY HASH( YEAR(hired) )
PARTITIONS 4;

Dans ce cas, le hachage sera créé en fonction du résultat généré par la fonction YEAR() sur la colonne "embauché".

Le partitionnement KEY est similaire à l'exception que l'utilisateur définit quelle colonne doit être hachée et le reste est à la charge de MySQL.

Alors que les partitions HASH et KEY distribuent les données de manière aléatoire sur le nombre de partitions, RANGE et LIST permettent à l'utilisateur de décider quoi faire. RANGE est couramment utilisé avec l'heure ou la date :

CREATE TABLE quarterly_report_status (
    report_id INT NOT NULL,
    report_status VARCHAR(20) NOT NULL,
    report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) ) (
    PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-01-01 00:00:00') ),
    PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-04-01 00:00:00') ),
    PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-07-01 00:00:00') ),
    PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-10-01 00:00:00') ),
    PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-01-01 00:00:00') ),
    PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-04-01 00:00:00') ),
    PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-07-01 00:00:00') ),
    PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-10-01 00:00:00') ),
    PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2010-01-01 00:00:00') ),
    PARTITION p9 VALUES LESS THAN (MAXVALUE)
);

Il peut également être utilisé avec d'autres types de colonnes :

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT NOT NULL,
    store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
    PARTITION p0 VALUES LESS THAN (6),
    PARTITION p1 VALUES LESS THAN (11),
    PARTITION p2 VALUES LESS THAN (16),
    PARTITION p3 VALUES LESS THAN MAXVALUE
);

Les partitions LIST fonctionnent sur la base d'une liste de valeurs qui trie les lignes sur plusieurs partitions :

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY LIST(store_id) (
    PARTITION pNorth VALUES IN (3,5,6,9,17),
    PARTITION pEast VALUES IN (1,2,10,11,19,20),
    PARTITION pWest VALUES IN (4,12,13,14,18),
    PARTITION pCentral VALUES IN (7,8,15,16)
);

Quel est l'intérêt d'utiliser des partitions, me demanderez-vous ? Le point principal est que les recherches sont nettement plus rapides qu'avec une table non partitionnée. Supposons que vous souhaitiez rechercher les lignes qui ont été créées au cours d'un mois donné. Si vous avez plusieurs années de données stockées dans la table, ce sera un défi - un index devra être utilisé et, comme nous le savons, les index aident à trouver des lignes, mais l'accès à ces lignes entraînera un tas de lectures aléatoires à partir de tout le tableau. Si vous avez des partitions créées sur une base année-mois, MySQL peut simplement lire toutes les lignes de cette partition particulière - pas besoin d'accéder à l'index, pas besoin de faire des lectures aléatoires :lisez simplement toutes les données de la partition, séquentiellement, et nous sommes tout est prêt.

Les partitions sont également très utiles pour gérer la rotation des données. Si MySQL peut facilement identifier les lignes à supprimer et les mapper sur une seule partition, au lieu d'exécuter DELETE FROM table WHERE…, qui utilisera l'index pour localiser les lignes, vous pouvez tronquer la partition. Ceci est extrêmement utile avec le partitionnement RANGE - en suivant l'exemple ci-dessus, si nous voulons conserver les données pendant 2 ans seulement, nous pouvons facilement créer une tâche cron, qui supprimera l'ancienne partition et en créera une nouvelle vide pour le mois prochain.

Compression InnoDB

Si nous avons un grand volume de données (sans nécessairement penser aux bases de données), la première chose qui nous vient à l'esprit est de le compresser. Il existe de nombreux outils qui offrent une option pour compresser vos fichiers, réduisant considérablement leur taille. InnoDB a également une option pour cela - MySQL et MariaDB prennent en charge la compression InnoDB. Le principal avantage de l'utilisation de la compression est la réduction de l'activité d'E/S. Les données, lorsqu'elles sont compressées, sont plus petites et donc plus rapides à lire et à écrire. La page InnoDB typique a une taille de 16 Ko, pour le SSD, il s'agit de 4 opérations d'E/S à lire ou à écrire (le SSD utilise généralement des pages de 4 Ko). Si nous parvenons à compresser 16 Ko en 4 Ko, nous réduisons simplement les opérations d'E/S par quatre. Cela n'aide pas vraiment beaucoup en ce qui concerne le rapport ensemble de données / mémoire. En fait, cela peut même empirer les choses - MySQL, pour opérer sur les données, doit décompresser la page. Pourtant, il lit la page compressée à partir du disque. Cela se traduit par un pool de mémoire tampon InnoDB stockant 4 Ko de données compressées et 16 Ko de données non compressées. Bien sûr, il existe des algorithmes en place pour supprimer les données inutiles (la page non compressée sera supprimée dans la mesure du possible, en ne gardant qu'une seule compressée en mémoire), mais vous ne pouvez pas vous attendre à une trop grande amélioration dans ce domaine.

Il est également important de garder à l'esprit le fonctionnement de la compression en ce qui concerne le stockage. Les disques SSD sont la norme pour les serveurs de base de données de nos jours et ils ont quelques caractéristiques spécifiques. Ils sont rapides, peu leur importe que le trafic soit séquentiel ou aléatoire (même s'ils préfèrent toujours l'accès séquentiel à l'aléatoire). Ils sont chers pour de gros volumes. Ils souffrent d'« usure » car ils peuvent gérer un nombre limité de cycles d'écriture. La compression aide considérablement ici - en réduisant la taille des données sur le disque, nous réduisons le coût de la couche de stockage pour la base de données. En réduisant la taille des données que nous écrivons sur le disque, nous augmentons la durée de vie du SSD.

Malheureusement, même si la compression aide, pour de plus gros volumes de données, cela peut ne pas suffire. Une autre étape serait de chercher autre chose qu'InnoDB.

Mes Rochers

MyRocks est un moteur de stockage disponible pour MySQL et MariaDB qui est basé sur un concept différent d'InnoDB. Mon collègue, Sebastian Insausti, a un joli blog sur l'utilisation de MyRocks avec MariaDB. L'essentiel est, en raison de sa conception (il utilise Log Structured Merge, LSM), MyRocks est nettement meilleur en termes de compression qu'InnoDB (qui est basé sur la structure B + Tree). MyRocks est conçu pour gérer de grandes quantités de données et pour réduire le nombre d'écritures. Il provient de Facebook, où les volumes de données sont importants et les exigences pour accéder aux données sont élevées. Ainsi, le stockage SSD - toujours, à une si grande échelle, chaque gain de compression est énorme. MyRocks peut même offrir une compression jusqu'à 2 fois meilleure qu'InnoDB (ce qui signifie que vous réduisez le nombre de serveurs par deux). Il est également conçu pour réduire l'amplification des écritures (nombre d'écritures nécessaires pour gérer un changement du contenu des lignes) - il nécessite 10 fois moins d'écritures qu'InnoDB. Ceci, évidemment, réduit la charge d'E/S mais, plus important encore, cela augmentera la durée de vie d'un SSD de dix fois par rapport à la gestion de la même charge avec InnoDB). Du point de vue des performances, plus le volume de données est petit, plus l'accès est rapide. Ainsi, les moteurs de stockage comme celui-ci peuvent également aider à extraire les données de la base de données plus rapidement (même si ce n'était pas la priorité la plus élevée lors de la conception de MyRocks).

Magasins de données en colonnes

Ressources associées Gestion des performances de ClusterControl Comprendre les effets d'une latence élevée dans les solutions MySQL et MariaDB à haute disponibilité Aide-mémoire sur les performances MySQL

À un moment donné, tout ce que nous pouvons faire est d'admettre que nous ne pouvons pas gérer un tel volume de données avec MySQL. Bien sûr, vous pouvez le partager, vous pouvez faire différentes choses, mais finalement cela n'a plus de sens. Il est temps de chercher des solutions complémentaires. L'une d'entre elles consisterait à utiliser des magasins de données en colonnes - des bases de données conçues pour l'analyse de données volumineuses. Bien sûr, ils n'aideront pas avec le type de trafic OLTP, mais les analyses sont à peu près standard de nos jours, car les entreprises essaient d'être axées sur les données et de prendre des décisions basées sur des chiffres exacts, et non sur des données aléatoires. Il existe de nombreux magasins de données en colonnes, mais nous aimerions en mentionner ici deux. MariaDB AX et ClickHouse. Nous avons quelques blogs expliquant ce qu'est MariaDB AX et comment MariaDB AX peut être utilisé. Ce qui est important, MariaDB AX peut être mis à l'échelle sous la forme d'un cluster, améliorant ainsi les performances. ClickHouse est une autre option pour exécuter des analyses - ClickHouse peut facilement être configuré pour répliquer les données de MySQL, comme nous en avons discuté dans l'un de nos articles de blog. Il est rapide, gratuit et peut également être utilisé pour former un cluster et pour partitionner des données pour des performances encore meilleures.

Conclusion

Nous espérons que cet article de blog vous a donné un aperçu de la façon dont de gros volumes de données peuvent être traités dans MySQL ou MariaDB. Heureusement, il y a quelques options à notre disposition et, éventuellement, si nous ne pouvons pas vraiment le faire fonctionner, il existe de bonnes alternatives.