os:rhel 7.3
mysql: 5.7
proxysql:1.4.15-1

ip 规划如下:

172.25.11.1 node1 (proxysql)

172.25.11.2 node2 (mysql master)
172.25.11.3 node3 (mysql slave)
172.25.11.4 node4 (mysql slave)

node 2 3 4 安装mysql5.7并且初始化

 yum install mysql-community-client-5.7.24-1.el7.x86_64.rpm mysql-community-common-5.7.24-1.el7.x86_64.rpm mysql-community-libs-5.7.24-1.el7.x86_64.rpm mysql-community-libs-compat-5.7.24-1.el7.x86_64.rpm mysql-community-server-5.7.24-1.el7.x86_64.rpm -y

node2

server-id=1
log-bin=mysql-bin
gtid-mode=on
enforce-gtid-consistency=1

grep password /var/log/mysqld.log

mysql> alter user root@localhost identified by 'Yakexi_007';
Query OK, 0 rows affected (0.12 sec)

mysql> grant replication slave on *.* to repl@'172.25.11.%' identified by 'Yakexi+007';
Query OK, 0 rows affected, 1 warning (0.40 sec)

mysql> Flush privileges;
Query OK, 0 rows affected (0.19 sec)

mysql> show master status;
+------------------+----------+--------------+------------------+------------------------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                        |
+------------------+----------+--------------+------------------+------------------------------------------+
| mysql-bin.000002 |      843 |              |                  | ba8f407d-389f-11e9-95ea-525400d000e0:1-3 |
+------------------+----------+--------------+------------------+------------------------------------------+
1 row in set (0.00 sec)

 

 

注意点:slave节点需要设置read_only=1。

node3

server-id=2
gtid-mode=on
enforce-gtid-consistency=1

read_only=1

mysql> change master to master_host='172.25.11.2',
    -> master_user='repl',
    -> master_password='Yakexi+007',
    -> master_log_file='mysql-bin.000002',
    -> master_log_pos=843;

start slave;

node4

server-id=3
gtid-mode=on
enforce-gtid-consistency=1

read_only=1

 

mysql> change master to master_host='172.25.11.2',
    -> master_user='repl',
    -> master_password='Yakexi+007',
    -> master_log_file='mysql-bin.000002',
    -> master_log_pos=843;

start slave;

 

 

 

node1 安装proxysql

 

解决依赖性

yum install -y  automake bzip2 cmake make g++ gcc git openssl debconf-utils

 yum install perl-DBI perl-DBD-MySQL perl-Time-HiRes perl-IO-Socket-SSL -y

yum install proxysql-1.4.15-1-centos7.x86_64.rpm -y

mysql读写分离与监控的使用(proxysql)_sql

cp /etc/proxysql.cnf /etc/proxysql.cnf.bak

systemctl start proxysql

mysql读写分离与监控的使用(proxysql)_sql_02

mysql读写分离与监控的使用(proxysql)_sql_03

根据 /etc/proxysql.cnf 文件内容,6032 是管理端口,6033 是 mysql 连接端口。

用server1本地连接proxysql  他的默认帐号密码admin

mysql -u admin -padmin -h 127.0.0.1 -P6032 --prompt='Admin> '

也可以mysql -uadmin -padmin -h 127.0.0.1 -P 6032

mysql读写分离与监控的使用(proxysql)_sql_04

 

mysql读写分离与监控的使用(proxysql)_sql_05

下面搜索到了main主库的资料

main 数据库

内存配置数据库,即MEMORY,表里存放后端db实例、用户验证、路由规则等信息。表名以runtime_开头的表示ProxySQL当前运行的配置内容,不能通过DML语句修改。只能修改对应的不以 runtime开头的表,然后“LOAD”使其生效,“SAVE”使其存到硬盘以供下次重启加载。

disk 数据库

持久化到硬盘的配置,sqlite数据文件。

stats 数据库

proxysql运行抓取的统计信息,包括到后端各命令的执行次数、流量、processlist、查询种类汇总/执行时间等等。

