1.读写分离技术

|---------------------------|------------------------------|
| 主库(Master) | 从库(Slave) |
| 主要负责处理写操作(INSERT,UPADTE等) | 从主库复制数据,主要负责处理大量的读操作(SELECT) |
[读写分离的作用]
|---------|---------------------------------------|
| 1.提升性能 | 将读写负载分散到不同数据库服务器,避免单一服务器瓶颈 |
| 2.提高扩展性 | 可以添加更多从库来水平扩展读能力 |
| 3.提高可用性 | 当某个从库宕机时,读请求可以被路由到其他健康的从库或主库,保证服务不中断。 |
[读写分离的好处]
其他了解:
综合使用(推荐大多数公司):ProxySQL
它是目前MySQL读写分离领域事实上的标准。它在功能、性能、透明性和运维复杂度上取得了最佳平衡。
--- Java使用(推荐Java团队):ShardingSphere-JDBC
如果是纯Java技术栈,并且对性能有极致要求,或者明确需要分库分表,那么ShardingSphere-JDBC是不二之选。
--- 老版本使用:MyCat
新项目不推荐使用。除非正在维护一个基于MyCat的老系统,或者团队对MyCat有很深的技术积累。
---简单使用(推荐云上用户):云厂商服务
如果项目完全构建在阿里云、AWS等云平台上,并且预算充足,直接使用云厂商的读写分离功能是最省心的选择如阿里云`RDS MySQL读写分离`。代价是失去灵活性和可能更高的长期成本。
2.什么是ProxySQL
ProxySQL 是一个高性能、高可用性、基于 MySQL 协议的开源数据库中间件
|--------|----------------------------------------------------------|
| 1.连接池 | 有效管理后端数据库连接,避免大量短连接造成的性能开销。 |
| 2.查询路由 | 根据预定义的规则,将不同的 SQL 语句发送到不同的 MySQL 服务器组(例如,写操作到主库,读操作到从库)。 |
| 3.负载均衡 | 根据预定义的规则,将不同的 SQL 语句发送到不同的 MySQL 服务器组(例如,写操作到主库,读操作到从库)。 |
| 4.故障转移 | 自动检测后端数据库的健康状态,将故障节点从流量池中移除,实现高可用。 |
| 5.查询缓存 | 缓存查询结果,对重复的读请求直接返回结果,极大减轻数据库压力。 |
| 6.动态配置 | 绝大多数配置可以在运行时修改,并动态加载,无需重启服务。 |
[ProxySQL核心功能]
3.ProxySQL如何实现读写分离
ProxySQL 通过一套多层配置系统来实现读写分离
核心概念:a. 后端服务器 (mysql_servers)
定义MySQL 数据库实例,例如:主库 (
hostgroup_id: 10)、从库1 (hostgroup_id: 20)、从库2 (hostgroup_id: 20)。hostgroup_id是一个逻辑分组ID。b. 用户认证 (mysql_users)
定义应用程序连接 ProxySQL 时使用的用户名和密码。这些用户必须在后端 MySQL 服务器上真实存在。
c. 查询规则 (mysql_query_rules)
这是实现读写分离的大脑。通过定义规则来告诉 ProxySQL 如何路由 SQL 语句。
- 规则匹配条件 :例如,匹配
SELECT语句的正则表达式 (^SELECT.*),或者根据 SQL 指纹、模式名等。
- 目标主机组 :匹配该规则的查询将被路由到指定的
destination_hostgroup。
- 应用/不应用缓存:可以指定某些查询是否启用缓存。
- 启用状态 :规则可以设置为启用 (
active=1) 或禁用 (active=0)。d. 流量处理流程
应用程序使用标准 MySQL 协议连接到 ProxySQL 的监听端口(默认 6033)。
ProxySQL 接收 SQL 查询。
ProxySQL 按顺序检查
mysql_query_rules表中的规则。一旦找到匹配的规则,查询就会被发送到规则指定的
destination_hostgroup中的某个服务器。如果没有规则匹配,默认情况下,查询会被发送到用户默认的
default_hostgroup(通常设置为主库的 hostgroup)。
4.案例实战Proxysql读写分离
proxysql-读写分离,有四个端口
6032是管理员登录
6033普通用户登录
1.master监控用户权限USAGE, REPLICATION CLIENT
应用程序用户权限ALL PRIVILEGES
2.proxysqlmysql -udamin -padmin -h 127.0.0.1 -P 6032
主库从库信息配置到mysql_servers表
字段:hostgroup_id,hostname,port,weight,max_connectionsLOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVER TO DISK;
配置监控用户global_variables表
variable_name='mysql-monitor_username'变为监控用户名
variable_name='mysql-monitor_password'变为监控用户密码LOAD MYSQL VARIABLES TO RUNTIME;
SAVE MYSQL VARIABLES TO DISK;
检查监控状态
monitor.mysql_server_connect_log
monitor.mysql_server_ping_log
读写分离规则mysql_query_rules表
字段:rule_id,active,math_digest,destinnation_hostgroup,applyLOAD MYSQL QUERY RULES TO RUNTIME
LOAD MYSQL QUERY RULES TO DISK
验证用户使用-P6033
4.1安装ProxySQL(Centos9)
安装依赖
sudo dnf install -y wget gnupg2
安装proxySQL
sudo dnf -y install https://repo.proxysql.com/ProxySQL/proxysql-3.0.x/centos/9/proxysql-3.0.4-1-centos9.x86_64.rpm
启动ProxySQL
sudo systemctl enable --now proxysql
sudo systemctl status proxysql
验证启动
netstat -tnlp

