mysqlslap et supersmack, deux outils de benchmark pour MySQL

7 July 2008 par arnaud

Il est parfois reprochĂ© au serveur MySQL de ne pas fournir suffisamment d’outils de benchmark / profiling concernant les requĂȘtes ou le fonctionnement du serveur lui-mĂȘme. Des commandes telles que SHOW STATUS (affiche l’Ă©tat du serveur Ă  un instant t), ou bien encore EXPLAIN (plan d’exĂ©cution de la requĂȘte SQL) permettent nĂ©anmoins d’obtenir de prĂ©cieuses informations.

Ceci Ă©tant dit, comment s’assurer que son serveur MySQL tiendra la charge ? 1000 requĂȘtes /s en insertion sont prĂ©vues le jour de la sortie de votre prochain service internet : votre serveur sera t-il capable d’y faire face  ?

Les deux outils prĂ©sentĂ©s aujourd’hui permettent de simuler la charge reçue par le serveur MySQL en fonction de diffĂ©rentes paramĂštres dont le nombre de connexions simultanĂ©es et le nombre de requĂȘtes par utilisateurs. Avec de tels outils, vous pouvez par exemple tester mysqlslap sur une de vos requĂȘtes clĂ©, visualiser comment celle-ci rĂ©agit sous diffĂ©rentes configurations, et visualiser un “score” Ă  base de temps d’exĂ©cution. Une fois ce “score” rĂ©cupĂ©rĂ©, comparez-le avec celui que vous obtiendriez avec la mĂȘme requĂȘte modifiĂ©e par vos soins, avez-vous progressĂ© ?

mysqlslap

mysqlslap est un “client” du serveur MySQL au mĂȘme titre que “mysql” ou “mysqladmin” (autre client). Officiellement disponible depuis la version 5.1.4 de MySQL, il est nĂ©anmoins possible de faire fonctionner mysqlslap avec des versions moins avancĂ©es. Plusieurs astuces pour cela, en voici une, suivie d’une autre. Il y’a peut-ĂȘtre encore plus simple : sur ma version d’ubuntu la version 5.0.51 de MySQL est installĂ©e, le binaire de mysqlslap est absent mais il m’a suffit d’installer les binaires de la 5.1.25 dans un autre rĂ©pertoire pour exĂ©cuter mysqlslap via le serveur MySQL 5.0.51 en fonctionnement.

mysqlslap est trĂšs simple d’utilisation, parmi ses options les plus notables on trouve :

–auto-generate-sql : mysqlslap peut gĂ©nĂ©rer pour vous des requĂȘtes SQL alĂ©atoires. Pratique pour des tests rapides, il vaut mieux nĂ©anmoins soumettre vos propres requĂȘtes Ă  mysqlslap.
–query : permet d’utiliser vos propres requĂȘtes.
–concurrency : simule un nombre de clients qui se connectent simultanĂ©ment.
–iterations : … pour rĂ©pĂ©ter votre test n fois.
--number-of-queries : permet d’attribuer Ă  chaque client un nombre de requĂȘtes approximatifs.
–engine : spĂ©cifie le moteur de stockage Ă  utiliser lorsque vous laissez mysqlslap gĂ©nĂ©rer ses propres requĂȘtes.
–csv : pour gĂ©nĂ©rer les rĂ©sultats de vos tests au format csv.

Notes :
- Il est possible de spĂ©cifier plusieurs tests Ă  la suite en sĂ©parant par une virgule vos valeurs pour les paramĂštres “concurrency”, “iterations”, “engines”.
- mysqlslap recherche par dĂ©faut une base du nom de “mysqlslap”, crĂ©ez lĂ . Ma base mysqlslap Ă©tant vide, j’ai utilisĂ© l’instruction “USE world” afin de ne pas avoir Ă  deplacer mes tables de test existant dans la base “world”. Pour des benchmarks plus prĂ©cis, Ă©vitez d’utiliser cette commande et dĂ©placez vos tables dans la base mysqlslap.