monitor 数据库

存储 monitor 模块收集的信息,主要是对后端db的健康/延迟检查。

 

Admin> use main;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
Admin> show tables;
+--------------------------------------------+
| tables                                     |
+--------------------------------------------+
| global_variables                           |
| mysql_collations                           |
| mysql_group_replication_hostgroups         |
| mysql_query_rules                          |
| mysql_query_rules_fast_routing             |
| mysql_replication_hostgroups               |
| mysql_servers                              |
| mysql_users                                |
| proxysql_servers                           |
| runtime_checksums_values                   |
| runtime_global_variables                   |
| 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_scheduler                          |
| scheduler                                  |
+--------------------------------------------+
20 rows in set (0.00 sec)

 

下面查看全局变量

Admin> select * from global_variables;
+-----------------------------------------------------+--------------------+
| variable_name                                       | variable_value     |
+-----------------------------------------------------+--------------------+
| mysql-shun_on_failures                              | 5                  |
| mysql-shun_recovery_time_sec                        | 10                 |
| mysql-query_retries_on_failure                      | 1                  |
| mysql-client_multi_statements                       | true               |
| mysql-connect_retries_delay                         | 1                  |
| mysql-connection_delay_multiplex_ms                 | 0                  |
| mysql-connection_max_age_ms                         | 0                  |
| mysql-connect_timeout_server_max                    | 10000              |
| mysql-eventslog_filename                            |                    |
| mysql-eventslog_filesize                            | 104857600          |
| mysql-default_charset                               | utf8               |
| mysql-free_connections_pct                          | 10                 |
| mysql-session_idle_ms                               | 1000               |
| mysql-client_found_rows                             | true               |
| mysql-monitor_enabled                               | true               |
| mysql-monitor_connect_timeout                       | 600                |
| mysql-monitor_ping_max_failures                     | 3                  |
| mysql-monitor_ping_timeout                          | 1000               |
| mysql-monitor_read_only_max_timeout_count           | 3                  |
| mysql-monitor_replication_lag_interval              | 10000              |
| mysql-monitor_replication_lag_timeout               | 1000               |
| mysql-monitor_groupreplication_healthcheck_interval | 5000               |
| mysql-monitor_groupreplication_healthcheck_timeout  | 800                |
| mysql-monitor_replication_lag_use_percona_heartbeat |                    |
| mysql-monitor_query_interval                        | 60000              |
| mysql-monitor_query_timeout                         | 100                |
| mysql-monitor_slave_lag_when_null                   | 60                 |
| mysql-monitor_wait_timeout                          | true               |
| mysql-monitor_writer_is_also_reader                 | true               |
| mysql-max_allowed_packet                            | 4194304            |
| mysql-throttle_connections_per_sec_to_hostgroup     | 1000000            |
| mysql-max_transaction_time                          | 14400000           |
| mysql-multiplexing                                  | true               |
| mysql-forward_autocommit                            | false              |
| mysql-enforce_autocommit_on_reads                   | false              |
| mysql-autocommit_false_not_reusable                 | false              |
| mysql-autocommit_false_is_transaction               | false              |
| mysql-verbose_query_error                           | false              |
| mysql-hostgroup_manager_verbose                     | 1                  |
| mysql-threshold_query_length                        | 524288             |
| mysql-threshold_resultset_size                      | 4194304            |
| mysql-query_digests_max_digest_length               | 2048               |
| mysql-query_digests_max_query_length                | 65000              |
| mysql-wait_timeout                                  | 28800000           |
| mysql-throttle_max_bytes_per_second_to_client       | 2147483647         |
| mysql-throttle_ratio_server_to_client               | 0                  |
| mysql-max_stmts_per_connection                      | 20                 |
| mysql-max_stmts_cache                               | 10000              |
| mysql-mirror_max_concurrency                        | 16                 |
| mysql-mirror_max_queue_length                       | 32000              |
| mysql-default_max_latency_ms                        | 1000               |
| mysql-query_processor_iterations                    | 0                  |
| mysql-query_processor_regex                         | 1                  |
| mysql-auto_increment_delay_multiplex                | 5                  |
| mysql-long_query_time                               | 1000               |
| mysql-query_cache_size_MB                           | 256                |
| mysql-poll_timeout_on_failure                       | 100                |
| mysql-server_capabilities                           | 45578              |
| mysql-kill_backend_connection_when_disconnect       | true               |
| mysql-session_idle_show_processlist                 | true               |
| mysql-query_digests                                 | true               |
| mysql-query_digests_lowercase                       | false              |
| mysql-servers_stats                                 | true               |
| mysql-default_reconnect                             | true               |
| mysql-ssl_p2s_ca                                    |                    |
| mysql-ssl_p2s_cert                                  |                    |
| mysql-ssl_p2s_key                                   |                    |
| mysql-ssl_p2s_cipher                                |                    |
| mysql-init_connect                                  |                    |
| mysql-default_sql_mode                              |                    |
| mysql-default_time_zone                             | SYSTEM             |
| mysql-connpoll_reset_queue_length                   | 50                 |
| mysql-stats_time_backend_query                      | false              |
| mysql-stats_time_query_processor                    | false              |
| admin-stats_credentials                             | stats:stats        |
| admin-stats_mysql_connections                       | 60                 |
| admin-stats_mysql_connection_pool                   | 60                 |
| admin-stats_mysql_query_cache                       | 60                 |
| admin-stats_system_cpu                              | 60                 |
| admin-stats_system_memory                           | 60                 |
| admin-telnet_admin_ifaces                           | (null)             |
| admin-telnet_stats_ifaces                           | (null)             |
| admin-refresh_interval                              | 2000               |
| admin-read_only                                     | false              |
| admin-hash_passwords                                | true               |
| admin-version                                       | 1.4.15-1-g61bc777  |
| admin-cluster_username                              |                    |
| admin-cluster_password                              |                    |
| admin-cluster_check_interval_ms                     | 1000               |
| admin-cluster_check_status_frequency                | 10                 |
| admin-cluster_mysql_query_rules_diffs_before_sync   | 3                  |
| admin-cluster_mysql_servers_diffs_before_sync       | 3                  |
| admin-cluster_mysql_users_diffs_before_sync         | 3                  |
| admin-cluster_proxysql_servers_diffs_before_sync    | 3                  |
| admin-cluster_mysql_query_rules_save_to_disk        | true               |
| admin-cluster_mysql_servers_save_to_disk            | true               |
| admin-cluster_mysql_users_save_to_disk              | true               |
| admin-cluster_proxysql_servers_save_to_disk         | true               |
| admin-checksum_mysql_query_rules                    | true               |
| admin-checksum_mysql_servers                        | true               |
| admin-checksum_mysql_users                          | true               |
| admin-web_enabled                                   | false              |
| admin-web_port                                      | 6080               |
| admin-admin_credentials                             | admin:admin        |
| admin-mysql_ifaces                                  | 0.0.0.0:6032       |
| mysql-threads                                       | 4                  |
| mysql-max_connections                               | 2048               |
| mysql-default_query_delay                           | 0                  |
| mysql-default_query_timeout                         | 36000000           |
| mysql-have_compress                                 | true               |
| mysql-poll_timeout                                  | 2000               |
| mysql-interfaces                                    | 0.0.0.0:6033       |
| mysql-default_schema                                | information_schema |
| mysql-stacksize                                     | 1048576            |
| mysql-server_version                                | 5.5.30             |
| mysql-connect_timeout_server                        | 3000               |
| mysql-monitor_username                              | monitor            |
| mysql-monitor_password                              | monitor            |
| mysql-monitor_history                               | 600000             |
| mysql-monitor_connect_interval                      | 60000              |
| mysql-monitor_ping_interval                         | 10000              |
| mysql-monitor_read_only_interval                    | 1500               |
| mysql-monitor_read_only_timeout                     | 500                |
| mysql-ping_interval_server_msec                     | 120000             |
| mysql-ping_timeout_server                           | 500                |
| mysql-commands_stats                                | true               |
| mysql-sessions_sort                                 | true               |
| mysql-connect_retries_on_failure                    | 10                 |
+-----------------------------------------------------+--------------------+
128 rows in set (0.00 sec)

