proxySQL with SemiSync
環境資訊
hostname | IP | port | role | comm |
---|---|---|---|---|
ms81 | 192.168.188.81 | 3399 | master | |
ms82 | 192.168.188.82 | 3399 | slave | |
ms83 | 192.168.188.83 | 3399 | slave | |
ms84 | 192.168.188.84 | 6033 | proxysql&sysbench |
- ProxySQL version 2.0.11-124-g971c15e, codename Truls
- MySQL 8.0.19 x86_64
- CentOS 7.8.2003 on Docker
配置半同步
-
ms81 配置環境
[10:46:55] root@ms81:~ # ./mysql_onekey_3.2.1.sh /opt/mysql-8.0.19-linux-glibc2.12-x86_64 3399 ##ms81 [10:51:30] root@ms81:~ # mysql -S /data/mysql/mysql3399/tmp/mysql.sock mysql> set global super_read_only=0; Query OK, 0 rows affected (0.00 sec) mysql> create user 'rep'@'192.168.188.%' identified by 'rep'; Query OK, 0 rows affected (0.02 sec) mysql> grant replication slave on *.* to 'rep'@'192.168.188.%'; Query OK, 0 rows affected (0.02 sec) mysql> create user 'proxy'@'192.168.188.%' identified with mysql_native_password by 'proxy'; Query OK, 0 rows affected (0.02 sec) mysql> grant replication client on *.* to 'proxy'@'192.168.188.%'; Query OK, 0 rows affected (0.02 sec) mysql> create user 'monitor'@'192.168.188.%' identified with mysql_native_password by 'monitor'; Query OK, 0 rows affected (10.02 sec) mysql> grant replication client on *.* to 'monitor'@'192.168.188.%'; Query OK, 0 rows affected (0.02 sec) mysql> install plugin rpl_semi_sync_master soname 'semisync_master.so'; Query OK, 0 rows affected (0.02 sec) mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so'; Query OK, 0 rows affected (0.02 sec) mysql> set global rpl_semi_sync_master_enabled =1; Query OK, 0 rows affected (0.00 sec) mysql> show global variables like '%semi%'; +-------------------------------------------+------------+ | Variable_name | Value | +-------------------------------------------+------------+ | rpl_semi_sync_master_enabled | ON | | rpl_semi_sync_master_timeout | 10000 | | rpl_semi_sync_master_trace_level | 32 | | rpl_semi_sync_master_wait_for_slave_count | 1 | | rpl_semi_sync_master_wait_no_slave | ON | | rpl_semi_sync_master_wait_point | AFTER_SYNC | | rpl_semi_sync_slave_enabled | OFF | | rpl_semi_sync_slave_trace_level | 32 | +-------------------------------------------+------------+ 8 rows in set (0.00 sec) mysql> reset master; Query OK, 0 rows affected (0.05 sec) mysql> show master status; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000001 | 155 | | | | +------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec)
-
ms82 配置環境
[10:51:32] root@ms82:~ # ./mysql_onekey_3.2.1.sh /opt/mysql-8.0.19-linux-glibc2.12-x86_64 3399 ##ms82 [10:51:39] root@ms82:~ # mysql -S /data/mysql/mysql3399/tmp/mysql.sock mysql> set global super_read_only=0; Query OK, 0 rows affected (0.00 sec) mysql> create user 'rep'@'192.168.188.%' identified by 'rep'; Query OK, 0 rows affected (0.02 sec) mysql> grant replication slave on *.* to 'rep'@'192.168.188.%'; Query OK, 0 rows affected (0.02 sec) mysql> create user 'proxy'@'192.168.188.%' identified with mysql_native_password by 'proxy'; Query OK, 0 rows affected (0.01 sec) mysql> grant replication client on *.* to 'proxy'@'192.168.188.%'; Query OK, 0 rows affected (0.01 sec) mysql> create user 'monitor'@'192.168.188.%' identified with mysql_native_password by 'monitor'; Query OK, 0 rows affected (0.01 sec) mysql> grant replication client on *.* to 'monitor'@'192.168.188.%'; Query OK, 0 rows affected (0.01 sec) mysql> install plugin rpl_semi_sync_master soname 'semisync_master.so'; Query OK, 0 rows affected (0.01 sec) mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so'; Query OK, 0 rows affected (0.01 sec) mysql> set global rpl_semi_sync_slave_enabled =1; Query OK, 0 rows affected (0.00 sec) mysql> show global variables like '%semi%'; +-------------------------------------------+------------+ | Variable_name | Value | +-------------------------------------------+------------+ | rpl_semi_sync_master_enabled | OFF | | rpl_semi_sync_master_timeout | 10000 | | rpl_semi_sync_master_trace_level | 32 | | rpl_semi_sync_master_wait_for_slave_count | 1 | | rpl_semi_sync_master_wait_no_slave | ON | | rpl_semi_sync_master_wait_point | AFTER_SYNC | | rpl_semi_sync_slave_enabled | ON | | rpl_semi_sync_slave_trace_level | 32 | +-------------------------------------------+------------+ 8 rows in set (0.00 sec) mysql> reset master; Query OK, 0 rows affected (0.03 sec) mysql> change master to master_host='192.168.188.81',master_port=3399,master_user='rep',master_password='rep',master_auto_position=1,get_master_public_key=1; Query OK, 0 rows affected, 2 warnings (0.07 sec) mysql> start slave; Query OK, 0 rows affected (0.03 sec)
-
ms83 配置環境
[10:51:35] root@ms83:~ # ./mysql_onekey_3.2.1.sh /opt/mysql-8.0.19-linux-glibc2.12-x86_64 3399 ##ms83 同ms82一樣,略。
-
master 檢視狀態
mysql> show global status like '%semi%'; +--------------------------------------------+-------+ | Variable_name | Value | +--------------------------------------------+-------+ | Rpl_semi_sync_master_clients | 2 | | Rpl_semi_sync_master_net_avg_wait_time | 0 | | Rpl_semi_sync_master_net_wait_time | 0 | | Rpl_semi_sync_master_net_waits | 0 | | Rpl_semi_sync_master_no_times | 0 | | Rpl_semi_sync_master_no_tx | 0 | | Rpl_semi_sync_master_status | ON | | Rpl_semi_sync_master_timefunc_failures | 0 | | Rpl_semi_sync_master_tx_avg_wait_time | 0 | | Rpl_semi_sync_master_tx_wait_time | 0 | | Rpl_semi_sync_master_tx_waits | 0 | | Rpl_semi_sync_master_wait_pos_backtraverse | 0 | | Rpl_semi_sync_master_wait_sessions | 0 | | Rpl_semi_sync_master_yes_tx | 0 | | Rpl_semi_sync_slave_status | OFF | +--------------------------------------------+-------+ 15 rows in set (0.00 sec)
配置ProxySQL
-
安裝
[11:08:20] root@ms84:/ofiles # yum localinstall -y proxysql-2.0.11-1-centos7.x86_64.rpm [11:19:53] root@ms84:/ofiles # rpm -ql proxysql /etc/logrotate.d/proxysql /etc/proxysql.cnf /etc/systemd/system/proxysql-initial.service /etc/systemd/system/proxysql.service /usr/bin/proxysql /usr/share/proxysql/tools/proxysql_galera_checker.sh /usr/share/proxysql/tools/proxysql_galera_writer.pl
-
啟動服務
由於在docker執行,無法使用systemctl,所以在這裡檢視一下service檔案,找到命令列,手動執行。[11:21:16] root@ms84:/ofiles # cat /etc/systemd/system/proxysql.service ... ... [Service] Type=forking RuntimeDirectory=proxysql #PermissionsStartOnly=true #ExecStartPre=/usr/bin/mkdir -p /var/run/proxysql /var/run/proxysql #ExecStartPre=/usr/bin/chown -R proxysql: /var/run/proxysql/ ExecStart=/usr/bin/proxysql --idle-threads -c /etc/proxysql.cnf PIDFile=/var/lib/proxysql/proxysql.pid #StandardError=null # all output is in stderr SyslogIdentifier=proxysql Restart=no User=proxysql Group=proxysql ... ... [11:23:25] root@ms84:/ofiles # /usr/bin/proxysql --idle-threads -c /etc/proxysql.cnf 2020-05-19 11:23:26 [INFO] Using config file /etc/proxysql.cnf 2020-05-19 11:23:26 [INFO] Using OpenSSL version: OpenSSL 1.1.1d 10 Sep 2019 2020-05-19 11:23:26 [INFO] No SSL keys/certificates found in datadir (/var/lib/proxysql). Generating new keys/certificates. [11:23:26] root@ms84:/ofiles # ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 10:38 ? 00:00:00 /usr/sbin/sshd -D root 6 1 0 10:38 ? 00:00:00 sshd: root@pts/0 root 8 6 0 10:38 pts/0 00:00:00 -zsh root 338 1 0 11:23 ? 00:00:00 /usr/bin/proxysql --idle-threads -c /etc/proxysql.cnf root 339 338 3 11:23 ? 00:00:00 /usr/bin/proxysql --idle-threads -c /etc/proxysql.cnf root 368 8 0 11:23 pts/0 00:00:00 ps -ef [11:23:40] root@ms84:/ofiles # ss -antulp|grep proxy tcp LISTEN 0 128 *:6032 *:* users:(("proxysql",pid=339,fd=40)) tcp LISTEN 0 128 *:6033 *:* users:(("proxysql",pid=339,fd=36)) tcp LISTEN 0 128 *:6033 *:* users:(("proxysql",pid=339,fd=35)) tcp LISTEN 0 128 *:6033 *:* users:(("proxysql",pid=339,fd=34)) tcp LISTEN 0 128 *:6033 *:* users:(("proxysql",pid=339,fd=32))
-
配置ProxySQL
- 通過管理埠登入ProxySQL的sqlite
[11:23:48] root@ms84:/ofiles # mysql -h 127.0.0.1 -P 6032 -uadmin -padmin
- 檢視一下sqlite的結構
mysql> show tables; +----------------------------------------------------+ | tables | +----------------------------------------------------+ | global_variables | | mysql_aws_aurora_hostgroups | | mysql_collations | | mysql_firewall_whitelist_rules | | mysql_firewall_whitelist_sqli_fingerprints | | mysql_firewall_whitelist_users | | mysql_galera_hostgroups | | mysql_group_replication_hostgroups | | mysql_query_rules | | mysql_query_rules_fast_routing | | mysql_replication_hostgroups | | mysql_servers | | mysql_users | | proxysql_servers | | restapi_routes | | runtime_checksums_values | | runtime_global_variables | | runtime_mysql_aws_aurora_hostgroups | | runtime_mysql_firewall_whitelist_rules | | runtime_mysql_firewall_whitelist_sqli_fingerprints | | runtime_mysql_firewall_whitelist_users | | runtime_mysql_galera_hostgroups | | runtime_mysql_group_replication_hostgroups | | runtime_mysql_query_rules | | runtime_mysql_query_rules_fast_routing | | runtime_mysql_replication_hostgroups | | runtime_mysql_servers | | runtime_mysql_users | | runtime_proxysql_servers | | runtime_restapi_routes | | runtime_scheduler | | scheduler | +----------------------------------------------------+ 32 rows in set (0.00 sec) mysql> select database(); +------------+ | DATABASE() | +------------+ | admin | +------------+ 1 row in set (0.00 sec) mysql> show databases; +-----+---------------+-------------------------------------+ | seq | name | file | +-----+---------------+-------------------------------------+ | 0 | main | | | 2 | disk | /var/lib/proxysql/proxysql.db | | 3 | stats | | | 4 | monitor | | | 5 | stats_history | /var/lib/proxysql/proxysql_stats.db | +-----+---------------+-------------------------------------+ 5 rows in set (0.00 sec)
- 配置讀寫組
mysql> use main; mysql> 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)) 1 row in set (0.00 sec) mysql> insert into mysql_replication_hostgroups(writer_hostgroup, reader_hostgroup,comment) values (100,101,'proxy'); Query OK, 1 row affected (0.00 sec) mysql> select * from mysql_replication_hostgroups; +------------------+------------------+------------+---------+ | writer_hostgroup | reader_hostgroup | check_type | comment | +------------------+------------------+------------+---------+ | 100 | 101 | read_only | proxy | +------------------+------------------+------------+---------+ 1 row in set (0.00 sec)
- 新增成員
mysql> show create table mysql_servers \G *************************** 1. row *************************** table: mysql_servers Create Table: CREATE TABLE mysql_servers ( hostgroup_id INT CHECK (hostgroup_id>=0) NOT NULL DEFAULT 0, hostname VARCHAR NOT NULL, port INT CHECK (port >= 0 AND port <= 65535) NOT NULL DEFAULT 3306, gtid_port INT CHECK ((gtid_port <> port OR gtid_port=0) AND gtid_port >= 0 AND gtid_port <= 65535) NOT NULL DEFAULT 0, status VARCHAR CHECK (UPPER(status) IN ('ONLINE','SHUNNED','OFFLINE_SOFT', 'OFFLINE_HARD')) NOT NULL DEFAULT 'ONLINE', weight INT CHECK (weight >= 0 AND weight <=10000000) NOT NULL DEFAULT 1, compression INT CHECK (compression IN(0,1)) NOT NULL DEFAULT 0, max_connections INT CHECK (max_connections >=0) NOT NULL DEFAULT 1000, max_replication_lag INT CHECK (max_replication_lag >= 0 AND max_replication_lag <= 126144000) NOT NULL DEFAULT 0, use_ssl INT CHECK (use_ssl IN(0,1)) NOT NULL DEFAULT 0, max_latency_ms INT UNSIGNED CHECK (max_latency_ms>=0) NOT NULL DEFAULT 0, comment VARCHAR NOT NULL DEFAULT '', PRIMARY KEY (hostgroup_id, hostname, port) ) 1 row in set (0.00 sec) mysql> insert into mysql_servers(hostgroup_id,hostname,port,max_connections) values (100,'192.168.188.81',3399,200); Query OK, 1 row affected (0.00 sec) mysql> insert into mysql_servers(hostgroup_id,hostname,port,max_connections) values (101,'192.168.188.82',3399,200); Query OK, 1 row affected (0.00 sec) mysql> insert into mysql_servers(hostgroup_id,hostname,port,max_connections) values (101,'192.168.188.83',3399,200); Query OK, 1 row affected (0.00 sec) mysql> mysql> select * from mysql_servers; +--------------+----------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+ | hostgroup_id | hostname | port | gtid_port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment | +--------------+----------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+ | 100 | 192.168.188.81 | 3399 | 0 | ONLINE | 1 | 0 | 200 | 0 | 0 | 0 | | | 101 | 192.168.188.82 | 3399 | 0 | ONLINE | 1 | 0 | 200 | 0 | 0 | 0 | | | 101 | 192.168.188.83 | 3399 | 0 | ONLINE | 1 | 0 | 200 | 0 | 0 | 0 | | +--------------+----------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+ 3 rows in set (0.00 sec)
- 配置ProxySQL User
mysql> 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, comment VARCHAR NOT NULL DEFAULT '', PRIMARY KEY (username, backend), UNIQUE (username, frontend)) 1 row in set (0.00 sec) mysql> insert into mysql_users(username,password,default_hostgroup,default_schema,max_connections) values ('proxy','proxy',100,'kk',1000); Query OK, 1 row affected (0.00 sec) 此時檢視monitor.mysql_server_ping_log,可以發現已經通了 mysql> select * from monitor.mysql_server_ping_log; +----------------+------+------------------+----------------------+------------+ | hostname | port | time_start_us | ping_success_time_us | ping_error | +----------------+------+------------------+----------------------+------------+ | 192.168.188.81 | 3399 | 1589859157227913 | 350 | NULL | | 192.168.188.81 | 3399 | 1589859166912107 | 376 | NULL | | 192.168.188.82 | 3399 | 1589859167034376 | 415 | NULL | | 192.168.188.83 | 3399 | 1589859167157356 | 235 | NULL | | 192.168.188.81 | 3399 | 1589859176911261 | 449 | NULL | | 192.168.188.82 | 3399 | 1589859177009697 | 565 | NULL | | 192.168.188.83 | 3399 | 1589859177108172 | 377 | NULL | | 192.168.188.82 | 3399 | 1589859186911860 | 625 | NULL | ... ... +----------------+------+------------------+----------------------+------------+ 154 rows in set (0.00 sec) 在master和slave上也能看到monitor@ms84連線資訊了 mysql> show processlist; +----+-----------------+-------------------+------+------------------+------+---------------------------------------------------------------+------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+-----------------+-------------------+------+------------------+------+---------------------------------------------------------------+------------------+ | 4 | event_scheduler | localhost | NULL | Daemon | 3071 | Waiting on empty queue | NULL | | 8 | root | localhost | NULL | Query | 0 | starting | show processlist | | 9 | rep | ms82.net188:52954 | NULL | Binlog Dump GTID | 2289 | Master has sent all binlog to slave; waiting for more updates | NULL | | 10 | rep | ms83.net188:43038 | NULL | Binlog Dump GTID | 2158 | Master has sent all binlog to slave; waiting for more updates | NULL | | 11 | monitor | ms84.net188:55902 | NULL | Sleep | 6 | | NULL | +----+-----------------+-------------------+------+------------------+------+---------------------------------------------------------------+------------------+ 5 rows in set (0.00 sec) 這一步要注意,mysql_users裡的使用者,是通過ProxySQL登入的使用者,對應的在MySQL層面,也要配置相應的許可權,做到前後端一致。 mysql> grant all privileges on kk.* to 'proxy'@'192.168.188.%'; Query OK, 0 rows affected (0.02 sec)
- 通過管理埠登入ProxySQL的sqlite
-
載入配置到runtime
mysql> load mysql users to run; Query OK, 0 rows affected (0.00 sec) mysql> load mysql servers to run; Query OK, 0 rows affected (0.00 sec) mysql> load mysql variables to run; Query OK, 0 rows affected (0.00 sec) mysql> save mysql users to disk; Query OK, 0 rows affected (0.02 sec) mysql> save mysql servers to disk; Query OK, 0 rows affected (0.11 sec) mysql> save mysql variables to disk; Query OK, 152 rows affected (0.03 sec)
-
讀寫組的切換實踐
-
此時檢視mysql servers,會發現三個節點的Hg都變成了101
因為三個節點都是read_only=1,monitor發現狀態後,根據mysql_replication_hostgroups 讀寫組的配置規則,檢測read_only的狀態後,將變更到只讀組。mysql> select * from mysql_servers; +--------------+----------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+ | hostgroup_id | hostname | port | gtid_port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment | +--------------+----------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+ | 101 | 192.168.188.81 | 3399 | 0 | ONLINE | 1 | 0 | 200 | 0 | 0 | 0 | | | 101 | 192.168.188.83 | 3399 | 0 | ONLINE | 1 | 0 | 200 | 0 | 0 | 0 | | | 101 | 192.168.188.82 | 3399 | 0 | ONLINE | 1 | 0 | 200 | 0 | 0 | 0 | | +--------------+----------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+ 3 rows in set (0.00 sec)
-
將master節點改為讀寫,然後去ProxySQL檢視mysql servers表
可以看到,隨著master節點轉為讀寫模式,ProxySQL檢測到狀態變更後,自動將ms81加入到讀寫組101。master:mysql> set global read_only=0; Query OK, 0 rows affected (0.00 sec) mysql> select * from mysql_servers; +--------------+----------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+ | hostgroup_id | hostname | port | gtid_port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment | +--------------+----------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+ | 101 | 192.168.188.82 | 3399 | 0 | ONLINE | 1 | 0 | 200 | 0 | 0 | 0 | | | 100 | 192.168.188.81 | 3399 | 0 | ONLINE | 1 | 0 | 200 | 0 | 0 | 0 | | | 101 | 192.168.188.83 | 3399 | 0 | ONLINE | 1 | 0 | 200 | 0 | 0 | 0 | | | 101 | 192.168.188.81 | 3399 | 0 | ONLINE | 1 | 0 | 200 | 0 | 0 | 0 | | +--------------+----------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+ 4 rows in set (0.01 sec)
-
預設的,讀寫節點也會同時存在於只讀組
如果想禁止這個特性,可以調整引數後,重啟生效#為false則讀寫節點不會存在於只讀組 mysql> show variables like '%also%'; +-------------------------------------+-------+ | Variable_name | Value | +-------------------------------------+-------+ | mysql-monitor_writer_is_also_reader | true | +-------------------------------------+-------+ 1 row in set (0.00 sec)
-
用sysbench建立結構
[13:37:29] root@ms84:~ # sysbench /usr/share/sysbench/oltp_read_write.lua --mysql-host=192.168.188.84 --mysql-port=6033 --mysql-user=proxy --mysql-password=proxy --db-driver=mysql --mysql-db=kk --table-size=5000 prepare sysbench 1.0.17 (using system LuaJIT 2.0.4) Creating table 'sbtest1'... Inserting 5000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... [13:37:46] root@ms84:~ # sysbench /usr/share/sysbench/oltp_read_write.lua --mysql-host=192.168.188.84 --mysql-port=6033 --mysql-user=proxy --mysql-password=proxy --db-driver=mysql --mysql-db=kk --table-size=5000 run sysbench 1.0.17 (using system LuaJIT 2.0.4) Running the test with following options: Number of threads: 1 Initializing random number generator from current time
-
檢視ProxySQL
可以看到,所有的請求都執行在100組(讀寫組)mysql> select hostgroup, digest, digest_text, count_star, first_seen, last_seen from stats.stats_mysql_query_digest; +-----------+--------------------+--------------------------------------------------------------------+------------+------------+------------+ | hostgroup | digest | digest_text | count_star | first_seen | last_seen | +-----------+--------------------+--------------------------------------------------------------------+------------+------------+------------+ | 100 | 0xE52A0A0210634DAC | INSERT INTO sbtest1 (id, k, c, pad) VALUES (?, ?, ?, ?) | 651 | 1589866799 | 1589866809 | | 100 | 0xE365BEB555319B9E | DELETE FROM sbtest1 WHERE id=? | 651 | 1589866799 | 1589866809 | | 100 | 0xFB239BC95A23CA36 | UPDATE sbtest1 SET c=? WHERE id=? | 651 | 1589866799 | 1589866809 | | 100 | 0xC198E52BCCB481C7 | UPDATE sbtest1 SET k=k+? WHERE id=? | 651 | 1589866799 | 1589866809 | | 100 | 0xDBF868B2AA296BC5 | SELECT SUM(k) FROM sbtest1 WHERE id BETWEEN ? AND ? | 651 | 1589866799 | 1589866809 | | 100 | 0x290B92FD743826DA | SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ? | 651 | 1589866799 | 1589866809 | | 100 | 0xC19480748AE79B4B | SELECT DISTINCT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c | 651 | 1589866799 | 1589866809 | | 100 | 0xBF001A0C13781C1D | SELECT c FROM sbtest1 WHERE id=? | 6501 | 1589866799 | 1589866809 | | 100 | 0x695FBF255DBEB0DD | COMMIT | 651 | 1589866799 | 1589866809 | | 100 | 0xAC80A5EA0101522E | SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c | 651 | 1589866799 | 1589866809 | | 100 | 0xFAD1519E4760CBDE | BEGIN | 651 | 1589866799 | 1589866809 | +-----------+--------------------+--------------------------------------------------------------------+------------+------------+------------+ 11 rows in set (0.00 sec)
-
-
配置讀寫分離
-
先檢視一下規則表的表結構
# https://github.com/sysown/proxysql/wiki/Main-(runtime)#mysql_query_rules mysql> 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, --規則id active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 0, --查詢處理模組將僅考慮active = 1的規則,並且僅將active規則載入到執行時。 username VARCHAR, --匹配使用者名稱的過濾條件。 如果為非NULL,則僅當使用正確的使用者名稱建立連線時,查詢才會匹配。 schemaname VARCHAR, --符合標準名稱的過濾條件。 如果為非NULL,則僅當連線使用schemaname作為預設架構時查詢才匹配 flagIN INT CHECK (flagIN >= 0) NOT NULL DEFAULT 0, --flagIN,flagOUT,應用-這些使我們能夠建立一個“規則鏈”,一個接一個地應用。 輸入標誌值設定為0,並且僅在開始時考慮flagIN = 0的規則。 當為特定查詢找到匹配規則時,將評估flagOUT,如果NOT NULL,則將在flagOUT中使用指定的標誌來標記查詢。 如果flagOUT與flagIN不同,則查詢將退出當前鏈,並輸入具有flagIN作為新輸入標誌的新規則鏈。 如果flagOUT與flagIN匹配,則將針對帶有該flagIN的第一條規則再次重新評估查詢。 直到不再有匹配的規則,或者將apply設定為1時,這才發生(這意味著這是最後一個要應用的規則) client_addr VARCHAR, --match traffic from a specific source,匹配特定來源。 proxy_addr VARCHAR, --match incoming traffic on a specific local IP,匹配特定本地IP的入口。 proxy_port INT CHECK (proxy_port >= 0 AND proxy_port <= 65535), --匹配特定本地埠 digest VARCHAR, --match queries with a specific digest, as returned by stats_mysql_query_digest.digest。 match_digest VARCHAR, --通過正則表示式匹配digest match_pattern VARCHAR, --通過正則表示式匹配sql文字 negate_match_pattern INT CHECK (negate_match_pattern IN (0,1)) NOT NULL DEFAULT 0, --如果為1,則只有與sql文字不匹配的查詢才被視為匹配項。 在與match_pattern或match_digest匹配的正則表示式前面,這充當NOT運算子 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, --將匹配的查詢路由到該主機組。 除非存在已啟動的事務,並且已登入的使用者將transaction_persistent標誌設定為1(請參見mysql_users表),否則將發生這種情況。 cache_ttl INT CHECK(cache_ttl > 0), --the number of milliseconds for which to cache the result of the query. Note: in ProxySQL 1.1 cache_ttl was in seconds 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), --執行匹配或重寫查詢的最大超時(以毫秒為單位)。 如果查詢的執行時間超過特定閾值,則會自動終止該查詢。 如果未指定超時,則應用全域性變數mysql-default_query_timeout。 retries INT CHECK (retries>=0 AND retries <=1000), --在執行查詢期間檢測到失敗的情況下,需要重新執行查詢的最大次數。 如果未指定重試,則應用全域性變數mysql-query_retries_on_failure delay INT UNSIGNED CHECK (delay >=0), --延遲查詢執行的毫秒數。是一種限制機制和QoS,允許優先處理某些查詢而不是其他查詢。 該值被新增到適用於所有查詢的mysql-default_query_delay全域性變數中。 未來版本的ProxySQL將提供更高階的限制機制。 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)), --如果為0,將禁用多路複用。 如果為1,則在沒有其他條件阻止這種情況(例如使用者變數或事務)的情況下,可以重新啟用Multiplex。 如果為2,則僅對當前查詢不禁用多路複用。 請參見Wiki。預設為NULL,因此不修改多路複用策略。 gtid_from_hostgroup INT UNSIGNED, log INT CHECK (log IN (0,1)), apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0, --當設定為1時,在匹配並處理此規則後將不再評估其他查詢(注意:此後將不再評估mysql_query_rules_fast_routing規則) comment VARCHAR) 1 row in set (0.00 sec)
-
根據sql匹配正則表示式,並載入到runtime
mysql> insert into mysql_query_rules(rule_id,active,match_pattern,destination_hostgroup,apply) values(1,1,'^SELECT.*FOR UPDATE$',100,1); Query OK, 1 row affected (0.00 sec) mysql> insert into mysql_query_rules(rule_id,active,match_pattern,destination_hostgroup,apply) values(2,1,'^SELECT',101,1); Query OK, 1 row affected (0.00 sec) mysql> select rule_id,active,match_pattern,destination_hostgroup,apply from mysql_query_rules; +---------+--------+----------------------+-----------------------+-------+ | rule_id | active | match_pattern | destination_hostgroup | apply | +---------+--------+----------------------+-----------------------+-------+ | 1 | 1 | ^SELECT.*FOR UPDATE$ | 100 | 1 | | 2 | 1 | ^SELECT | 101 | 1 | +---------+--------+----------------------+-----------------------+-------+ 2 rows in set (0.00 sec) mysql> load mysql query rules to run; Query OK, 0 rows affected (0.00 sec) mysql> save mysql query rules to disk; Query OK, 0 rows affected (0.04 sec)
-
使用sysbench執行事務,並檢視stats.mysql_query_digest
[14:31:03] root@ms84:~ # sysbench /usr/share/sysbench/oltp_read_write.lua --mysql-host=192.168.188.84 --mysql-port=6033 --mysql-user=proxy --mysql-password=proxy --db-driver=mysql --mysql-db=kk --table-size=5000 run sysbench 1.0.17 (using system LuaJIT 2.0.4) mysql> select * from stats.stats_mysql_query_digest_reset; Empty set (0.00 sec) mysql> select hostgroup, digest, digest_text, count_star, first_seen, last_seen from stats.stats_mysql_query_digest; +-----------+--------------------+--------------------------------------------------------------------+------------+------------+------------+ | hostgroup | digest | digest_text | count_star | first_seen | last_seen | +-----------+--------------------+--------------------------------------------------------------------+------------+------------+------------+ | 100 | 0xE52A0A0210634DAC | INSERT INTO sbtest1 (id, k, c, pad) VALUES (?, ?, ?, ?) | 409 | 1589870243 | 1589870250 | | 100 | 0xFB239BC95A23CA36 | UPDATE sbtest1 SET c=? WHERE id=? | 409 | 1589870243 | 1589870250 | | 100 | 0xC198E52BCCB481C7 | UPDATE sbtest1 SET k=k+? WHERE id=? | 409 | 1589870243 | 1589870250 | | 101 | 0xC19480748AE79B4B | SELECT DISTINCT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c | 409 | 1589870243 | 1589870250 | | 100 | 0xE365BEB555319B9E | DELETE FROM sbtest1 WHERE id=? | 409 | 1589870243 | 1589870250 | | 101 | 0xAC80A5EA0101522E | SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c | 409 | 1589870243 | 1589870250 | | 101 | 0xDBF868B2AA296BC5 | SELECT SUM(k) FROM sbtest1 WHERE id BETWEEN ? AND ? | 409 | 1589870243 | 1589870250 | | 101 | 0x290B92FD743826DA | SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ? | 409 | 1589870243 | 1589870250 | | 101 | 0xBF001A0C13781C1D | SELECT c FROM sbtest1 WHERE id=? | 4087 | 1589870243 | 1589870250 | | 100 | 0x695FBF255DBEB0DD | COMMIT | 409 | 1589870243 | 1589870250 | | 100 | 0xFAD1519E4760CBDE | BEGIN | 410 | 1589870243 | 1589870250 | +-----------+--------------------+--------------------------------------------------------------------+------------+------------+------------+ 11 rows in set (0.01 sec)
-
針對特定SQL進行讀寫分離規則(生產環境強烈建議使用此模式)
因為生產環境業務情況較為固定,SQL類別總體上有一個固定範圍。根據業務情況,並不是將所有讀寫進行分離就是最佳方案,很多時候只許將特定的一些SQL集路由到slave上進行讀,而大部分業務還保留在主庫。
這時便用上了基於digest進行讀寫分離的規則。一般將特別大事務量的查詢,或特別頻繁的查詢路由到slave上。
不過digest是完全正則匹配, 如果出現大小寫、多空格等情況,生成的digest是不同的,無法利用上規則比如,上一個實驗裡,0xBF001A0C13781C1D 這個sql運行了4087次,其它sql都遠低於該值。那麼我們就為這個sql指定規則。
mysql> insert into mysql_query_rules(rule_id,active,digest,destination_hostgroup,apply) values(3,1,'0xBF001A0C13781C1D',101,1); Query OK, 1 row affected (0.00 sec) mysql> update mysql_query_rules set active=0 , apply=0 where rule_id in (1,2); Query OK, 2 rows affected (0.00 sec) mysql> select rule_id,active,digest,destination_hostgroup,apply from mysql_query_rules; +---------+--------+--------------------+-----------------------+-------+ | rule_id | active | digest | destination_hostgroup | apply | +---------+--------+--------------------+-----------------------+-------+ | 1 | 0 | NULL | 100 | 0 | | 2 | 0 | NULL | 101 | 0 | | 3 | 1 | 0xBF001A0C13781C1D | 101 | 1 | +---------+--------+--------------------+-----------------------+-------+ 3 rows in set (0.00 sec) mysql> select * from stats.stats_mysql_query_digest_reset; Empty set (0.00 sec) mysql> load mysql query rules to run; Query OK, 0 rows affected (0.00 sec) mysql> save mysql query rules to disk; Query OK, 0 rows affected (0.04 sec)
-
使用sysbench執行事務,並檢視stats.mysql_query_digest
可以看到,0xBF001A0C13781C1D已經被路由到slave,其它事務不受影響,依然在master進行。[14:58:57] root@ms84:~ # sysbench /usr/share/sysbench/oltp_read_write.lua --mysql-host=192.168.188.84 --mysql-port=6033 --mysql-user=proxy --mysql-password=proxy --db-driver=mysql --mysql-db=kk --table-size=5000 run mysql> select hostgroup, digest, digest_text, count_star, first_seen, last_seen from stats.stats_mysql_query_digest; +-----------+--------------------+--------------------------------------------------------------------+------------+------------+------------+ | hostgroup | digest | digest_text | count_star | first_seen | last_seen | +-----------+--------------------+--------------------------------------------------------------------+------------+------------+------------+ | 100 | 0xE52A0A0210634DAC | INSERT INTO sbtest1 (id, k, c, pad) VALUES (?, ?, ?, ?) | 653 | 1589871539 | 1589871549 | | 100 | 0xE365BEB555319B9E | DELETE FROM sbtest1 WHERE id=? | 653 | 1589871539 | 1589871549 | | 100 | 0xFB239BC95A23CA36 | UPDATE sbtest1 SET c=? WHERE id=? | 653 | 1589871539 | 1589871549 | | 100 | 0xC198E52BCCB481C7 | UPDATE sbtest1 SET k=k+? WHERE id=? | 653 | 1589871539 | 1589871549 | | 100 | 0xC19480748AE79B4B | SELECT DISTINCT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c | 653 | 1589871539 | 1589871549 | | 100 | 0xDBF868B2AA296BC5 | SELECT SUM(k) FROM sbtest1 WHERE id BETWEEN ? AND ? | 653 | 1589871539 | 1589871549 | | 100 | 0x290B92FD743826DA | SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ? | 653 | 1589871539 | 1589871549 | | 101 | 0xBF001A0C13781C1D | SELECT c FROM sbtest1 WHERE id=? | 6521 | 1589871539 | 1589871549 | | 100 | 0x695FBF255DBEB0DD | COMMIT | 653 | 1589871539 | 1589871549 | | 100 | 0xAC80A5EA0101522E | SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c | 653 | 1589871539 | 1589871549 | | 100 | 0xFAD1519E4760CBDE | BEGIN | 653 | 1589871539 | 1589871549 | +-----------+--------------------+--------------------------------------------------------------------+------------+------------+------------+ 11 rows in set (0.01 sec)
-