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

Utilisation de Sysbench pour générer des données de test pour une table fragmentée dans MySQL

Sysbench est un excellent outil pour générer des données de test et effectuer des benchmarks MySQL OLTP. Généralement, on ferait un cycle de préparation-exécution-nettoyage lors de l'exécution d'un benchmark à l'aide de Sysbench. Par défaut, la table générée par Sysbench est une table de base standard sans partition. Ce comportement peut être étendu, bien sûr, mais il faut savoir l'écrire dans le script LUA.

Dans cet article de blog, nous allons montrer comment générer des données de test pour une table partitionnée dans MySQL à l'aide de Sysbench. Cela peut être utilisé comme terrain de jeu pour nous permettre d'approfondir les causes et les effets du partitionnement des tables, de la distribution des données et du routage des requêtes.

Partitionnement de table sur un seul serveur

Le partitionnement sur un seul serveur signifie simplement que toutes les partitions de la table résident sur le même serveur/instance MySQL. Lors de la création de la structure de la table, nous définirons toutes les partitions à la fois. Ce type de partitionnement est bon si vous avez des données qui perdent de leur utilité au fil du temps et qui peuvent être facilement supprimées d'une table partitionnée en supprimant la partition (ou les partitions) contenant uniquement ces données.

Créez le schéma Sysbench :

mysql> CREATE SCHEMA sbtest;

Créez l'utilisateur de la base de données sysbench :

mysql> CREATE USER 'sbtest'@'%' IDENTIFIED BY 'passw0rd';
mysql> GRANT ALL PRIVILEGES ON sbtest.* TO 'sbtest'@'%';

Dans Sysbench, on utiliserait la commande --prepare pour préparer le serveur MySQL avec des structures de schéma et générer des lignes de données. Nous devons ignorer cette partie et définir la structure de la table manuellement.

Créer une table partitionnée. Dans cet exemple, nous allons créer une seule table appelée sbtest1 et elle sera partitionnée par une colonne nommée "k", qui est essentiellement un entier compris entre 0 et 1 000 000 (basé sur l'option --table-size que nous sommes utilisera ultérieurement dans l'opération d'insertion uniquement) :

mysql> CREATE TABLE `sbtest1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `k` int(11) NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`,`k`)
  )
  PARTITION BY RANGE (k) (
    PARTITION p1 VALUES LESS THAN (499999),
    PARTITION p2 VALUES LESS THAN MAXVALUE
  );

Nous allons avoir 2 partitions - La première partition est appelée p1 et stockera les données où la valeur dans la colonne "k" est inférieure à 499 999 et la seconde partition, p2, stockera les valeurs restantes . Nous créons également une clé primaire qui contient les deux colonnes importantes - "id" est pour l'identifiant de ligne et "k" est la clé de partition. Dans le partitionnement, une clé primaire doit inclure toutes les colonnes dans la fonction de partitionnement de la table (où nous utilisons "k" dans la fonction de partition de plage).

Vérifiez que les partitions sont là :

mysql> SELECT TABLE_SCHEMA, TABLE_NAME, PARTITION_NAME, TABLE_ROWS 
       FROM INFORMATION_SCHEMA.PARTITIONS 
       WHERE TABLE_SCHEMA='sbtest2' 
       AND TABLE_NAME='sbtest1';
+--------------+------------+----------------+------------+
| TABLE_SCHEMA | TABLE_NAME | PARTITION_NAME | TABLE_ROWS |
+--------------+------------+----------------+------------+
| sbtest       | sbtest1    | p1             |          0 |
| sbtest       | sbtest1    | p2             |          0 |
+--------------+------------+----------------+------------+

Nous pouvons ensuite démarrer une opération Sysbench d'insertion uniquement comme ci-dessous :

$ sysbench \
/usr/share/sysbench/oltp_insert.lua \
--report-interval=2 \
--threads=4 \
--rate=20 \
--time=9999 \
--db-driver=mysql \
--mysql-host=192.168.11.131 \
--mysql-port=3306 \
--mysql-user=sbtest \
--mysql-db=sbtest \
--mysql-password=passw0rd \
--tables=1 \
--table-size=1000000 \
run

Observez la croissance des partitions de table au fur et à mesure que Sysbench s'exécute :

mysql> SELECT TABLE_SCHEMA, TABLE_NAME, PARTITION_NAME, TABLE_ROWS 
       FROM INFORMATION_SCHEMA.PARTITIONS 
       WHERE TABLE_SCHEMA='sbtest2' 
       AND TABLE_NAME='sbtest1';