mysql_query_rules
指定Query路由到后端不同​​​服务器​​的规则列表。

mysql_replication_hostgroups
监视指定主机组中所有服务器的read_only值,并且根据read_only的值将服务器分配给写入器或读取器主机组

定义 hostgroup 的主从关系。ProxySQL monitor 模块会监控 HG 后端所有servers 的 read_only 变量,如果发现从库的 read_only 变为0、主库变为1,则认为角色互换了,自动改写 mysql_servers 表里面 hostgroup 关系,达到自动 Failover 效果。

mysql_servers
后端可以连接MySQL服务器的列表。

mysql_users
配置后端数据库的账号和监控的账号

scheduler
调度器是一个类似于​​​cron​​的实现,集成在ProxySQL中,具有毫秒的粒度。通过脚本检测来设置ProxySQL。

 

Admin> set mysql-threads = 100;

runtime_开头的是运行时的配置,这些是不能修改的。要修改ProxySQL的配置,需要修改了非runtime_ 表,修改后必须执行LOAD ... TO RUNTIME才能加载到RUNTIME生效,执行save ... to disk才能将配置持久化保存到磁盘。

现在添加节点

insert into mysql_servers(hostgroup_id,hostname,port) values(10,'172.25.11.2',3306);

insert into mysql_servers(hostgroup_id,hostname,port) values(10,'172.25.11.3',3306);