4.2关闭防火墙
systemctl disable --now firewalld
sed -i 's/^SELINUX=.*/SELINUX=disabled/g' /etc/selinux/config
4.3配置读写分离
4.3.1在主库执行(MySQL-Master)
创建监控用户-proxysql
CREATE USER proxysql@'192.168.189.%' IDENTIFIED BY 'Proxysql@123';
GRANT USAGE,REPLICATION CLIENT ON *.* TO proxysql@'192.168.189.%';
创建应用程序用户(http&nginx)
bash
CREATE USER http@'%' IDENTIFIED BY 'Http@123';
bash
GRANT ALL PRIVILEGES ON *.* TO http@'%';
bash
CREATE USER nginx@'%' IDENTIFIED BY 'Nginx@123';
bash
GRANT ALL PRIVILEGES ON *.* TO nginx@'%';
4.3.2在proxysql主机进行配置
|---------------------|-------------------|------------------------------------------|
| 字段名 | 值 | 说明 |
| hostgroup_id | 10 | 主机组ID |
| hostname | '192.168.189.129' | 服务器地址 :后端 MySQL 服务器的 IP 地址或主机名 |
| port | 3306 | 端口号 :MySQL 服务的监听端口(默认3306) |
| weight | 1000 | 权重 :负载均衡权重,值越高,该服务器接收的查询越多(相对比例) |
| max_connections | 1000 | 最大连接数 :ProxySQL 到该服务器的最大并发连接数 |
[mysql_servers字段]
登录proxysql
mysql -u admin -padmin -h 127.0.0.1 -P 6032 --prompt='ProxySQLAdmin>'

清空mysql_servers
bash
DELETE FROM mysql_servers;
添加主库到mysql_servers(这里我设置主库hostgroup_id=10)
bash
INSERT INTO mysql_servers(hostgroup_id,hostname,port,weight,max_connections) VALUES (10,'192.168.189.138',3306,1000,1000);
添加从库到mysql_servers(这里我设置从库hostgroup_id=20)
bash
INSERT INTO mysql_servers(hostgroup_id,hostname,port,weight,max_connections) VALUES (20,'192.168.189.129',3306,1000,1000);
查看添加结果
bash
SELECT hostgroup_id,hostname,port,weight,max_connections FROM mysql_servers;