+--------------+------------+----------------+------------+
| TABLE_SCHEMA | TABLE_NAME | PARTITION_NAME | TABLE_ROWS |
+--------------+------------+----------------+------------+
| sbtest       | sbtest1    | p1             |       1021 |
| sbtest       | sbtest1    | p2             |       1644 |
+--------------+------------+----------------+------------+

Si on compte le nombre total de lignes à l'aide de la fonction COUNT, cela correspondra au nombre total de lignes rapporté par les partitions :

mysql> SELECT COUNT(id) FROM sbtest1;
+-----------+
| count(id) |
+-----------+
|      2665 |
+-----------+

C'est tout. Nous avons un partitionnement de table à serveur unique prêt avec lequel nous pouvons jouer.

Partitionnement de table multi-serveur

Dans le partitionnement multi-serveurs, nous allons utiliser plusieurs serveurs MySQL pour stocker physiquement un sous-ensemble de données d'une table particulière (sbtest1), comme illustré dans le schéma suivant :

Nous allons déployer 2 nœuds MySQL indépendants - mysql1 et mysql2. La table sbtest1 sera partitionnée sur ces deux nœuds et nous appellerons cette combinaison partition + hôte un shard. Sysbench s'exécute à distance sur le troisième serveur, imitant le niveau application. Étant donné que Sysbench n'est pas sensible aux partitions, nous avons besoin d'un pilote de base de données ou d'un routeur pour acheminer les requêtes de base de données vers le bon fragment. Nous utiliserons ProxySQL pour atteindre cet objectif.

Créons une autre nouvelle base de données appelée sbtest3 à cet effet :

mysql> CREATE SCHEMA sbtest3;
mysql> USE sbtest3;

Accordez les bons privilèges à l'utilisateur de la base de données sbtest :

mysql> CREATE USER 'sbtest'@'%' IDENTIFIED BY 'passw0rd';
mysql> GRANT ALL PRIVILEGES ON sbtest3.* TO 'sbtest'@'%';

Sur mysql1, créez la première partition de la table :

mysql> CREATE TABLE `sbtest1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `k` int(11) NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`,`k`)
  )
  PARTITION BY RANGE (k) (
    PARTITION p1 VALUES LESS THAN (499999)
  );

Contrairement au partitionnement autonome, nous définissons uniquement la condition pour la partition p1 dans la table afin de stocker toutes les lignes avec des valeurs de colonne "k" allant de 0 à 499 999.

Sur mysql2, créez une autre table partitionnée :

mysql> CREATE TABLE `sbtest1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `k` int(11) NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`,`k`)
  )
  PARTITION BY RANGE (k) (
    PARTITION p2 VALUES LESS THAN MAXVALUE
  );

Sur le deuxième serveur, il doit contenir les données de la deuxième partition en stockant le reste des valeurs anticipées de la colonne "k".

Notre structure de table est maintenant prête à être remplie avec des données de test.

Avant de pouvoir exécuter l'opération d'insertion uniquement Sysbench, nous devons installer un serveur ProxySQL en tant que routeur de requête et servir de passerelle pour nos partitions MySQL. Le partitionnement multiserveur nécessite que les connexions de base de données provenant des applications soient acheminées vers le bon fragment. Sinon, vous verriez l'erreur suivante :

1526 (Table has no partition for value 503599)

Installez ProxySQL à l'aide de ClusterControl, ajoutez l'utilisateur de base de données sbtest dans ProxySQL, ajoutez les deux serveurs MySQL dans ProxySQL et configurez mysql1 en tant que groupe d'hôtes 11 et mysql2 en tant que groupe d'hôtes 12 :

Ensuite, nous devons travailler sur la façon dont la requête doit être acheminée. Un exemple de requête INSERT qui sera exécutée par Sysbench ressemblera à ceci :

INSERT INTO sbtest1 (id, k, c, pad) 
  VALUES (0, 503502, '88816935247-23939908973-66486617366-05744537902-39238746973-63226063145-55370375476-52424898049-93208870738-99260097520', '36669559817-75903498871-26800752374-15613997245-76119597989')

Nous allons donc utiliser l'expression régulière suivante pour filtrer la requête INSERT pour "k" => 500000, afin de respecter la condition de partitionnement :