insert into mysql_servers(hostgroup_id,hostname,port) values(10,'172.25.11.4',3306);

#使用insert语句添加主机到mysql_servers表中,其中:hostgroup_id 10 表示写组,20表示读组。

select * from mysql_servers\G;

查看状态

*************************** 1. row ***************************
       hostgroup_id: 10
           hostname: 172.25.11.2
               port: 3306
             status: ONLINE
             weight: 1
        compression: 0
    max_connections: 1000
max_replication_lag: 0
            use_ssl: 0
     max_latency_ms: 0
            comment:
*************************** 2. row ***************************
       hostgroup_id: 10
           hostname: 172.25.11.3
               port: 3306
             status: ONLINE
             weight: 1
        compression: 0
    max_connections: 1000
max_replication_lag: 0
            use_ssl: 0
     max_latency_ms: 0
            comment:
*************************** 3. row ***************************
       hostgroup_id: 10
           hostname: 172.25.11.4
               port: 3306
             status: ONLINE
             weight: 1
        compression: 0
    max_connections: 1000
max_replication_lag: 0
            use_ssl: 0
     max_latency_ms: 0
            comment:
3 rows in set (0.00 sec)

修改后,加载到RUNTIME,并保存到disk。

load mysql servers to runtime;

save mysql servers to disk;

监控后端MySQL节点

添加节点之后,还需要监控后端节点。对于后端是主从复制的环境来说,这是必须的,因为ProxySQL需要通过每个节点的read_only值来 自动调整它们是属于读组还是写组。

首先在后端master节点上创建一个用于监控的用户名(只需在master上创建即可,因 为会复制到slave上),这个用户名只需具有USAGE权 限即可。如果还需要监控复制结构中slave是否严重延迟于master(这个俗语叫做"拖后 腿",术语叫做"replication lag"),则还需具备replication client权限。这里直接赋予这个权限。

 

 

MASTER上

create user monitor@'172.25.11.%' identified by 'Yakexi+007';

grant replication client on *.* to monitor@'172.25.11.%';

 

ProxySQL上配置监控

mysql> set mysql-monitor_username='monitor';
Query OK, 1 row affected (0.00 sec)

mysql> set mysql-monitor_password='Yakexi+007';
Query OK, 1 row affected (0.00 sec)