mysqlslap en pratique

undercat@u200:/usr/local/mysql5125$ ./bin/mysqlslap –user=mysql –concurrency=200 –number-of-queries=1000 –iterations=10 –query=”USE world;SELECT SQL_NO_CACHE ci.name, co.name from City ci, Country co where ci.countrycode = co.code and ci.name like ‘c%’”

On obtient :

Benchmark
Average number of seconds to run all queries: 1.121 seconds
Minimum number of seconds to run all queries: 1.015 seconds
Maximum number of seconds to run all queries: 1.265 seconds
Number of clients running queries: 200
Average number of queries per client: 5

Nous avons ici 200 clients concurrents dont on limite le nombre de requĂȘtes Ă  1000 au total, ce qui nous donne environ 5 requĂȘtes par client.

En rajoutant la clause –csv et une concurrence variable :

undercat@u200:/usr/local/mysql5125$ ./bin/mysqlslap --user=mysql –csv=/tmp/slap.csv –concurrency=1,10,50,100,200 –iterations=10 --query="USE world;SELECT SQL_NO_CACHE ci.name, co.name from City ci, Country co where ci.countrycode = co.code and ci.name like 'c%'"

J’utilise ici SQL_NO_CACHE afin de ne pas placer la requĂȘte dans le query cache, ce qui fausserait les tests.

L’option –csv couplĂ© Ă  openoffice / impress par exemple, permet de crĂ©er rapidement un graphique issu de nos tests. Ci-dessous le csv gĂ©nĂ©rĂ© et le graphique  :

undercat@u200:/tmp$ cat slap.csv
,mixed,0.002,0.000,0.004,1,1
,mixed,0.015,0.011,0.027,10,1
,mixed,0.063,0.061,0.068,50,1
,mixed,0.133,0.122,0.205,100,1
,mixed,0.245,0.105,0.298,200,1


graphique issu d\'un csv mysqlslap

supersmack

Disponible sur http://vegan.net/tony/supersmack/, cet outil n’Ă©volue plus depuis trois ans mais il reste intĂ©ressant ! Initialement dĂ©veloppĂ© par Sasha Pachev (un ancien de chez MySQL), puis retouchĂ© par plusieurs autre contributeurs dont JĂ©remy Zawodny, supersmack est moins intuitif que mysqlslap mais il se rattrape par ailleurs puisqu’il est plus largement disponible (pas seulement sur MySQL 5) et offre des rĂ©glages plus fins. Il est notamment possible de construire dynamiquement une requĂȘte Ă  partir d’un “dictionnaire”… supersmack peut en effet “piocher” dans un fichier texte une liste d’identifiants par exemple, nous verrons comment.

Note : en plus des avantages suscitĂ©s, supersmack peut Ă©galement ĂȘtre interfacĂ© avec PostgreSQL et Oracle.

Installation de supersmack

Le binaire n’Ă©tant pas distribuĂ© avec mysql, nos tests sous supersmack vont nĂ©cessiter quelques Ă©tapes supplĂ©mentaires.

PremiÚre étape, récupérer les sources :

wget http://vegan.net/tony/supersmack/super-smack-1.3.tar.gz

puis

./configure --with-mysql=/usr/local/mysql5125

A ce stade vous devriez voir s’afficher ceci :

Building with the following options:

MySQL Support………………… yes
PostgreSQL Support……………. no
Oracle Support……………….. no

Thanks for using super-smack!

Faites suivre d’un make, et make install : supersmack devait ĂȘtre opĂ©rationnel.

Si ça n’est pas le cas, veillez Ă  avoir installĂ© les paquets suivants (ubuntu) :

apt-get install libmysqlclient15-dev
apt-get install build-essential

supersmack : fonctionnement

Le répertoire /smacks contient deux exemples : select-key.smack et update-select.smack.
Prenons comme base le premier fichier et voyons comment le configurer.

