Ajout documentation sur les groupes de réplication, les utilisateurs, les règles de redirection et le cache de requêtes

This commit is contained in:
Eric Morino 2023-04-03 11:28:21 +02:00
parent ace6769483
commit 1d5363e249

View file

@ -183,3 +183,303 @@ Pour conserver les modifications de configuration lors des redémarrages, *SAVE
ProxySQL Admin> SAVE MYSQL VARIABLES TO DISK;
Query OK, 54 rows affected (0.02 sec)
~~~
## Groupe d'hôtes de réplication
Les changements de topologie du cluster sont surveillés en fonction des groupes d'hôtes de réplication configuré dans ProxySQL.
ProxySQL comprend la topologie de réplication en surveillant la valeur de la variable `read_only` sur les serveurs configurés dans les groupes d'hôtes dans la table `mysql_replication_hostgroups`
Cette table est vide par défaut et doit être configuré en spécifiant une paire de groupes d'hôtes `READER` et `WRITER`, par exemple :
~~~
ProxySQL Admin> SHOW CREATE TABLE mysql_replication_hostgroups\G
*************************** 1. row ***************************
table: mysql_replication_hostgroups
Create Table: CREATE TABLE mysql_replication_hostgroups (
writer_hostgroup INT CHECK (writer_hostgroup>=0) NOT NULL PRIMARY KEY,
reader_hostgroup INT NOT NULL CHECK (reader_hostgroup<>writer_hostgroup AND reader_hostgroup>=0),
check_type VARCHAR CHECK (LOWER(check_type) IN ('read_only','innodb_read_only','super_read_only','read_only|innodb_read_only','read_only&innodb_read_only')) NOT NULL DEFAULT 'read_only',
comment VARCHAR NOT NULL DEFAULT '', UNIQUE (reader_hostgroup))
ProxySQL Admin> INSERT INTO mysql_replication_hostgroups (writer_hostgroup,reader_hostgroup,comment) VALUES (1,2,'cluster1');
Query OK, 1 row affected (0.00 sec)
~~~
Maintenant, tout les serveurs backend MySQL configurés dans le groupe d'hôtes 1 ou 2 seront placés dans leurs groupe d'hôte respectif en fonction de leur valeur `read_only` :
* S'ils ont `read_only=0`, alors il seront déplacés dans le groupe d'hôtes 1 (`writer_hostgroup`) qui permet de faire de l'écriture
* S'ils ont `read_only=1`, alors il seront déplacés dans le groupe d'hôtes 2 (`reader_hostgroup`) qui permet de faire de la lecture seule
Pour activé cette configuration et l'activé lors de l'exécution, il faut exécuter la même commande `LOAD` utilisée pour les serveurs MySQL, car `LOAD MYSQL SERVERS TO RUNTIME` traite à la fois les tables `mysql_servers` et `mysql_replication_hostgroups`
Le résultat du check `read_only` sont logger dans la table `mysql_servers_read_only_log` dans la base `monitor` :
~~~
ProxySQL Admin> SELECT * FROM monitor.mysql_server_read_only_log ORDER BY time_start_us DESC LIMIT 3
+---------------+------+------------------+-----------------+-----------+-------+
| hostname | port | time_start_us | success_time_us | read_only | error |
+---------------+------+------------------+-----------------+-----------+-------+
| 192.168.4.247 | 3306 | 1680509025040593 | 716 | 0 | NULL |
| 192.168.4.244 | 3306 | 1680509025018830 | 583 | 1 | NULL |
| 192.168.4.245 | 3306 | 1680509023039065 | 368 | 1 | NULL |
+---------------+------+------------------+-----------------+-----------+-------+
3 rows in set (0.000 sec)
~~~
ProxySQL surveille la valeur `read_only` pour les serveurs, et il a également créé le groupe d'hôtes2 (`hostgroup_id=2`) vers l'endroit où il a déplacé les serveurs avec read_only=1 (readers) du groupe d'hôtes1 (`hostgroup_id=1`).
~~~
ProxySQL Admin> SELECT * FROM mysql_servers;
+--------------+---------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| hostgroup_id | hostname | port | gtid_port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+---------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| 1 | 192.168.4.247 | 3306 | 0 | ONLINE | 1 | 0 | 1000 | 0 | 0 | 0 | |
| 2 | 192.168.4.224 | 3306 | 0 | ONLINE | 1 | 0 | 1000 | 0 | 0 | 0 | |
| 2 | 192.168.4.245 | 3306 | 0 | ONLINE | 1 | 0 | 1000 | 0 | 0 | 0 | |
+--------------+---------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
5 rows in set (0.000 sec)
~~~
Pour sauvegarder, on enregistre la configuration sur le disque :
~~~
ProxySQL Admin> SAVE MYSQL SERVERS TO DISK;
Query OK, 0 rows affected (0.01 sec)
ProxySQL Admin> SAVE MYSQL VARIABLES TO DISK;
Query OK, 54 rows affected (0.00 sec)
~~~
## Utilisateurs MySQL
Après avoir configuré les backend MySQL, dans la table `mysql_servers`, l'étape suivante est de configuré les utilisateurs MySQL.
Ceci ce fait en ajoutant des entrées à la table `mysql_users` :
~~~
ProxySQL Admin> SHOW CREATE TABLE mysql_users\G
*************************** 1. row ***************************
table: mysql_users
Create Table: CREATE TABLE mysql_users (
username VARCHAR NOT NULL,
password VARCHAR,
active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 1,
use_ssl INT CHECK (use_ssl IN (0,1)) NOT NULL DEFAULT 0,
default_hostgroup INT NOT NULL DEFAULT 0,
default_schema VARCHAR,
schema_locked INT CHECK (schema_locked IN (0,1)) NOT NULL DEFAULT 0,
transaction_persistent INT CHECK (transaction_persistent IN (0,1)) NOT NULL DEFAULT 1,
fast_forward INT CHECK (fast_forward IN (0,1)) NOT NULL DEFAULT 0,
backend INT CHECK (backend IN (0,1)) NOT NULL DEFAULT 1,
frontend INT CHECK (frontend IN (0,1)) NOT NULL DEFAULT 1,
max_connections INT CHECK (max_connections >=0) NOT NULL DEFAULT 10000,
attributes VARCHAR CHECK (JSON_VALID(attributes) OR attributes = '') NOT NULL DEFAULT '',
comment VARCHAR NOT NULL DEFAULT '',
PRIMARY KEY (username, backend),
UNIQUE (username, frontend))
1 row in set (0.000 sec)
~~~
Cette table est vide par défaut, pour ajouter des utilisateurs, spécifiez le nom d'utilisateur, le mot de passe et le groupe d'hôtes par défaut pour la configuration de base :
~~~
ProxySQL Admin> INSERT INTO mysql_users(username,password,default_hostgroup) VALUES ('foo','bar',1);
ProxySQL Admin> SELECT * FROM mysql_users;
+----------+--------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+------------+---------+
| username | password | active | use_ssl | default_hostgroup | default_schema | schema_locked | transaction_persistent | fast_forward | backend | frontend | max_connections | attributes | comment |
+----------+--------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+------------+---------+
| root | | 1 | 0 | 1 | NULL | 0 | 1 | 0 | 1 | 1 | 10000 | | |
| foo | bar | 1 | 0 | 1 | NULL | 0 | 1 | 0 | 1 | 1 | 10000 | | |
+----------+--------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+------------+---------+
2 rows in set (0.000 sec)
~~~
En définissant le groupe d'hôtes par défaut, nous spécifions à quels serveurs principaux un utilisateur doit se connecter PAR DÉFAUT, c'est-à-dire qu'il s'agira de la route par défaut pour le trafic provenant de l'utilisateur spécifique, des règles supplémentaires peuvent être configurées pour rediriger, mais en leur absence, toutes les requêtes iront au groupe d'hôtes spécifique.
~~~
ProxySQL Admin> LOAD MYSQL USERS TO RUNTIME;
Query OK, 0 rows affected (0.00 sec)
ProxySQL Admin> SAVE MYSQL USERS TO DISK;
Query OK, 0 rows affected (0.01 sec)
~~~
ProxySQL est maintenant prêt à servir le trafic sur le port 6033 (par défaut).
~~~
# mysql -u foo -p bar -h 127.0.0.1 -P6033 -e"SELECT @@port"
+--------+
| @@port |
+--------+
| 3306 |
+--------+
~~~
## Règles de requêtes
Les règles de requetes sont un puissant levier pour contrôler le trafic qui passe a travers ProxySQL, et sont configurés dans la table `mysql_query_rules` :
~~~
ProxySQL Admin> SHOW CREATE TABLE mysql_query_rules\G
*************************** 1. row ***************************
table: mysql_query_rules
Create Table: CREATE TABLE mysql_query_rules (
rule_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 0,
username VARCHAR,
schemaname VARCHAR,
flagIN INT CHECK (flagIN >= 0) NOT NULL DEFAULT 0,
client_addr VARCHAR,
proxy_addr VARCHAR,
proxy_port INT CHECK (proxy_port >= 0 AND proxy_port <= 65535),
digest VARCHAR,
match_digest VARCHAR,
match_pattern VARCHAR,
negate_match_pattern INT CHECK (negate_match_pattern IN (0,1)) NOT NULL DEFAULT 0,
re_modifiers VARCHAR DEFAULT 'CASELESS',
flagOUT INT CHECK (flagOUT >= 0),
replace_pattern VARCHAR CHECK(CASE WHEN replace_pattern IS NULL THEN 1 WHEN replace_pattern IS NOT NULL AND match_pattern IS NOT NULL THEN 1 ELSE 0 END),
destination_hostgroup INT DEFAULT NULL,
cache_ttl INT CHECK(cache_ttl > 0),
cache_empty_result INT CHECK (cache_empty_result IN (0,1)) DEFAULT NULL,
cache_timeout INT CHECK(cache_timeout >= 0),
reconnect INT CHECK (reconnect IN (0,1)) DEFAULT NULL,
timeout INT UNSIGNED CHECK (timeout >= 0),
retries INT CHECK (retries>=0 AND retries <=1000),
delay INT UNSIGNED CHECK (delay >=0),
next_query_flagIN INT UNSIGNED,
mirror_flagOUT INT UNSIGNED,
mirror_hostgroup INT UNSIGNED,
error_msg VARCHAR,
OK_msg VARCHAR,
sticky_conn INT CHECK (sticky_conn IN (0,1)),
multiplex INT CHECK (multiplex IN (0,1,2)),
gtid_from_hostgroup INT UNSIGNED,
log INT CHECK (log IN (0,1)),
apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0,
attributes VARCHAR CHECK (JSON_VALID(attributes) OR attributes = '') NOT NULL DEFAULT '',
comment VARCHAR)
1 row in set (0.000 sec)
~~~
Pour configuré ProxySQL pour envoyer les 2 premières requêtes au réplica hostgroup2, et tout le reste au primaire, les règles suivantes seraient requises :
~~~
ProxySQL Admin> INSERT INTO mysql_query_rules (rule_id,active,username,match_digest,destination_hostgroup,apply) VALUES (10,1,'foo','^SELECT c FROM test WHERE id=?',2,1);
Query OK, 1 row affected (0.00 sec)
ProxySQL Admin> INSERT INTO mysql_query_rules (rule_id,active,username,match_digest,destination_hostgroup,apply) VALUES (20,1,'foo','DISTINCT c FROM test',2,1);
Query OK, 1 row affected (0.00 sec)
~~~
Points clés concernant ces règles de requête (et les règles de requête en général) :
* Les règles de requête sont traitées selon l'ordre de `rule_id`
* Seules les règles qui ont `active=1` sont traitées
* Le premier exemple de règle utilise l'accent circonflexe (^) et le dollar ($) : ce sont des caractères regex spéciaux qui marquent le début et la fin d'un motif. Dans ce cas `match_digestormatch_pattern` doit correspondre complètement à la requête
* La deuxième règle de l'exemple n'utilise ni d'accent circonflexe, ni dollar : la correspondance peut se trouver n'importe où dans la requête.
* Le point d'interrogation est échappé car il a une signification particulière dans regex
* `apply=1` signifie qu'aucune autre règle ne doit être évaluée si la règle actuelle correspondait
La configuration actuelle de la règle peut être vérifiée dans la table `mysql_query_rules` :
~~~
ProxySQL Admin> SELECT match_digest,destination_hostgroup FROM mysql_query_rules WHERE active=1 AND username='test' ORDER BY rule_id;
+-----------------------------------+-----------------------+
| match_digest | destination_hostgroup |
+-----------------------------------+-----------------------+
| ^SELECT c FROM sbtest1 WHERE id=? | 2 |
| DISTINCT c FROM test | 2 |
+-----------------------------------+-----------------------+
2 rows in set (0.000 sec)
~~~
Pour ces 2 règles spécifiques, des requêtes seront envoyées aux réplica, Si aucune règle ne correspond à la requête, le `default_hostgroup` configuré pour l'utilisateur s'applique, c'est-à-dire 1 pour l'utilisateur `test`
La table `stats_mysql_query_digest_reset` peut être interrogé pour récupérer la charge de travail précédente et effacer le contenu de la table `stats_mysql_query_digest`, et la TRUNCATE, ceci est recommandé avant d'activer les règles de requête pour revoir facilement les modifications.
On sauvegarde et on active les changements :
~~~
ProxySQL Admin> LOAD MYSQL QUERY RULES TO RUNTIME;
Query OK, 0 rows affected (0.00 sec)
~~~
Une fois le trafic passé par la nouvelle configuration, `stats_mysql_query_digest` montrera les changements de routage par requête :
~~~
ProxySQL Admin> SELECT hostgroup hg, sum_time, count_star, digest_text FROM stats_mysql_query_digest ORDER BY sum_time DESC;
+----+----------+------------+----------------------------------------------------------------------+
| hg | sum_time | count_star | digest_text |
+----+----------+------------+----------------------------------------------------------------------+
| 2 | 14520738 | 50041 | SELECT c FROM test WHERE id=? |
| 2 | 3203582 | 5001 | SELECT DISTINCT c FROM test WHERE id BETWEEN ? AND ?+? ORDER BY c |
| 1 | 3142041 | 5001 | COMMIT |
| 1 | 2270931 | 5001 | SELECT c FROM test WHERE id BETWEEN ? AND ?+? ORDER BY c |
| 1 | 2021320 | 5003 | SELECT c FROM test WHERE id BETWEEN ? AND ?+? |
| 1 | 1768748 | 5001 | UPDATE test SET k=k+? WHERE id=? |
| 1 | 1697175 | 5003 | SELECT SUM(K) FROM test WHERE id BETWEEN ? AND ?+? |
| 1 | 1346791 | 5001 | UPDATE test SET c=? WHERE id=? |
| 1 | 1263259 | 5001 | DELETE FROM est WHERE id=? |
| 1 | 1191760 | 5001 | INSERT INTO test (id, k, c, pad) VALUES (?, ?, ?, ?) |
| 1 | 875343 | 5005 | BEGIN |
+----+----------+------------+----------------------------------------------------------------------+
11 rows in set (0.00 sec)
~~~
Les 2 premières requêtes identifiées sont envoyées aux réplicas `hostgroup2`.
## Cache de requêtes
Un cas d'utilisation populaire pour ProxySQL consiste à agir comme un cache de requêtes.
Par défaut, les requêtes ne sont pas mises en cache, ceci est activé en définissant `cache_ttl` (en millisecondes) sur une règle définie dans `mysql_query_rules`
Pour mettre en cache toutes les requêtes envoyées aux réplicas pendant 5 secondes, mettez à jour le `cache_ttl` sur les règles de requête définies dans l'exemple précédent :
~~~
ProxySQL Admin> UPDATE mysql_query_rules set cache_ttl=5000 WHERE active=1 AND destination_hostgroup=2;
Query OK, 2 rows affected (0.000 sec)
ProxySQL Admin> LOAD MYSQL QUERY RULES TO RUNTIME;
Query OK, 0 rows affected (0.00 sec)
ProxySQL Admin> SELECT 1 FROM stats_mysql_query_digest_reset LIMIT 1; -- on remet à zéro le compteur
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.00 sec)
~~~
Une fois le trafic passé par la nouvelle configuration, `stats_mysql_query_digest` affichera les requêtes mises en cache avec une valeur de groupe d'hôtes de "-1" :
~~~
ProxySQL Admin> SELECT hostgroup hg, sum_time, count_star, digest_text FROM stats_mysql_query_digest ORDER BY sum_time DESC;
+----+----------+------------+----------------------------------------------------------------------+
| hg | sum_time | count_star | digest_text |
+----+----------+------------+----------------------------------------------------------------------+
| 1 | 7457441 | 5963 | COMMIT |
| 1 | 6767681 | 5963 | SELECT c FROM test WHERE id BETWEEN ? AND ?+? ORDER BY c |
| 2 | 4891464 | 8369 | SELECT c FROM test WHERE id=? |
| 1 | 4573513 | 5963 | UPDATE test SET k=k+? WHERE id=? |
| 1 | 4531319 | 5963 | SELECT c FROM test WHERE id BETWEEN ? AND ?+? |
| 1 | 3993283 | 5963 | SELECT SUM(K) FROM test WHERE id BETWEEN ? AND ?+? |
| 1 | 3482242 | 5963 | UPDATE test SET c=? WHERE id=? |
| 1 | 3209088 | 5963 | DELETE FROM test WHERE id=? |
| 1 | 2959358 | 5963 | INSERT INTO test (id, k, c, pad) VALUES (?, ?, ?, ?) |
| 1 | 2415318 | 5963 | BEGIN |
| 2 | 2266662 | 1881 | SELECT DISTINCT c FROM test WHERE id BETWEEN ? AND ?+? ORDER BY c |
| -1 | 0 | 4082 | SELECT DISTINCT c FROM test WHERE id BETWEEN ? AND ?+? ORDER BY c |
| -1 | 0 | 51261 | SELECT c FROM test WHERE id=? |
+----+----------+------------+----------------------------------------------------------------------+
13 rows in set (0.00 sec)
~~~