修改后,加载到RUNTIME,并保存到disk。

mysql> load mysql variables to runtime;
Query OK, 0 rows affected (0.01 sec)

mysql> save mysql variables to disk;
Query OK, 97 rows affected (0.19 sec)

 

验证监控结果:ProxySQL监控模块的指标都保存在monitor库的log表中。

select * from mysql_server_connect_log\G;

select * from mysql_server_connect_log;

mysql读写分离与监控的使用(proxysql)_数据库_06

 

心跳信息的监控(对ping指标的监控)

select * from mysql_server_ping_log;

select * from mysql_server_ping_log\G;

mysql读写分离与监控的使用(proxysql)_数据库_07

 

select hostgroup_id,hostname,port,status,weight from mysql_servers;

查看各组信息

mysql读写分离与监控的使用(proxysql)_数据库_08

mysql> select * from mysql_server_read_only_log;
Empty set (0.01 sec)

mysql> select * from mysql_server_replication_lag_log;
Empty set (0.00 sec)

发现日志为空

下面修改

mysql> insert into mysql_replication_hostgroups values(10,20,1);
Query OK, 1 row affected (0.01 sec)

mysql> select hostgroup_id,hostname,port,status,weight from mysql_servers;
+--------------+-------------+------+--------+--------+
| hostgroup_id | hostname    | port | status | weight |
+--------------+-------------+------+--------+--------+
| 10           | 172.25.11.2 | 3306 | ONLINE | 1      |
| 10           | 172.25.11.3 | 3306 | ONLINE | 1      |
| 10           | 172.25.11.4 | 3306 | ONLINE | 1      |
+--------------+-------------+------+--------+--------+
3 rows in set (0.00 sec)

写入磁盘后会生效

mysql> load mysql servers to runtime;
Query OK, 0 rows affected (0.01 sec)

mysql> save mysql servers to disk;
Query OK, 0 rows affected (0.45 sec)

mysql> select hostgroup_id,hostname,port,status,weight from mysql_servers;
+--------------+-------------+------+--------+--------+
| hostgroup_id | hostname    | port | status | weight |
+--------------+-------------+------+--------+--------+
| 10           | 172.25.11.2 | 3306 | ONLINE | 1      |
| 20           | 172.25.11.4 | 3306 | ONLINE | 1      |
| 20           | 172.25.11.3 | 3306 | ONLINE | 1      |
+--------------+-------------+------+--------+--------+
3 rows in set (0.00 sec)

所有节点都在id=10的写组,slave1和slave2都是slave,它们的read_only=1,这两个节点将会移动到id=20的组。如果一开始这3节点都在id=20的读组 ,那么移动的将是Master节点,会移动到id=10的写组。

mysql读写分离与监控的使用(proxysql)_数据库_09

这时就会有监控日志了

配置mysql_users

上面的所有配置都是关于后端MySQL节点的,现在可以配置关于SQL语句的,包括:发送 SQL语句的用户、SQL语句的路由规则、SQL查询的缓存、SQL语句的重写等等。本小节是SQL请求所使用的用户配置,例如root用户。这要求我们 需要先在后端MySQL节点添加好相关用户。这里以root和test两个用户名为例。

master节点上执行:(只需master执行即可,会复制给两个slave)

grant all on *.* to root@'172.25.11.%' identified by 'Yakexi_007';

grant all on *.* to test@'172.25.11.%' identified by 'Yakexi_007';

ProxySQL端,配置mysql_users表,将刚才的两个用户添加到该表中。

mysql> insert into mysql_users(username,password,default_hostgroup) values('root','Yakexi_007',10);
Query OK, 1 row affected (0.00 sec)

mysql> insert into mysql_users(username,password,default_hostgroup) values('test','Yakexi_007',10);
Query OK, 1 row affected (0.00 sec)

mysql> load mysql users to runtime;
Query OK, 0 rows affected (0.00 sec)

mysql> save mysql users to disk;
Query OK, 0 rows affected (0.27 sec)

 