^INSERT INTO sbtest1 \(id, k, c, pad\) VALUES \([0-9]\d*, ([5-9]{1,}[0-9]{5}|[1-9]{1,}[0-9]{6,}).*

L'expression ci-dessus essaie simplement de filtrer les éléments suivants :

  • [0-9]\d* - Nous attendons ici un entier auto-incrémenté, donc nous comparons avec n'importe quel entier.

  • [5-9]{1,}[0-9]{5} - La valeur correspond à n'importe quel entier de 5 comme premier chiffre, et de 0 à 9 sur les 5 derniers chiffres, pour correspondre à la valeur de la plage de 500 000 à 999 999.

  • [1-9]{1,}[0-9]{6,} - La valeur correspond à n'importe quel entier de 1 à 9 comme premier chiffre, et de 0 à 9 sur les 6 derniers chiffres ou plus, pour correspondre à la valeur de 1 000 000 et plus.

Nous allons créer deux règles de requête similaires. La première règle de requête est la négation de l'expression régulière ci-dessus. Nous donnons à cette règle l'ID 51 et le groupe d'hôtes de destination doit être le groupe d'hôtes 11 pour correspondre à la colonne "k" <500 000 et transmettre les requêtes à la première partition. Cela devrait ressembler à ceci :

Faites attention au "Negate Match Pattern" dans la capture d'écran ci-dessus. Cette option est essentielle pour le routage correct de cette règle de requête.

Ensuite, créez une autre règle de requête avec l'ID de règle 52, en utilisant la même expression régulière et le groupe d'hôtes de destination doit être 12, mais cette fois, laissez le "Negate Match Pattern" sur false, comme indiqué ci-dessous :

Nous pouvons ensuite démarrer une opération d'insertion uniquement à l'aide de Sysbench pour générer des données de test . Les informations relatives à l'accès à MySQL doivent être l'hôte ProxySQL (192.168.11.130 sur le port 6033) :

$ sysbench \
/usr/share/sysbench/oltp_insert.lua \
--report-interval=2 \
--threads=4 \
--rate=20 \
--time=9999 \
--db-driver=mysql \
--mysql-host=192.168.11.130 \
--mysql-port=6033 \
--mysql-user=sbtest \
--mysql-db=sbtest3 \
--mysql-password=passw0rd \
--tables=1 \
--table-size=1000000 \
run

Si vous ne voyez aucune erreur, cela signifie que ProxySQL a acheminé nos requêtes vers le bon fragment/partition. Vous devriez voir que le nombre d'accès à la règle de requête augmente pendant l'exécution du processus Sysbench :

Sous la section Top Requêtes, nous pouvons voir le résumé du routage des requêtes :

Pour revérifier, connectez-vous à mysql1 pour rechercher la première partition et vérifiez la valeur minimale et maximale de la colonne 'k' sur la table sbtest1 :

mysql> USE sbtest3;
mysql> SELECT min(k), max(k) FROM sbtest1;
+--------+--------+
| min(k) | max(k) |
+--------+--------+
| 232185 | 499998 |
+--------+--------+

Ça a l'air génial. La valeur maximale de la colonne « k » ne dépasse pas la limite de 499 999. Vérifions le nombre de lignes qu'il stocke pour cette partition :

mysql> SELECT TABLE_SCHEMA, TABLE_NAME, PARTITION_NAME, TABLE_ROWS 
       FROM INFORMATION_SCHEMA.PARTITIONS 
       WHERE TABLE_SCHEMA='sbtest3' 
       AND TABLE_NAME='sbtest1';
+--------------+------------+----------------+------------+
| TABLE_SCHEMA | TABLE_NAME | PARTITION_NAME | TABLE_ROWS |
+--------------+------------+----------------+------------+
| sbtest3      | sbtest1    | p1             |       1815 |
+--------------+------------+----------------+------------+

Vérifions maintenant l'autre serveur MySQL (mysql2) :

mysql> USE sbtest3;
mysql> SELECT min(k), max(k) FROM sbtest1;
+--------+--------+
| min(k) | max(k) |
+--------+--------+
| 500003 | 794952 |
+--------+--------+

Vérifions le nombre de lignes qu'il stocke pour cette partition :

mysql> SELECT TABLE_SCHEMA, TABLE_NAME, PARTITION_NAME, TABLE_ROWS 
       FROM INFORMATION_SCHEMA.PARTITIONS 
       WHERE TABLE_SCHEMA='sbtest3' 
       AND TABLE_NAME='sbtest1';
+--------------+------------+----------------+------------+
| TABLE_SCHEMA | TABLE_NAME | PARTITION_NAME | TABLE_ROWS |
+--------------+------------+----------------+------------+
| sbtest3      | sbtest1    | p2             |       3247 |
+--------------+------------+----------------+------------+

Superbe! Nous avons une configuration de test MySQL partagée avec un partitionnement de données approprié à l'aide de Sysbench pour que nous puissions jouer avec. Bonne analyse comparative !