目录
[二、MySQL 主从读写分离实现方案](#二、MySQL 主从读写分离实现方案)
[2.1 ProxySQL实现mysql8主从同步读写分离](#2.1 ProxySQL实现mysql8主从同步读写分离)
一、MySQL主从同步
- MySQL内建的复制功能是构建大型,高性能应用程序的基础
- 通过将MySQL的某一台主机(master)的数据复制到其他主机(slaves)上,并重新执行一遍来执行 复制过程中一台服务器充当主服务器,而其他一个或多个其他服务器充当从服务器
1、MySQL支持的复制类型
- 基于语句(statement)的复制
- 在主服务器上执行SQL语句,在从服务器上执行同样的语句。MySQL默认采用基于语句的复制,效率比较高。
- 基于行(row)的复制
- 把改变的内容复制过去,而不是把命令在从服务器上执行一遍。从MySQL 5.0开始支持。
- 混合型(mixed)的复制
- 默认采用基于语句的复制,一旦发现基于语句的无法精确复制时,就会采用基于行的复制。
2、为什么要做主从复制
- 灾备
- 数据分布
- 负载平衡
- 读写分离
- 提高并发能力
3、主从复制原理
主要基于MySQL二进制日志 主要包括三个线程(2个I/O线程,1个SQL线程)
![](https://i-blog.csdnimg.cn/direct/ac24ef8e80864154a71a2ebc7b521952.png)
1、MySQL将数据变化记录到二进制日志中;
2、Slave将MySQL的二进制日志拷贝到Slave的中继日志中;
3、Slave将中继日志中的事件在做一次,将数据变化,反应到自身(Slave)的数据库
详细步骤:
1、从库通过手工执行change master to 语句连接主库,提供了连接的用户一切条件(user 、password、port、ip),并且让从库知道,二进制日志的起点位置(file名 position 号); start slave
2、从库的IO线程和主库的dump线程建立连接。
3、从库根据change master to 语句提供的file名和position号,IO线程向主库发起binlog的请求。
4、主库dump线程根据从库的请求,将本地binlog以events的方式发给从库IO线程。
5、从库IO线程接收binlog events,并存放到本地relay-log中,传送过来的信息,会记录到master.info中
6、从库SQL线程应用relay-log,并且把应用过的记录到relay-log.info中,默认情况下,已经应用过的relay 会自动被清理purge
![](https://i-blog.csdnimg.cn/direct/00ec2f4849ea43c391d19b6ce6c7c7ff.png)
4、MySQL复制常用的拓扑结构
- 主从类型(Master-Slave)
- 主主类型(Master-Master)
- 级联类型(Master-Slave-Slave)
1、基于**binlog
**的主从同步
主库配置
配置文件:
[root@localhost ~]# tail -1 /etc/my.cnf
server_id=1
[root@localhost ~]# systemctl restart mysqld
备份:
[root@localhost ~]# mysqldump --opt -B db1 it school > db.sql
授权用户:
mysql> create user rep@'172.16.%.%' identified with mysql_native_password by '123456';
mysql> grant replication slave on *.* to rep@'172.16.%.%';
mysql> show master status;
+---------------+----------+--------------+------------------+--------------------------------------------------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+--------------------------------------------------------------------------------------+
| binlog.000015 | 756 | | | 2db179b1-cf96-11ee-8b00-2e6ff2d90c84:1-14,
d09e219c-cec9-11ee-baf1-2e6ff2d90c84:1-46 |
+---------------+----------+--------------+------------------+--------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
从库配置:
配置文件:
[root@localhost ~]# tail -1 /etc/my.cnf
server_id=2
[root@localhost ~]# systemctl restart mysqld
[root@localhost ~]# tail -1 /etc/my.cnf
server_id=3
[root@localhost ~]# systemctl restart mysqld
还原主库备份:
# scp db.sql 172.16.100.22:/root/
# scp db.sql 172.16.100.23:/root/
mysql -uroot -pMySQL@123 < db.sql
mysql> show slave status \G
*************************** 1. row ***************************
Slave_IO_State: Connecting to source
Master_Host: 192.168.150.21
Master_User: rep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: binlog.000003
Read_Master_Log_Pos: 157
Relay_Log_File: localhost-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: binlog.000003
Slave_IO_Running: Connecting
Slave_SQL_Running: Yes
...
Last_IO_Error: error connecting to master 'rep@192.168.150.21:3306' - retry-time: 60 retries: 1 message: Can't connect to MySQL server on '192.168.150.21:3306' (111)
[root@localhost ~]# mysqladmin -urep -p123456 -h192.168.150.21 ping
mysqladmin: [Warning] Using a password on the command line interface can be insecure.
mysqld is alive
# 查询日志
[root@localhost ~]# tail /var/log/mysql/mysqld.log
...
2023-12-02T03:17:53.631813Z 5 [ERROR] [MY-010584] [Repl] Slave I/O for channel '': error connecting to master 'rep@192.168.150.21:3306' - retry-time: 60 retries: 3 message: Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection. Error_code: MY-002061
![](https://i-blog.csdnimg.cn/direct/94834c6a6e0c4429a809dd56b992c83b.png)
解决方法:
**方案一:**修改master库的密码加密方式
mysql> alter user 'rep'@'192.168.150.%' identified with mysql_native_password by '123456';
Query OK, 0 rows affected (0.01 sec)
方案二:设置从库的change master 时加get_master_public_key=1参数
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> change master to
-> master_host='172.16.100.21',
-> master_user='rep',
-> master_password='123456',
-> master_log_file='binlog.000015',
-> master_log_pos=756,
-> get_master_public_key=1;
Query OK, 0 rows affected, 9 warnings (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.01 sec)
可选配置
#[可选] 0(默认)表示读写(主机),1表示只读(从机)
read-only=0
#设置日志文件保留的时长,单位是秒
binlog_expire_logs_seconds=6000
#控制单个二进制日志大小。此参数的最大和默认值是1GB
max_binlog_size=200M
#[可选]设置不要复制的数据库
binlog-ignore-db=test
#[可选]设置需要复制的数据库,默认全部记录。
binlog-do-db=需要复制的主数据库名字
#[可选]设置binlog格式
binlog_format=STATEMENT
2、基于gtid的主从同步配置
开启gtid
gtid_mode=ON
enforce-gtid-consistency=ON
mysql> CHANGE MASTER TO
> MASTER_HOST = host,
> MASTER_PORT = port,
> MASTER_USER = user,
> MASTER_PASSWORD = password,
> MASTER_AUTO_POSITION = 1;
Or from MySQL 8.0.23:
mysql> CHANGE REPLICATION SOURCE TO
> SOURCE_HOST = host,
> SOURCE_PORT = port,
> SOURCE_USER = user,
> SOURCE_PASSWORD = password,
> SOURCE_AUTO_POSITION = 1;
mysql> START SLAVE;
Or from MySQL 8.0.22:
mysql> START REPLICA;
GTID 从库误写入操作处理
查看监控信息:
Last_SQL_Error: Error 'Can't create database 'db4'; database exists' on query. Default database: 'db4'. Query: 'create database db4'
Retrieved_Gtid_Set: 71bfa52e-4aae-11e9-ab8c-000c293b577e:1-3
Executed_Gtid_Set: 71bfa52e-4aae-11e9-ab8c-000c293b577e:1-2,
7ca4a2b7-4aae-11e9-859d-000c298720f6:1
注入空事务的方法:
stop slave;
set gtid_next='99279e1e-61b7-11e9-a9fc-000c2928f5dd:3';
begin;commit;
set gtid_next='AUTOMATIC';
这里的xxxxx:N 也就是你的slave sql thread报错的GTID,或者说是你想要跳过的GTID。
最好的解决方案:重新构建主从环境
二、MySQL 主从读写分离实现方案
-
(1).MySQL Router:MySQL官方提供的轻量级MySQL代理(路由),只提供读写分离功能,前身为SQL Proxy。
-
(2).ProxySQL:类似于MySQL Router,轻量级MySQL代理,提供读写分离功能,也支持一些sharding功能。有percona版和官方版两个版本。
-
(3).MaxScale:MariaDB的中间件,和MySQL Router、ProxySQL类似。
- 这三者类似,都是轻量级数据库中间件。
-
(4).Amoeba、Cobar、MyCAT:提供很多功能,最主要的功能包括读写分离、sharding。
- 这三者的渊源较深,都是开源的。Amoeba后继无人,于是Cobar出来,Cobar后继无人,加上2013年出现了一次较严重的问题,于是MyCAT站在Cobar的肩膀上出来了。
( 1 )通过程序实现读写分离(需要程序支持)
php和Java 程序都可以通过设置多个连接文件轻松地实现对数据库读写分离,当语句关键字为 select 时,就去连接读库的连接文件,若为 update、 insert、 delete 时,连接写库的连接文件
![](https://i-blog.csdnimg.cn/direct/c3c79436665247928aa1a554cd84b00c.png)
通过程序实现读写分离的缺点就是需要开发人员对程序进行改造,程序本身无法直接支持读写分离
( 2)通过开源的软件实现读写分离
Maxscale 、Atlas 、Mycat 等代理软件也可以实现读写分离的功能,并且无须对应用程序做任何修改,而且它们还支持负载均衡等功能 ;缺点是又引入了单点服务,并且稳定性不如程序实现好
( 3)大型门户独立开发 DAL 综合软件
百度、阿里等大型门户都有开发牛人,会花大力气开发适合自己业务的读写分离、负载均衡、监控报警、自动扩容、自动收缩等一系列功能的 DAL 层软件
MySQL 写分离的基本逻辑图如图
![](https://i-blog.csdnimg.cn/direct/55920d931cd7494c88f482007a050e07.png)
2.1 ProxySQL实现mysql8主从同步读写分离
1、ProxySQL基本介绍
![](https://i-blog.csdnimg.cn/direct/23e5fd07a5e546598d4e06d6181d87fa.png)
1.1 前言
ProxySQL是 MySQL 的高性能、高可用性、协议感知代理。以下为结合主从复制对ProxySQL读写分离、黑白名单、路由规则等做些基本测试。
1.2 基本介绍
先简单介绍下ProxySQL及其功能和配置,主要包括:
- 最基本的读/写分离,且方式有多种;
- 可定制基于用户、基于schema、基于语句的规则对SQL语句进行路由,规则很灵活;
- 动态加载配置,即绝大部分的配置可以在线修改,但有少部分参数还是需要重启来生效;
- 可缓存查询结果。虽然缓存策略比较简陋,但实现了基本的缓存功能;
- 过滤危险的SQL,增加防火墙等功能;
- 提供连接池、日志记录、审计日志等功能;
1.2.1 请求流程
流量从客户端发出 → ProxySQL进行处理转发 → 后端处理 → ProxySQL的前端连接 → 返回客户端的基本流程
![](https://i-blog.csdnimg.cn/direct/5fe1058e5d4d4ff893d8a27ce4d48226.png)
1.2.2 核心功能
![](https://i-blog.csdnimg.cn/direct/93339360da3e46c8a8ba5b9d9d392a46.png)
- 读写分离:可查询走从库,写入走主库
- 简单Sharding:ProxySQL的sharding是通过正则匹配来实现的,对于需要拆分SQL以及合并SQL执行结果的不能支持,所以写了简单sharding
- 连接池管理:常规功能,为了提高SQL执行效率。
- 多路复用:主要优化点在后端mysql连接的复用,对比smart client,中间层不仅对前端建连也会对后端建连,可自行控制后端连接的复用逻辑。
- 流量管控:kill连接和kill query;whitelist配置。
- 高可用:底层mysql,如果从库挂了,自动摘除流量;主库挂了暂不处理。proxysql自身高可用提供cluster的功能,cluster内部会自行同步元数据以及配置变更信息。
- 查询缓存:对username+schema+query的key进行缓存,设置ttl过期,不适合写完就查的场景,因为在数据在未过期之前可能是脏数据。
- 动态配置:大部分的配置可动态变更,先load到runtime,在save到disk,通过cluster的功能同步到其他的节点。
- 流量镜像:同一份流量可以多出写入,但是并不保证mirror的流量一定成功。
- SQL改写:在query rules中配置replace规则,可以对指定的SQL进行改写。
当ProxySQL启动后,将监听两个端口:
(1).admin管理接口,默认端口为6032。该端口用于查看、配置ProxySQL。
(2).接收SQL语句的接口,默认端口为6033,这个接口类似于MySQL的3306端口。
![](https://i-blog.csdnimg.cn/direct/594f77f3d3464e1cbb23e5e2dc01932c.png)
ProxySQL的admin管理接口是一个使用MySQL协议的接口,所以,可以直接使用mysql客户端、navicat等工具去连接这个管理接口
2、ProxySQL结构
![](https://i-blog.csdnimg.cn/direct/81b2275fac4e4832b67edddab49f2d99.png)
-
Qurey Processor 用于匹配查询规则并根据规则决定是否缓存查询或者将查询加入黑名单或者重新路由、重写查询或者镜像查询到其他hostgroup。
-
User Auth 为底层后端数据库认证提供了用户凭证。
-
Hostgroup manager -- 负责管理发送SQL请求都后端数据库并跟踪SQL请求状态。
-
Connection pool -- 负责管理后端数据库连接,连接池中建立的连接被所有的前端应用程序共享。
-
Monitoring -- 负责监控后端数据库健康状态主从复制延时并临时下线不正常的数据库实例。
1.启动过程
![](https://i-blog.csdnimg.cn/direct/978169d3cff041f8862aff45340195ba.png)
-
RUNTIME层:代表的是ProxySQL当前生效的配置,包括 global_variables, mysql_servers, mysql_users, mysql_query_rules。无法直接修改这里的配置,必须要从下一层load进来
-
MEMORY层:是平时在mysql命令行修改的 main 里头配置,可以认为是SQLite数据库在内存的镜像。该层级的配置在main库中以mysql_开头的表以及global_variables表,这些表的数据可以直接修改;
-
DISK|CONFIG FILR层:持久存储的那份配置,一般在
$(DATADIR)/proxysql.db
,在重启的时候会从硬盘里加载。/etc/proxysql.cnf
文件只在第一次初始化的时候用到,完了后,如果要修改监听端口,还是需要在管理命令行里修改,再 save 到硬盘。
注意:
- 如果找到数据库文件(proxysql.db),ProxySQL 将从 proxysql.db 初始化其内存中配置。因此,磁盘被加载到 MEMORY 中,然后加载到 RUNTIME 中。
- 如果找不到数据库文件(proxysql.db)且存在配置文件(proxysql.cfg),则解析配置文件并将其内容加载到内存数据库中,然后将其保存在 proxysql.db 中并在加载到 RUNTIME。 请务必注意,
- 如果找到 proxysql.db,则不会解析配置文件。也就是说,在正常启动期间,ProxySQL 仅从持久存储的磁盘数据库初始化其内存配置。
2.数据库结构
ProxySQL自身共有5个库,分别为3个保存在内存中的库,和2个保存在磁盘的SQLite库。 通过6032管理端口登入后,默认就是main库,所有的配置更改都必须在这个库中进行,disk存档库不会直接受到影响。
# mysql -uadmin -padmin -h127.0.0.1 -P6032
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.5.30 (ProxySQL Admin Module)
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)
-
main:内存配置数据库,表里存放后端db实例、用户验证、路由规则等信息。表名以 runtime开头的表示proxysql当前运行的配置内容,不能通过dml语句修改,只能修改对应的不以 runtime 开头的(在内存)里的表,然后 LOAD 使其生效, SAVE 使其存到硬盘以供下次重启加载。
-
disk:是持久化到硬盘的配置,sqlite数据文件。SQLite3 数据库,默认位置为 $(DATADIR)/proxysql.db,在重新启动时,未保留的内存中配置将丢失。因此,将配置保留在 DISK 中非常重要。(SQLite是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎)
-
stats:proxysql运行抓取的统计信息,包括到后端各命令的执行次数、流量、processlist、查询种类汇总/执行时间等等。
-
monitor:库存储 monitor 模块收集的信息,主要是对后端db的健康/延迟检查。
-
stats_history:统计信息历史库
3.核心配置表
![](https://i-blog.csdnimg.cn/direct/bfb090bddee04a19a381d8a8d7a271d0.png)
![](https://i-blog.csdnimg.cn/direct/acc67034b1c84e43b2b0501823f6d194.png)
![](https://i-blog.csdnimg.cn/direct/90b261e1caeb44769575215c4270a142.png)
![](https://i-blog.csdnimg.cn/direct/5fb5d79d22284163ab80edc3e1f877e5.png)
![](https://i-blog.csdnimg.cn/direct/cb6f7332fb8149309374d8af53f62095.png)
![](https://i-blog.csdnimg.cn/direct/f1e99eab5ef34cb782a8e82c3342cbde.png)
4.命令
![](https://i-blog.csdnimg.cn/direct/774a3135970641958089aee7238e9404.png)
5.小结
这些数据库的功能实现了实用化内容:
-
允许轻松动态更新配置,便于运维管理,与MySQL兼容的管理界面可用于此目的。
-
允许尽可能多的配置项目动态修改,而不需要重新启动ProxySQL进程
-
可以毫不费力地回滚无效配置
-
通过多级配置系统实现的,其中设置从运行时移到内存,并根据需要持久保存到磁盘
2、实验环境
机器名称 | IP配置 | 服务角色 | 备注 |
---|---|---|---|
proxy | 192.168.150.24 | proxysql控制器 | 用于监控管理 |
master | 192.168.150.21 | 数据库主服务器 | |
slave1 | 192.168.150.22 | 数据库从服务器 | |
slave2 | 192.168.150.23 | 数据库从服务器 |
3、实现数据库主从复制
基于GTID实现mysql8.0主从同步,配置过程略。
4、安装ProxySQL
# 配置yum源
cat > /etc/yum.repos.d/proxysql.repo << EOF
[proxysql]
name=ProxySQL YUM repository
baseurl=https://repo.proxysql.com/ProxySQL/proxysql-2.5.x/centos/\$releasever
gpgcheck=1
gpgkey=https://repo.proxysql.com/ProxySQL/proxysql-2.5.x/repo_pub_key
EOF
# 安装proxysql
yum install -y proxysql
启动 ProxySQL
[root@proxy ~]# systemctl enable --now proxysql
# 管理员登录
[root@proxy ~]# mysql -uadmin -padmin -h 127.0.0.1 -P 6032
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.5.30 (ProxySQL Admin Module)
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MySQL [(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、disk、stats 、monitor 和 stats_history
main: 内存配置数据库,即 MEMORY,表里存放后端 db 实例、用户验证、路由规则等信息。main 库中有如下信息:
MySQL [(none)]> show tables from main;
+----------------------------------------------------+
| tables |
+----------------------------------------------------+
| coredump_filters |
| 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_hostgroup_attributes |
| mysql_query_rules |
| mysql_query_rules_fast_routing |
| mysql_replication_hostgroups |
| mysql_servers |
| mysql_users |
| proxysql_servers |
| restapi_routes |
| runtime_checksums_values |
| runtime_coredump_filters |
| 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_hostgroup_attributes |
| 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 |
+----------------------------------------------------+
36 rows in set (0.00 sec)
库下的主要表:
mysql_servers: 后端可以连接 MySQL 服务器的列表
mysql_users: 配置后端数据库的账号和监控的账号。
mysql_query_rules: 指定 Query 路由到后端不同服务器的规则列表。
注: 表名以 runtime_开头的表示 ProxySQL 当前运行的配置内容,不能通过 DML 语句修改。
只能修改对应的不以 runtime 开头的表,然后 "LOAD" 使其生效,"SAVE" 使其存到硬盘以供下次重启加载。
disk :持久化的磁盘的配置
stats: 统计信息的汇总
monitor:一些监控的收集信息,比如数据库的健康状态等
stats_history: 这个库是 ProxySQL 收集的有关其内部功能的历史指标
配置 ProxySQL 所需账户
在 Master (172.16.100.21) 的MySQL 上创建 ProxySQL 的监控账户和对外访问账户
create user 'monitor'@'172.16.%.%' identified with mysql_native_password by 'Monitor@123.com';
grant all privileges on *.* to 'monitor'@'172.16.%.%' with grant option;
#proxysql 的对外访问账户
create user 'proxysql'@'172.16.%.%' identified with mysql_native_password by '123456';
grant all privileges on *.* to 'proxysql'@'172.16.%.%' with grant option;
5、配置ProxySQL
使用proxysql,主要需要完成以下几项内容的配置:
- 配置监控账号。监控账号用于检测后端mysql实例是否健康(是否能连接、复制是否正常、复制是否有延迟等)。
- 到后端mysql实例创建监控账号。
- 配置后端mysql实例连接信息。实例连接信息存储在mysql_servers表。
- 配置连接proxysql和后端实例的账号。账号信息存储在mysql_users表。
- 配置查询路由信息。路由信息存储在mysql_query_rules表。
- 配置后端mysql集群信息。根据后端mysql集群架构,配置分别存储在mysql_replication_hostgroups、mysql_group_replication_hostgroups、runtime_mysql_galera_hostgroups、runtime_mysql_aws_aurora_hostgroups等表中。
- 根据具体需要,调优相关参数。参数存储在global_variables表。
一、配置ProxySQL主从分组信息
1.用到这个表:mysql_replication_hostgroup,表结构如下:
MySQL [(none)]> 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)
注:writer_hostgroup 和reader_hostgroup 写组和读组都要大于等于0且不能相同
2.创建组:(定义写为1,读为0)
MySQL [(none)]> insert into mysql_replication_hostgroups (writer_hostgroup,reader_hostgroup,comment) values (1,0,'proxy');
Query OK, 1 row affected (0.00 sec)
MySQL [(none)]> load mysql servers to runtime;
Query OK, 0 rows affected (0.01 sec)
MySQL [(none)]> save mysql servers to disk;
Query OK, 0 rows affected (0.02 sec)
注意:ProxySQL会根据server的read_only的取值将服务器进行分组。read_only=0的server,master被分到编号为1的写组,read_only=1的server,slave则分到编号为0的读组
MySQL [(none)]> select * from mysql_replication_hostgroups;
+------------------+------------------+------------+---------+
| writer_hostgroup | reader_hostgroup | check_type | comment |
+------------------+------------------+------------+---------+
| 1 | 0 | read_only | proxy |
+------------------+------------------+------------+---------+
1 row in set (0.00 sec)
3.添加主从服务器节点:
MySQL [(none)]> insert into mysql_servers(hostgroup_id,hostname,port) values (1,'172.16.100.21',3306);
Query OK, 1 row affected (0.00 sec)
MySQL [(none)]> insert into mysql_servers(hostgroup_id,hostname,port) values (0,'172.16.100.22',3306);
Query OK, 1 row affected (0.00 sec)
MySQL [(none)]> insert into mysql_servers(hostgroup_id,hostname,port) values (0,'172.16.100.23',3306);
Query OK, 1 row affected (0.00 sec)
MySQL [(none)]> load mysql servers to runtime;
Query OK, 0 rows affected (0.01 sec)
MySQL [(none)]> save mysql servers to disk;
Query OK, 0 rows affected (0.00 sec)
MySQL [(none)]> 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.150.21 | 3306 | 0 | ONLINE | 1 | 0 | 1000 | 0 | 0 | 0 | |
| 0 | 192.168.150.22 | 3306 | 0 | ONLINE | 1 | 0 | 1000 | 0 | 0 | 0 | |
| 0 | 192.168.150.23 | 3306 | 0 | ONLINE | 1 | 0 | 1000 | 0 | 0 | 0 | |
+--------------+----------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
3 rows in set (0.00 sec)
4.为ProxySQL监控MySQL后端节点
MySQL [(none)]> use monitor
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
MySQL [monitor]> set mysql-monitor_username='monitor';
Query OK, 1 row affected (0.00 sec)
MySQL [monitor]> set mysql-monitor_password='Monitor@123.com';
Query OK, 1 row affected (0.00 sec)
上面这两句是修改变量的方式还可以在main库下面用sql语句方式修改
在main下修改:
MySQL [monitor]> 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
MySQL [main]> UPDATE global_variables SET variable_value='monitor' WHERE variable_name='mysql-monitor_username';
Query OK, 1 row affected (0.00 sec)
MySQL [main]> UPDATE global_variables SET variable_value='Monitor@123.com' WHERE variable_name='mysql-monitor_password';
Query OK, 1 row affected (0.00 sec)
修改后,保存到runtime和disk
MySQL [monitor]> load mysql variables to runtime;
MySQL [monitor]> save mysql variables to disk;
查看监控账号【ProxySQL】
SELECT * FROM global_variables WHERE variable_name LIKE 'mysql-monitor_%';
//也可以这样快速定位
MySQL [(none)]> select @@mysql-monitor_username;
+--------------------------+
| @@mysql-monitor_username |
+--------------------------+
| monitor |
+--------------------------+
1 row in set (0.00 sec)
MySQL [(none)]> select @@mysql-monitor_password;
+--------------------------+
| @@mysql-monitor_password |
+--------------------------+
| Monitor@123.com |
+--------------------------+
1 row in set (0.00 sec)
MySQL [(none)]> select * from monitor.mysql_server_connect_log;
+----------------+------+------------------+-------------------------+---------------+
| hostname | port | time_start_us | connect_success_time_us | connect_error |
+----------------+------+------------------+-------------------------+---------------+
| 192.168.150.21 | 3306 | 1701659547601785 | 2126 | NULL |
| 192.168.150.23 | 3306 | 1701659548266990 | 1883 | NULL |
| 192.168.150.22 | 3306 | 1701659548932828 | 1626 | NULL |
| 192.168.150.21 | 3306 | 1701659607601353 | 1672 | NULL |
| 192.168.150.22 | 3306 | 1701659608066386 | 1649 | NULL |
| 192.168.150.23 | 3306 | 1701659608531392 | 1962 | NULL |
| 192.168.150.21 | 3306 | 1701659667601720 | 1283 | NULL |
| 192.168.150.23 | 3306 | 1701659668394216 | 2033 | NULL |
| 192.168.150.22 | 3306 | 1701659669186458 | 1350 | NULL |
+----------------+------+------------------+-------------------------+---------------+
9 rows in set (0.00 sec)
验证监控信息,ProxySQL 监控模块的指标都保存在monitor库的log表中
以下是连接是否正常的监控,对connect指标的监控 ,在前面可能会有很多connect_error,这是因为没有配置监控信息时的错误,配置后如果connect_error的结果为NULL则表示正常
5.对心跳信息的监控:
MySQL [(none)]> select * from mysql_server_ping_log limit 10;
+----------------+------+------------------+----------------------+------------+
| hostname | port | time_start_us | ping_success_time_us | ping_error |
+----------------+------+------------------+----------------------+------------+
| 192.168.150.21 | 3306 | 1701659547602344 | 460 | NULL |
| 192.168.150.23 | 3306 | 1701659547604095 | 245 | NULL |
| 192.168.150.22 | 3306 | 1701659547604690 | 258 | NULL |
| 192.168.150.23 | 3306 | 1701659557601548 | 471 | NULL |
| 192.168.150.21 | 3306 | 1701659557601738 | 313 | NULL |
| 192.168.150.22 | 3306 | 1701659557601713 | 349 | NULL |
| 192.168.150.22 | 3306 | 1701659567602161 | 572 | NULL |
| 192.168.150.23 | 3306 | 1701659567602361 | 405 | NULL |
| 192.168.150.21 | 3306 | 1701659567602318 | 460 | NULL |
| 192.168.150.22 | 3306 | 1701659577602909 | 434 | NULL |
+----------------+------+------------------+----------------------+------------+
10 rows in set (0.00 sec)
6.查看read_only日志监控:
MySQL [(none)]> select * from mysql_server_read_only_log limit 5;
+----------------+------+------------------+-----------------+-----------+-------+
| hostname | port | time_start_us | success_time_us | read_only | error |
+----------------+------+------------------+-----------------+-----------+-------+
| 192.168.150.23 | 3306 | 1701659547606174 | 373 | 1 | NULL |
| 192.168.150.22 | 3306 | 1701659547606768 | 634 | 1 | NULL |
| 192.168.150.21 | 3306 | 1701659547606639 | 858 | 0 | NULL |
| 192.168.150.21 | 3306 | 1701659549101574 | 657 | 0 | NULL |
| 192.168.150.22 | 3306 | 1701659549101863 | 422 | 1 | NULL |
+----------------+------+------------------+-----------------+-----------+-------+
5 rows in set (0.00 sec)
Monitor 模块就会开始监控后端的read_only值,当监控到read_only值,就会按照read_only的值将某些节点自动移到读写组
一些监控的状态斗志在log相关,都在monitor库下面的 global_variables 变量。
7.ProxySQL配置对外访问账号:(要在MySQL节点上创建)
前面已经配置:配置ProxySQL 账户,我创建的对外访问账户是:用户:proxysql,密码:123456
mysql_users表结构如下:
MySQL [(none)]> 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.00 sec)
将对外访问账号添加到mysql_users表中:
insert into mysql_users (username,password,default_hostgroup,transaction_persistent) values ('proxysql','123456',1,1);
load mysql users to runtime;
save mysql users to disk;
MySQL [(none)]> select * from mysql_users\G
*************************** 1. row ***************************
username: proxysql
password: 123456
active: 1
use_ssl: 0
default_hostgroup: 1
default_schema: NULL
schema_locked: 0
transaction_persistent: 1
fast_forward: 0
backend: 1
frontend: 1
max_connections: 10000
attributes:
comment:
1 row in set (0.00 sec)
注:transaction_persistent 如果为1,则一个完整的SQL只可能路由到一个节点;这点非常重要,主要解决这种情况:一个事务有混合的读操作和写操作组成,事务未提交前,如果事务中的读操作和写操作路由到不同节点,那么读取到的结果必然是脏数据。所以一般情况下,该值应该设置为1,尤其是业务中使用到事务机制的情况(默认为0)
mysql_users 表有不少字段,最主要的三个字段username,password,default_hostgroup
A.username: 前端链接ProxySQL ,以及ProxySQL 将SQL 语句路由给MySQL所使用的的用户名
B.password:用户名对应的密码,。可以是明文密码,也可以是hash密码。如果想使用hash密码,可以先在某个MySQL节点上执行select password(PASSWORD),然后将加密结果复制到该字段。
C.default_hostgroup:该用户名默认的路由目标。例如,指定root用户的该字段值为1时,则使用 proxysql 用户发送的SQL语句默认情况下将路由到hostgroup_id=1 组中的某个
在从库端172.16.100.22上通过对方访问账号proxy连接,测试是否路由能默认到hostgroup_id=1,它是一个写组
[root@slave1 ~]# mysql -h172.16.100.24 -uproxysql -p'123456' -P 6033
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.5.30 (ProxySQL)
Copyright (c) 2000, 2022, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| db1 |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.01 sec)
mysql> select @@server_id;
+-------------+
| @@server_id |
+-------------+
| 21 |
+-------------+
1 row in set (0.00 sec)
#通过proxysql用户,创建一个keme库
mysql> create database keme;
Query OK, 1 row affected (0.00 sec)
在slave2:172.16.100.23 上去验证一下,是否同步过去keme这个库
mysql> select @@server_id;
+-------------+
| @@server_id |
+-------------+
| 23 |
+-------------+
1 row in set (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| db1 |
| information_schema |
| keme |
| mysql |
| performance_schema |
| sys |
+--------------------+
6 rows in set (0.01 sec)
8.添加读写分离规则(mysql_query_rules)
proxysql支持正则,这里添加两条匹配规则
- 表示像select * from xxx for update这种语句都会分到到写组
2)表示像select这种语句都会被分配到读组。
insert into mysql_query_rules(rule_id,active,match_pattern,destination_hostgroup,apply) values(1,1,'^select .* for update$',1,1);
insert into mysql_query_rules(rule_id,active,match_pattern,destination_hostgroup,apply) values(2,1,'^select',0,1);
load mysql query rules to runtime;
save mysql query rules to disk;
9.测试读写分离
[root@slave1 ~]# mysql -uproxysql -p123456 -h 172.16.100.24 -P 6033 -e "select @@server_id"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
| 3 |
+-------------+
[root@slave1 ~]# mysql -uproxysql -p123456 -h 172.16.100.24 -P 6033 -e "select @@server_id"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
| 2 |
+-------------+
[root@slave1 ~]# mysql -uproxysql -p123456 -h 172.16.100.24 -P 6033 -e "begin;select @@server_id commit;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------+
| commit |
+--------+
| 1 |
+--------+