mysql_users表有不少字段,最主要的三个字段为username、password和default_hostgroup:

  • username:前端连接ProxySQL,以及ProxySQL将SQL语句路由给MySQL所使用的用户名。
  • password:用户名对应的密码。可以是明文密码,也可以是hash密码。如果想使用hash密码,可以先在某个MySQL节点上执行select password(PASSWORD),然后将加密结果复制到该字段。
  • default_hostgroup:该用户名默认的路由目标。例如,指定root用户的该字段值为10时,则使用root用户发送的SQL语句默认情况下将路由到hostgroup_id=10组中的某个节点。

select * from mysql_users;

mysql读写分离与监控的使用(proxysql)_mysql_10

只有active=1的用户才是有效的用户。

至于transaction_persistent字段,当它的值为1时,表示事务持久化: 当某连接使用该用户开启了一个事务后,那么在事务提交/回滚之前,所有的语句都路由到同一个组中,避免语句分散到不同组。

在以前的版本中,默认值为0,不 知道从哪个版本开始,它的默认值为1。如果为0,则执行下面的语句修改为1。

update mysql_users set transaction_persistent=1 where username='root';

mysql> load mysql users to runtime;
Query OK, 0 rows affected (0.00 sec)

mysql> save mysql users to disk;
Query OK, 0 rows affected (0.27 sec)

测试刚才的用户能否使用

mysql读写分离与监控的使用(proxysql)_sql_11

 

读写分离:配置路由规则

ProxySQL的路由规则非常灵活,可以基于用户、基于schema以及基于每个语句实现 路由规则的定制。本文只是实验,实际的路由规则绝不应该仅根据所谓的读、 写操作进行分离,而是从各项指标中找出压力大、执行频繁的语句单独写规则、做缓存等等。和查询规则有关的表有两个:mysql_query_rules和 mysql_query_rules_fast_routing,后者是前者的扩展表,1.4.7之后才支持该快速路由表。本文只介绍第一个表。插入两个 规则,目的是将select语句分离到hostgroup_id=20的读组,但由于select语句中有一个特殊语句SELECT...FOR UPDATE它会申请写锁,所以应该路由到hostgroup_id=10的写组。

 

PROXYSQL端

mysql> insert into
    -> mysql_query_rules(rule_id,active,match_digest,destination_hostgroup,apply) VALUES (1,1,'^SELECT.*FOR UPDATE$',10,1), (2,1,'^SELECT',20,1);
Query OK, 2 rows affected (0.00 sec)

mysql> load mysql query rules to runtime;
Query OK, 0 rows affected (0.00 sec)

mysql> save mysql query rules to disk;
Query OK, 0 rows affected (0.36 sec)

 

select ... for update规则的rule_id必须要小于普通的select规则的rule_id,因为ProxySQL是根据rule_id的顺序进行规则匹配的。

测试下,读操作是否路由给了hostgroup_id=20的读组。

mysql -uroot -pYakexi_007 -P6033 -h127.0.0.1 -e 'select @@server_id'

mysql读写分离与监控的使用(proxysql)_数据库_12

 

 

看看写操作。这里以事务持久化进行测试。

 

mysql -uroot -pYakexi_007 -P6033 -h127.0.0.1

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|           1 |
+-------------+
1 row in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|           3 |
+-------------+
1 row in set (0.00 sec)

 

mysql读写分离与监控的使用(proxysql)_mysql_13

查看路由的信息,可查询stats库中的stats_mysql_query_digest表。

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                      |
+----+----------+------------+----------------------------------+
| 10 | 114385   | 1          | create database proxy_test       |
| 20 | 6455     | 3          | select @@server_id               |
| 10 | 2018     | 1          | show databases                   |
| 10 | 1062     | 1          | commit                           |
| 10 | 787      | 1          | start transaction                |
| 10 | 0        | 7          | select @@version_comment limit ? |
+----+----------+------------+----------------------------------+
7 rows in set (0.00 sec)

可以看出 读的组为20  写的组为10