EvoquĂ©e en introduction, supersmack dispose d’une fonctionnalitĂ© trĂšs pratique dans certains cas, il s’agit du “dictionnaire”. Ce dernier permet de construire des requĂȘtes dynamiques, comme si votre requĂȘte Ă©tait directement issue de votre script. Exemple :

SELECT Capital FROM Country WHERE Code = “$code_pays”

Difficile d’exĂ©cuter une telle requĂȘte avec mysqlslap… Il faudrait s’arranger pour rĂ©cupĂ©rer le code pays via une jointure mais dans certains cas cette information n’est tout simplement pas disponible. Il se peut que vous souhaitiez exĂ©cuter une sĂ©rie de requĂȘte construites dynamiquement Ă  partir d’informations contenues dans un fichier.

Construisons Ă  titre d’exemple un tel dictionnaire Ă  partir de l’une de nos tables (la fameuse base “world” est encore une fois mise Ă  contribution).

mysql> select distinct(countrycode) into outfile '/tmp/code_pays_pop_under_2M.txt' from City where population < 2000000;

On a ainsi exportĂ© dans /tmp/code_pays_under_2M.txt la liste des codes pays qui possĂšdent des villes infĂ©rieures Ă  2 000 000 d’habitants. Le fichier contient des lignes stockĂ©s sous la forme suivante :

AFG
NLD
ANT


Notre “dictionnaire” dĂ©sormais construit, supersmack pourra y piocher les informations requises et construire dynamiquement nos requĂȘtes.

Voyons maintenant à quoi ressemble un fichier .smack. Nous partons ici du fichier select-key.smack pour construire un dbnewz.smack allégé pour notre exemple :

//define a dictionary
dictionary “code_pays”
{
type “rand”; // autres valeurs possibles : “seq” ou “unique”
source_type “file”; // nous utiliserons le fichier contenant nos codes pays
source “/tmp/code_pays_pop_under_2M.txt”; // emplacement du fichier “dictionnaire”
delim “,”; // take the part of the line before ,
file_size_equiv “45000″; // if the file is greater than this
//divide the real file size by this value obtaining N and take every Nth
//line skipping others. This is needed to be able to target a wide key
// range without using up too much memory with test keys
} 

//define a query
query “find_capital”
{
query “SELECT SQL_NO_CACHE ci.Name, ci.Population
FROM City ci
INNER JOIN Country co ON ci.CountryCode = co.Code
WHERE co.Code = ‘$code_pays’”;
type “req_code_pays”; // libellĂ© de votre requete, permet de s’y retrouver dans les resultats
has_result_set “y”; // On attend des resultats (a la difference d’un UPDATE par ex).
parsed “y”; // signale que supersmack doit construire dynamiquement la requete a partir du dictionnaire
}

// define database client type
client “dbnewz”
{
user “root”; // connect as this user
pass “XXXXXXX”; // use this password
host “localhost”; // connect to this host
db “world”; // switch to this database
#socket ” /var/run/mysqld/mysqld.sock”;  // j’utilise ici la valeur de SHOW VARIABLES LIKE ’socket’;
query_barrel “1 find_capital”; // Execute 1 fois la requete “find_capital” a chaque iteration.

}

main
{
dbnewz.init(); // initialize the client
dbnewz.set_num_rounds($2); // le 2eme argument recu par supersmack est le nombre d’iterations.
dbnewz.create_threads($1); // permet de definir combien de clients simultanĂ©s l’on souhaite.
dbnewz.connect();
dbnewz.unload_query_barrel(); // for each client fire the query barrel
dbnewz.collect_threads();
dbnewz.disconnect()
;
}

Il est Ă©galement possible pour supersmack de crĂ©er automatiquement les tables dans lesquelles se dĂ©rouleront les tests, ouvrez le fichier select-key.smack pour davantage d’informations, il fournit la syntaxe relative Ă  cette fonctionnalitĂ©.

Nous pouvons désormais lancer le test, ici 50 clients concurrents et 1000 itérations :