加载配置到内存&磁盘
bash
LOAD MYSQL SERVERS TO RUNTIME;
bash
SAVE MYSQL SERVERS TO DISK;
配置监控用户(设置监控用户名&密码)
bash
UPDATE global_variables SET variable_value='proxysql' WHERE variable_name='mysql-monitor_username';
bash
UPDATE global_variables SET variable_value='Proxysql@123' WHERE variable_name='mysql-monitor_password';
bash
select * from global_variables where variable_name='admin-admin_credentials' or variable_name='mysql-monitor_username' or variable_name='mysql-monitor_password';
LOAD MYSQL VARIABLES TO RUNTIME;
SAVE MYSQL VARIABLES TO DISK;

检查监控状态
bash
SELECT * FROM monitor.mysql_server_connect_log ORDER BY time_start_us DESC LIMIT 5;
bash
SELECT * FROM monitor.mysql_server_ping_log ORDER BY time_start_us DESC LIMIT 5;

配置应用程序用户
-- 需要根据 Master服务器创建用户
#超级用户client@'192.168.189.%' 'Client@123';
#HTTP应用 http@'%' 'Http@123';
#Nginx应用 nginx@'%' 'Nginx@123';
注:先清空现有用户
bash
DELETE FROM mysql_users;
1.添加应用程序用户
bash
INSERT INTO mysql_users(username, password, default_hostgroup, transaction_persistent) VALUES
-> ('client', 'Client@123', 10, 1),
-> ('http', 'Http@123', 10, 1),
-> ('nginx', 'Nginx@123', 10, 1);
2.查看用户
bash
select username,password from mysql_users;

3.加载配置到内存&磁盘
bash
LOAD MYSQL USERS TO RUNTIME;
bash
SAVE MYSQL USERS TO DISK;
配置读写分离规则
mysql_query_rules(配置表)
1.这是持久化存储所有查询规则配置的表
2.存储在 ProxySQL 的磁盘数据库(通常是 SQLite)中
runtime_mysql_query_rules(运行时表)
1.这是内存中当前实际生效的规则表
2.ProxySQL 进程运行时使用这个表进行查询路由决策
3.内容从 mysql_query_rules 加载而来
4.重启 ProxySQL 服务后,会重新从配置表加载
|---------------------------|-------------------------------------|
| rule_id | 规则ID,决定规则匹配的顺序(从小到大) |
| active | 规则是否激活:1=激活,0=禁用 |
| match_digest | 基于 SQL 语句的摘要(规范化后的语句)进行匹配 |
| match_pattern | 基于 SQL 语句的原始文本进行正则匹配 |
| destination_hostgroup | 目标主机组ID,匹配后查询将被路由到该组 |
| apply | 是否应用此规则:1=匹配后立即应用并停止后续匹配,0=继续匹配后续规则 |
| comment | 规则的备注说明 |
[mysql_query_rules字段]
1.清空现有规则
bash
DELETE FROM mysql_query_rules;
2.规则1:捕获 SELECT ... FOR UPDATE,发往写组 (10)
bash
INSERT INTO mysql_query_rules (rule_id, active, match_digest, destination_hostgroup, apply)
VALUES (1, 1, '^SELECT.*FOR UPDATE', 10, 0);
3.规则2:捕获所有其他 SELECT,发往读组 (20),并停止匹配
bash
INSERT INTO mysql_query_rules (rule_id, active, match_digest, destination_hostgroup, apply)
VALUES (1, 1, '^SELECT.*FOR UPDATE', 10, 0);
4.规则3:默认规则,将所有未匹配的语句发往写组 (10),并停止匹配
bash
INSERT INTO mysql_query_rules (rule_id, active, match_digest, destination_hostgroup, apply)
VALUES (3, 1, '.*', 10, 1);
5.加载配置到内存&磁盘
bash
LOAD MYSQL QUERY RULES TO RUNTIME;
bash
LOAD MYSQL QUERY RULES TO DISK;
5.测试与验证
开启一台新机器连接有Proxysql的主机,执行读写操作
5.1登录到Proxysql主机数据库
bash
mysql -uclient -p'Client@123' -h 192.168.189.133 -P6033
测试
bash
SELECT * FROM user.user1;
CREATE DATABASE proxysql_test1;
5.2在Proxysql主机数据库监控
bash
SELECT hostgroup,count_star,digest_text FROM stats.stats_mysql_query_digest ORDER BY count_star DESC LIMIT 10;
