Sysbench is een geweldig hulpmiddel om testgegevens te genereren en MySQL OLTP-benchmarks uit te voeren. Gewoonlijk zou men een cyclus voorbereiden, uitvoeren en opschonen uitvoeren bij het uitvoeren van een benchmark met Sysbench. Standaard is de door Sysbench gegenereerde tabel een standaard niet-partitie basistabel. Dit gedrag kan natuurlijk worden uitgebreid, maar je moet weten hoe je het in het LUA-script schrijft.
In deze blogpost laten we zien hoe je met Sysbench testgegevens kunt genereren voor een gepartitioneerde tabel in MySQL. Dit kan voor ons als een speeltuin worden gebruikt om verder te duiken in het oorzaak-gevolg van tabelpartitionering, gegevensdistributie en query-routing.
Single-server tabelpartitionering
Single-server-partitionering betekent simpelweg dat alle partities van de tabel zich op dezelfde MySQL-server/instance bevinden. Bij het maken van de tabelstructuur zullen we alle partities tegelijk definiëren. Dit soort partitionering is goed als je gegevens hebt die na verloop van tijd hun bruikbaarheid verliezen en die gemakkelijk uit een gepartitioneerde tabel kunnen worden verwijderd door de partitie (of partities) die alleen die gegevens bevat te verwijderen.
Maak het Sysbench-schema:
mysql> CREATE SCHEMA sbtest;
Maak de sysbench-databasegebruiker:
mysql> CREATE USER 'sbtest'@'%' IDENTIFIED BY 'passw0rd';
mysql> GRANT ALL PRIVILEGES ON sbtest.* TO 'sbtest'@'%';
In Sysbench zou men de opdracht --prepare gebruiken om de MySQL-server voor te bereiden met schemastructuren en rijen met gegevens te genereren. We moeten dit deel overslaan en de tabelstructuur handmatig definiëren.
Maak een gepartitioneerde tabel. In dit voorbeeld gaan we slechts één tabel maken met de naam sbtest1 en deze wordt gepartitioneerd door een kolom met de naam "k", wat in feite een geheel getal is tussen 0 en 1.000.000 (gebaseerd op de optie --table-size die we gaan gebruiken in de bewerking voor alleen invoegen later):
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
);
We gaan 2 partities hebben - De eerste partitie heet p1 en zal gegevens opslaan waarbij de waarde in kolom "k" lager is dan 499.999 en de tweede partitie, p2, zal de resterende waarden opslaan . We maken ook een primaire sleutel die beide belangrijke kolommen bevat - "id" is voor rij-ID en "k" is de partitiesleutel. Bij het partitioneren moet een primaire sleutel alle kolommen in de partitioneringsfunctie van de tabel bevatten (waar we "k" gebruiken in de range-partitiefunctie).
Controleer of de partities aanwezig zijn:
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 |
+--------------+------------+----------------+------------+
We kunnen dan een Sysbench-invoegbewerking starten, zoals hieronder:
$ 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
Kijk hoe de tabelpartities groeien terwijl Sysbench draait:
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 |
+--------------+------------+----------------+------------+
Als we het totale aantal rijen tellen met de COUNT-functie, komt dit overeen met het totale aantal rijen dat door de partities wordt gerapporteerd:
mysql> SELECT COUNT(id) FROM sbtest1;
+-----------+
| count(id) |
+-----------+
| 2665 |
+-----------+
Dat is het. We hebben een tafelpartitionering voor één server klaar waarmee we kunnen spelen.
Multi-server tabelpartitionering
Bij multi-server-partitionering gaan we meerdere MySQL-servers gebruiken om een subset van gegevens van een bepaalde tabel (sbtest1) fysiek op te slaan, zoals weergegeven in het volgende diagram:
We gaan 2 onafhankelijke MySQL-knooppunten implementeren - mysql1 en mysql2. De sbtest1-tabel wordt op deze twee knooppunten gepartitioneerd en we zullen deze partitie + host-combinatie een shard noemen. Sysbench draait op afstand op de derde server en bootst de applicatielaag na. Omdat Sysbench niet partitiebewust is, hebben we een databasestuurprogramma of router nodig om de databasequery's naar de juiste shard te routeren. We zullen ProxySQL gebruiken om dit doel te bereiken.
Laten we voor dit doel nog een nieuwe database maken met de naam sbtest3:
mysql> CREATE SCHEMA sbtest3;
mysql> USE sbtest3;
Verleen de juiste privileges aan de sbtest databasegebruiker:
mysql> CREATE USER 'sbtest'@'%' IDENTIFIED BY 'passw0rd';
mysql> GRANT ALL PRIVILEGES ON sbtest3.* TO 'sbtest'@'%';
Maak op mysql1 de eerste partitie van de tabel:
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)
);
In tegenstelling tot standalone partitionering, definiëren we alleen de voorwaarde voor partitie p1 in de tabel om alle rijen op te slaan met kolom "k"-waarden variërend van 0 tot 499.999.
Maak op mysql2 nog een gepartitioneerde tabel:
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
);
Op de tweede server moet deze de gegevens van de tweede partitie bevatten door de resterende verwachte waarden van kolom "k" op te slaan.
Onze tabelstructuur is nu klaar om te worden gevuld met testgegevens.
Voordat we de Sysbench-invoegbewerking kunnen uitvoeren, moeten we een ProxySQL-server installeren als de queryrouter en fungeren als gateway voor onze MySQL-shards. Sharding met meerdere servers vereist dat databaseverbindingen die van de toepassingen komen, naar de juiste shard worden gerouteerd. Anders zou u de volgende fout te zien krijgen:
1526 (Table has no partition for value 503599)
Installeer ProxySQL met ClusterControl, voeg de sbtest-databasegebruiker toe aan ProxySQL, voeg beide MySQL-servers toe aan ProxySQL en configureer mysql1 als hostgroep 11 en mysql2 als hostgroep 12:
Vervolgens moeten we werken aan hoe de query moet worden gerouteerd. Een voorbeeld van een INSERT-query die door Sysbench wordt uitgevoerd, ziet er ongeveer zo uit:
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')
We gaan dus de volgende reguliere expressie gebruiken om de INSERT-query voor "k" => 500000 te filteren, om aan de partitievoorwaarde te voldoen:
^INSERT INTO sbtest1 \(id, k, c, pad\) VALUES \([0-9]\d*, ([5-9]{1,}[0-9]{5}|[1-9]{1,}[0-9]{6,}).*
De bovenstaande uitdrukking probeert eenvoudig het volgende te filteren:
-
[0-9]\d* - We verwachten hier een auto-increment integer, dus matchen we met elk integer.
-
[5-9]{1,}[0-9]{5} - De waarde komt overeen met een willekeurig geheel getal van 5 als het eerste cijfer, en 0-9 voor de laatste 5 cijfers, om overeen te komen met de bereikwaarde van 500.000 tot 999.999.
-
[1-9]{1,}[0-9]{6,} - De waarde komt overeen met een willekeurig geheel getal van 1-9 als het eerste cijfer, en 0-9 voor de laatste 6 of grotere cijfers, om overeen te komen met de waarde van 1.000.000 en groter.
We zullen twee vergelijkbare zoekregels maken. De eerste vraagregel is de ontkenning van de bovenstaande reguliere expressie. We geven deze regel ID 51 en de bestemmingshostgroep moet hostgroep 11 zijn om overeen te komen met kolom "k" <500.000 en de query's door te sturen naar de eerste partitie. Het zou er zo uit moeten zien:
Let op het "Negate Match Pattern" in de bovenstaande schermafbeelding. Die optie is van cruciaal belang voor de juiste routering van deze queryregel.
Maak vervolgens nog een queryregel met regel-ID 52, gebruik dezelfde reguliere expressie en de bestemmingshostgroep moet 12 zijn, maar laat deze keer het "Negate Match Pattern" op false, zoals hieronder weergegeven:
We kunnen dan een invoegbewerking starten met Sysbench om testgegevens te genereren . De MySQL-toegangsgerelateerde informatie moet de ProxySQL-host zijn (192.168.11.130 op poort 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
Als u geen fout ziet, betekent dit dat ProxySQL onze query's naar de juiste shard/partitie heeft doorgestuurd. U zou moeten zien dat de zoekopdrachtregeltreffers toenemen terwijl het Sysbench-proces wordt uitgevoerd:
Onder de sectie Topquery's kunnen we de samenvatting van de queryrouting zien:
Om dubbel te controleren, logt u in op mysql1 om de eerste partitie te zoeken en controleert u de minimum- en maximumwaarde van kolom 'k' in tabel sbtest1:
mysql> USE sbtest3;
mysql> SELECT min(k), max(k) FROM sbtest1;
+--------+--------+
| min(k) | max(k) |
+--------+--------+
| 232185 | 499998 |
+--------+--------+
Ziet er goed uit. De maximale waarde van kolom "k" overschrijdt de limiet van 499.999 niet. Laten we eens kijken hoeveel rijen het voor deze partitie opslaat:
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 |
+--------------+------------+----------------+------------+
Laten we nu eens kijken naar de andere MySQL-server (mysql2):
mysql> USE sbtest3;
mysql> SELECT min(k), max(k) FROM sbtest1;
+--------+--------+
| min(k) | max(k) |
+--------+--------+
| 500003 | 794952 |
+--------+--------+
Laten we eens kijken hoeveel rijen het voor deze partitie opslaat:
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 |
+--------------+------------+----------------+------------+
Fantastisch! We hebben een shard MySQL-testopstelling met de juiste gegevenspartitionering met behulp van Sysbench waarmee we kunnen spelen. Veel plezier met benchmarken!