root@u200:/opt/super-smack-1.3/smacks# super-smack dbnewz.smack 50 1000

Query Barrel Report for client dbnewz
connect: max=888ms  min=7ms avg= 213ms from 50 clients
Query_type    num_queries    max_time    min_time    q_per_s
req_code_pays    50000    41    1    1327.08

Nous avons ici obtenu en moyenne 1327 requĂȘtes / seconde pour cette requĂȘtes et 50 clients concurrents entre le dĂ©but et la fin de nos tests.

ConnectĂ© sur le serveur MySQL en question, on observe via un SHOW FULL PROCESSLIST des requĂȘtes du type :

SELECT SQL_NO_CACHE ci.Name, ci.Population
FROM City ci
INNER JOIN Country co ON ci.CountryCode = co.Code
WHERE co.Code = ‘LKA’


Le code ‘LKA’ a Ă©tĂ© remplacĂ© par supersmack lui-mĂȘme, le dictionnaire a donc bien fonctionnĂ©.

Vous venez de faire connaissance avec ces deux outils de benchmark (si ça n’Ă©tait pas dĂ©jĂ  fait), pensez Ă  les utiliser lors de vos prochaines Ă©valuations de performance (serveur / requĂȘtes). Il est en effet toujours apprĂ©ciable de pouvoir qualifier la situation de dĂ©part afin de mesurer l’Ă©tendue des progrĂšs effectuĂ©s par la suite.



Autres billets susceptibles de vous intéresser :
  • mysql_secure_installation, utile mais non paramĂ©trable
  • DBDesigner 4 : gĂ©nĂ©rer son MCD par reverse engineering
  • Les covering index, de la thĂ©orie Ă  la pratique avec MyISAM et InnoDB
  • 15 secondes pour installer une rĂ©plication MySQL avec MySQL Sandbox, pari tenu ?
  • CardinalitĂ©, sĂ©lectivitĂ© et distributivitĂ© d’un index MySQL : quel impact sur le plan d’exĂ©cution ?
  • 4 réponses à “mysqlslap et supersmack, deux outils de benchmark pour MySQL”

    1. Cédric Says:

      Bonjour,

      merci pour l’article, il met efficacement le pied Ă  l’Ă©trier. Toutefois je compare trois requĂȘtes SELECT * FROM matable WHERE id = valeur; sur trois tables, dont le champ id (clef primaire) est respectivement du type int, char(30), varchar(100).
      Intuitivement je pensais avoir des diffĂ©rences de temps d’exĂ©cution, et en fait non. MĂȘme en rĂ©pĂ©tant les tests plusieurs fois, en jouant sur iterations et concurrency, j’obtiens des temps trĂšs proches Ă  chaque fois.
      Donc ma question : y’a t’il un piĂšge dans lequel il ne faut pas tomber avec ce genre d’outils? Quelles sont les prĂ©cautions?
      Possible aussi que les trois requĂȘtes soient effectivement Ă©gales, mais je crains l’erreur de condition expĂ©rimentale.

      Cordialement
      Cédric

    2. pébé Says:

      Salut Cédric,
      plusieurs questions:
      InnoDB ou MyISAM?
      version de MySQL?
      quel type de test fais tu?
      Single Key lookup est quand mĂȘme ce qu il y a de plus rapide comme requĂȘte.

    3. arnaud Says:

      Salut Cédric,

      un article qui tombe Ă  point pour notre discussion : http://www.bigdbahead.com/?p=58
      matt constate 25% de perf en moins sur des requetes identiques dont la clé primaire est mise entre quotes.

    4. dbnewz » Blog Archive » GĂ©nĂ©rer un jeu de donnĂ©es : shell, mysqlslap, et procĂ©dure stockĂ©e Says:

      [...] est un outil de benchmark que nous avons étudié récemment. Nous détournons ici son utilisation premiÚre pour finalement exécuter notre million de [...]

    Laisser un commentaire