MySQL [(none)]> show tables from disk;
+------------------------------------+
| tables |
+------------------------------------+
| global_variables | # (1)
| mysql_collations | # (N)
| mysql_group_replication_hostgroups | # (2)
| mysql_query_rules | # (3)
| mysql_query_rules_fast_routing | # (4)
| mysql_replication_hostgroups | # (5)
| mysql_servers | # (6)
| mysql_users | # (7)
| proxysql_servers | # (8)
| scheduler | # (9)
+------------------------------------+
10 rows in set (0.00 sec)
上面的结果中我给这些表都标注了一些序号,其所对应的表的内容有以下讲究:
(1)中包含两类变量,以amdin-开头的表示admin variables,以mysql-开头的表示mysql variables。修改哪类变量,前文的XXX就代表哪类
(2,5,6)对应的都是mysql servers
(3,4)对应的是mysql query rules
(7)对应的mysql users
(9)对应的scheduler
(N)只是一张表,保存的是ProxySQL支持的字符集和排序规则,它是不用修改的
(8)是ProxySQL的集群配置表,该功能目前还处于实验阶段。如果想要配置该功能,则load/save proxysql_servers to/from ...
6.3 启动ProxySQL时如何加载配置
如果 ProxySQL 是刚安装的,或者磁盘数据库文件为空(甚至不存在),或者启动 ProxySQL 时使用了选项 --initial,这几种情况启动 ProxySQL 时,都会从传统配置文件 config file 中读取配置加载到内存数据库,并自动 load 到 runtime 数据结构、save到磁盘数据库,这是初始化 ProxySQL 运行环境的过程。
如果不是第一次启动 ProxySQL ,由于已经存在磁盘数据库文件,这时 ProxySQL 会从磁盘数据库中读取几乎所有的配置(即使传统配置文件中配置了某项,也不会去解析),但有3项是必须从传统配置文件中读取,它们分别是:
datadir:ProxySQL启动时,必须从配置文件中确定它的数据目录,因为磁盘数据库文件、日志以及其它一些文件是存放在数据目录下的。如果使用/etc/init.d/proxysql管理ProxySQL,则除了修改/etc/proxysql.cnf的datadir,还需要修改该脚本中的datadir。
restart_on_missing_heartbeats:MySQL线程丢失多少次心跳,就会杀掉这个线程并重启它。默认值为10。
execute_on_exit_failure:如果设置了该变量,ProxySQL父进程将在每次ProxySQL崩溃的时候执行已经定义好的脚本。建议使用它来生成一些崩溃时的警告和日志。注意,ProxySQL的重启速度可能只有几毫秒,因此很多其它的监控工具可能无法探测到ProxySQL的一次普通故障,此时可使用该变量
7. 不同类型的读写分离方案解析
数据库中间件最基本的功能就是实现读写分离, ProxySQL 当然也支持。而且 ProxySQL 支持的路由规则非常灵活,不仅可以实现最简单的读写分离,还可以将读/写都分散到多个不同的组,以及实现分库 sharding (分表sharding的规则比较难写,但也能实现)。
本文只描述通过规则制定的语句级读写分离,不讨论通过 ip/port, client, username, schemaname 实现的读写分离。
下面描述了ProxySQL能实现的常见读写分离类型
7.1 最简单的读写分离
这种模式的读写分离,严格区分后端的master和slave节点,且slave节点必须设置选项read_only=1
在ProxySQL上,分两个组,一个写组HG=10,一个读组HG=20。同时在ProxySQL上开启monitor模块的read_only监控功能,让ProxySQL根据监控到的read_only值来自动调整节点放在HG=10(master会放进这个组)还是HG=20(slave会放进这个组)
这种模式的读写分离是最简单的,只需在mysql_users表中设置用户的默认路由组为写组HG=10,并在mysql_query_rules中加上两条简单的规则(一个select for update,一个select)即可
这种读写分离模式,在环境较小时能满足绝大多数需求。但是需求复杂、环境较大时,这种模式就太过死板,因为一切都是monitor模块控制的
7.2 多个读组或写组的分离模式
前面那种读写分离模式,是通过 monitor 模块监控 read_only 来调整的,所以每一个后端集群必须只能分为一个写组,一个读组。
但如果想要区分不同的 select ,并将不同的 select 路由到不同的节点上。例如有些查询语句的开销非常大,想让它们独占一个节点/组,其它查询共享一个节点/组,怎么实现?
例如,下面这种模式
看上去非常简单。但是却能适应各种需求。例如,后端做了分库,对某库的查询要路由到特定的主机组
至于各个主机组是同一个主从集群(下图左边),还是互相独立的主从集群环境(下图右边),要看具体的需求,不过这种读写分离模式都能应付
在实现这种模式时,前提是不能开启monitor模块的read_only监控功能,也不要设置mysql_replication_hostgroup 表
例如,下面的配置实现的是上图左边的结构:写请求路由给HG=10,对test1库的select语句路由给HG=20,其它select路由给HG=30
mysql_servers:
+--------------+----------+------+--------+--------+
| hostgroup_id | hostname | port | status | weight |
+--------------+----------+------+--------+--------+
| 10 | host1 | 3306 | ONLINE | 1 |
| 20 | host2 | 3306 | ONLINE | 1 |
| 30 | host3 | 3306 | ONLINE | 1 |
+--------------+----------+------+--------+--------+
mysql_users:
+----------+-------------------+
| username | default_hostgroup |
+----------+-------------------+
| root | 10 |
+----------+-------------------+
mysql_query_rules:
+---------+-----------------------+----------------------+
| rule_id | destination_hostgroup | match_digest |
+---------+-----------------------+----------------------+
| 1 | 10 | ^SELECT.*FOR UPDATE$ |
| 2 | 20 | ^SELECT.*test1\..* |
| 3 | 30 | ^SELECT |
+---------+-----------------------+----------------------+
查看表结构的方式:
PRAGMA table_info("表名");
8. ProxySQL实现读写分离示例
环境说明:
//配置proxysql的yum源
[root@proxysql ~]# cat <<EOF | tee /etc/yum.repos.d/proxysql.repo
[proxysql_repo]
name= ProxySQL
baseurl=http://repo.proxysql.com/ProxySQL/proxysql-1.4.x/centos/7
gpgcheck=1
gpgkey=http://repo.proxysql.com/ProxySQL/repo_pub_key
//安装proxysql
[root@proxysql ~]# yum -y install proxysql
//启动proxysql并设置开机自动启动
//proxysql默认只提供了sysv风格的启动脚本,所以想设置开机自启则需借助于chkconfig工具
[root@proxysql ~]# systemctl start proxysql
[root@proxysql ~]# chkconfig proxysql on
8.2 配置ProxySQL
8.2.1 mysql主库添加proxysql可以增删改查的账号
mysql> grant all on *.* to 'proxysql'@'172.16.12.128' identified by 'pwproxysql';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)
8.2.2 登录proxysql管理端
[root@proxysql ~]# yum -y install mariadb
[root@proxysql ~]# export MYSQL_PS1="(\u@\h:\p) [\d]> "
[root@proxysql ~]# mysql -uadmin -padmin -h127.0.0.1 -P6032
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.5.30 (ProxySQL Admin Module)
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
([email protected]:6032) [(none)]> 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)
数据库说明:
main 内存配置数据库,表里存放后端db实例、用户验证、路由规则等信息。表名以 runtime开头的表示proxysql当前运行的配置内容,不能通过dml语句修改,只能修改对应的不以 runtime 开头的(在内存)里的表,然后 LOAD 使其生效, SAVE 使其存到硬盘以供下次重启加载
disk 是持久化到硬盘的配置,sqlite数据文件
stats 是proxysql运行抓取的统计信息,包括到后端各命令的执行次数、流量、processlist、查询种类汇总/执行时间等等
monitor 库存储 monitor 模块收集的信息,主要是对后端db的健康/延迟检查
stats_history 统计信息历史库
8.2.3 Proxysql管理端添加后端连接mysql主从数据库的配置
([email protected]:6032) [(none)]> show tables from main;
+--------------------------------------------+
| tables |
+--------------------------------------------+
| global_variables | # ProxySQL的基本配置参数,类似与MySQL
| mysql_collations | # 配置对MySQL字符集的支持
| mysql_group_replication_hostgroups | # MGR相关的表,用于实例的读写组自动分配
| mysql_query_rules | # 路由表
| mysql_query_rules_fast_routing | # 主从复制相关的表,用于实例的读写组自动分配
| mysql_replication_hostgroups | # 存储MySQL实例的信息
| mysql_servers | # 存储MySQL用户
| mysql_users | # 存储ProxySQL的信息,用于ProxySQL Cluster同步
| 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)
runtime_ 开头的是运行时的配置,这些是不能修改的。要修改 ProxySQL 的配置,需要修改了非 runtime_ 表,修改后必须执行 LOAD ... TO RUNTIME 才能加载到 RUNTIME 生效,执行 save ... to disk 才能将配置持久化保存到磁盘
下面语句中没有先切换到 main 库也执行成功了,因为 ProxySQL 内部使用的 SQLite3 数据库引擎,和 MySQL 的解析方式是不一样的。即使执行了 USE main 语句也是无任何效果的,但不会报错
使用 insert 语句添加 mysql 主机到 mysql_servers 表中,其中:hostgroup_id 1 表示写组,2表示读组
([email protected]:6032) [(none)]> insert into mysql_servers(hostgroup_id,hostname,port,weight,comment) values(1,'172.16.12.129',3306,1,'Write Group');
Query OK, 1 row affected (0.00 sec)
([email protected]:6032) [(none)]> insert into mysql_servers(hostgroup_id,hostname,port,weight,comment) values(2,'172.16.12.130',3306,1,'Read Group');
Query OK, 1 row affected (0.00 sec)
([email protected]:6032) [(none)]> select * from mysql_servers;
+--------------+---------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+-------------+
| hostgroup_id | hostname | port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+---------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+-------------+
| 1 | 172.16.12.129 | 3306 | ONLINE | 1 | 0 | 1000 | 0 | 0 | 0 | Write Group |
| 2 | 172.16.12.130 | 3306 | ONLINE | 1 | 0 | 1000 | 0 | 0 | 0 | Read Group |
+--------------+---------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+-------------+
2 rows in set (0.00 sec)
修改后,需要加载到RUNTIME,并保存到disk
([email protected]:6032) [(none)]> load mysql servers to runtime;
Query OK, 0 rows affected (0.01 sec)
([email protected]:6032) [(none)]> save mysql servers to disk;
Query OK, 0 rows affected (0.01 sec)
在 proxysql 主机的 mysql_users 表中添加刚才在 master 上创建的账号 proxysql,proxysql 客户端需要使用这个账号来访问数据库
default_hostgroup 默认组设置为写组,也就是1;
当读写分离的路由规则不符合时,会访问默认组的数据库;
([email protected]:6032) [(none)]> insert into mysql_users(username,password,default_hostgroup,transaction_persistent)values('proxysql','pwproxysql',1,1);
Query OK, 1 row affected (0.00 sec)
([email protected]:6032) [(none)]> select * from mysql_users \G
*************************** 1. row ***************************
username: proxysql # 后端mysql实例的用户名
password: pwproxysql # 后端mysql实例的密码
active: 1 # active=1表示用户生效,0表示不生效
use_ssl: 0
default_hostgroup: 1 # 用户默认登录到哪个hostgroup_id下的实例
default_schema: NULL # 用户默认登录后端mysql实例时连接的数据库,这个地方为NULL的话,则由全局变量mysql-default_schema决定,默认是information_schema
schema_locked: 0
transaction_persistent: 1 # 如果设置为1,连接上ProxySQL的会话后,如果在一个hostgroup上开启了事务,那么后续的sql都继续维持在这个hostgroup上,不论是否会匹配上其它路由规则,直到事务结束。虽然默认是0
fast_forward: 0 # 忽略查询重写/缓存层,直接把这个用户的请求透传到后端DB。相当于只用它的连接池功能,一般不用,路由规则 .* 就行了
backend: 1
frontend: 1
max_connections: 10000 # 该用户允许的最大连接数
1 row in set (0.00 sec)
([email protected]:6032) [(none)]> load mysql users to runtime;
Query OK, 0 rows affected (0.00 sec)
([email protected]:6032) [(none)]> save mysql users to disk;
Query OK, 0 rows affected (0.00 sec)
8.2.4 添加健康检测的帐号
在mysql的 master 端添加属于proxysql的只读账号
mysql> GRANT SELECT ON *.* TO 'monitor'@'172.16.12.%' IDENTIFIED BY 'monitor';
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
在proxysql主机端修改变量设置健康检测的账号
([email protected]:6032) [(none)]> set mysql-monitor_username='monitor';
Query OK, 1 row affected (0.00 sec)
([email protected]:6032) [(none)]> set mysql-monitor_password='monitor';
Query OK, 1 row affected (0.00 sec)
([email protected]:6032) [(none)]> load mysql variables to runtime;
Query OK, 0 rows affected (0.00 sec)
([email protected]:6032) [(none)]> save mysql variables to disk;
Query OK, 97 rows affected (0.00 sec)
8.2.5 添加读写分离的路由规则
将 select 查询语句全部路由至 hostgroup_id=2 的组(也就是读组)
但是 select * from tb for update 这样的语句是会修改数据的,所以需要单独定义,将它路由至 hostgroup_id=1 的组(也就是写组)
其他没有被规则匹配到的组将会被路由至用户默认的组(mysql_users 表中的 default_hostgroup)
([email protected]:6032) [(none)]> insert into mysql_query_rules(rule_id,active,match_digest,destination_hostgroup,apply)values(1,1,'^SELECT.*FOR UPDATE$',1,1);
Query OK, 1 row affected (0.00 sec)
([email protected]:6032) [(none)]> insert into mysql_query_rules(rule_id,active,match_digest,destination_hostgroup,apply)values(2,1,'^SELECT',2,1);
Query OK, 1 row affected (0.00 sec)
([email protected]:6032) [(none)]> select rule_id,active,match_digest,destination_hostgroup,apply from mysql_query_rules;
+---------+--------+----------------------+-----------------------+-------+
| rule_id | active | match_digest | destination_hostgroup | apply |
+---------+--------+----------------------+-----------------------+-------+
| 1 | 1 | ^SELECT.*FOR UPDATE$ | 1 | 1 |
| 2 | 1 | ^SELECT | 2 | 1 |
+---------+--------+----------------------+-----------------------+-------+
2 rows in set (0.00 sec)
([email protected]:6032) [(none)]> load mysql query rules to runtime;
Query OK, 0 rows affected (0.01 sec)
([email protected]:6032) [(none)]> load admin variables to runtime;
Query OK, 0 rows affected (0.00 sec)
([email protected]:6032) [(none)]> save mysql query rules to disk;
Query OK, 0 rows affected (0.01 sec)
([email protected]:6032) [(none)]> save admin variables to disk;
Query OK, 31 rows affected (0.00 sec)
8.3 验证读写分离
8.3.1 登录 proxysql 客户端
登录用户是刚才我们在 mysql_user 表中创建的用户,端口为6033
[root@proxysql ~]# mysql -uproxysql -ppwproxysql -h127.0.0.1 -P6033
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.5.30 (ProxySQL)
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
([email protected]:6033) [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.01 sec)
8.3.2 尝试修改数据库和查询
创建2个数据库并查询一下表
([email protected]:6033) [(none)]> create database jinxinruntian;
Query OK, 1 row affected (0.00 sec)
([email protected]:6033) [(none)]> create database wangqing;
Query OK, 1 row affected (0.01 sec)
([email protected]:6033) [(none)]> select user,host from mysql.user;
+---------------+---------------+
| user | host |
+---------------+---------------+
| monitor | 172.16.12.% |
| proxysql | 172.16.12.128 |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+---------------+---------------+
5 rows in set (0.00 sec)
8.3.3 验证读写分离是否成功
proxysql有个类似审计的功能,可以查看各类SQL的执行情况,其需要在proxysql管理端执行
[root@proxysql ~]# mysql -uadmin -padmin -h127.0.0.1 -P6032
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.5.30 (ProxySQL Admin Module)
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
([email protected]:6032) [(none)]> select * from stats_mysql_query_digest;
+-----------+--------------------+----------+--------------------+----------------------------------+------------+------------+------------+----------+----------+----------+
| hostgroup | schemaname | username | digest | digest_text | count_star | first_seen | last_seen | sum_time | min_time | max_time |
+-----------+--------------------+----------+--------------------+----------------------------------+------------+------------+------------+----------+----------+----------+
| 1 | information_schema | proxysql | 0xCE6BB7764BA98E04 | create database jinxinruntian | 1 | 1542612588 | 1542612588 | 2058 | 2058 | 2058 |
| 1 | information_schema | proxysql | 0x34B4BDE2EF8B8AE3 | create database wangqing | 1 | 1542612596 | 1542612596 | 3788 | 3788 | 3788 |
| 2 | information_schema | proxysql | 0x0F02B330C823D739 | select user,host from mysql.user | 3 | 1542612628 | 1542612996 | 20005315 | 4390 | 10000613 |
+-----------+--------------------+----------+--------------------+----------------------------------+------------+------------+------------+----------+----------+----------+
3 rows in set (0.00 sec)
从上面的 hostgroup 和 digest_text 值来看,所有的写操作都被路由至1组,读操作都被路由至2组,其中1组为写组,2组为读组!
由此可见,读写分离成功!!!
Powered by MWeb,
Theme used GitHub CSS. 鄂ICP备17019432号-1