proxysql-2.7.1-1-centos7.x86_64.rpm
读写分离
读写分离的概念
读写分离是⼀种数据库优化技术,主要⽬的是通过将数据库的读操作和写操作分散到不同的数据库
实例上,来提⾼数据库的整体性能和可扩展性。其基本原理是让主数据库处理事务性增、改、删操
作(即写操作),⽽从数据库处理SELECT查询操作(即读操作)。通过这种⽅式,可以有效地减
轻单⼀数据库服务器的负担,特别是当读操作远多于写操作时,能够显著提升数据库的并发处理能
⼒和响应速度。
读写分离的基本实现步骤通常包括以下⼏个⽅⾯:
- 数据库服务器搭建主从集群:可以是⼀主⼀从,也可以是⼀主多从。
- 主数据库负责读写操作:承担写操作的任务,并通过复制机制将数据变更同步到从数据库。
- 从数据库只负责读操作:接收主数据库同步过来的数据,并提供读服务。
- 数据同步机制:主数据库通过复制(Replication)等⽅式将数据变更同步到从数据库,确保
数据的⼀致性。 - 业务服务器的读写分离策略:业务服务器需要将写操作发送到主数据库,将读操作发送到从数
据库。这可以通过应⽤程序代码中的逻辑控制,或者通过使⽤中间件来实现。
读写分离的主要优点包括:
提⾼数据库的并发处理能⼒:通过分散读写操作,减轻单⼀数据库服务器的负担。
提升读操作的性能:从数据库可以专⻔优化读操作,提⾼查询效率。
增强系统的可扩展性:可以通过增加从数据库的数量来线性地提升读性能。
降低写操作的延迟:主数据库专注于写操作,可以更快地完成事务处理。
然⽽,读写分离也并⾮适⽤于所有场景。其适⽤性主要取决于具体的业务需求和数据库访问模式。
例如,对于读多写少的应⽤场景,读写分离可以带来显著的性能提升;
⽽对于写操作⾮常频繁的场景,读写分离可能⽆法有效解决问题,甚⾄可能引⼊新的复杂性。
此外,读写分离还可能带来数据
⼀致性的延迟问题,需要根据具体业务需求来权衡。
在实际应⽤中,读写分离通常结合其他数据库优化技术⼀起使⽤,如缓存、分库分表等,以综合提
升数据库系统的整体性能和可扩展性。
ProxySQL是什么
ProxySQL 是⼀款⾼性能、⾼可⽤性的 MySQL 中间件,其主要特点和功能如下:
- 读写分离:ProxySQL ⽀持多种⽅式的读写分离,可以根据不同的策略(如基于⽤户、基于
schema、基于语句)将读写操作路由到不同的后端数据库实例。 - 查询路由:ProxySQL 具有强⼤的规则路由引擎,可以根据预定义的规则对 SQL 语句进⾏路
由,⽀持复杂的查询改写和分库分表操作。 - 查询缓存:ProxySQL 提供了查询缓存功能,可以缓存查询结果,减少后端数据库的负载,提
升查询效率。 - 后端节点监控:ProxySQL 能够监控后端数据库节点的状态,包括⼼跳信息、读写状态、数据
同步延迟等,提供详细的监控数据。 - 故障切换:ProxySQL ⽀持故障切换功能,当主数据库出现故障时,可以⾃动切换到备⽤数据
库,保证系统的⾼可⽤性。 - 动态配置:ProxySQL 的配置数据基于 SQLite 存储,⼏乎所有的配置都可以在线更改,⽆需
重启服务。 - 连接池:ProxySQL ⽀持连接池功能,可以有效管理数据库连接,减少连接建⽴和释放的开
销,提升系统性能。 - 跨平台⽀持:ProxySQL ⽀持多种数据库系统,包括 Amazon Aurora、RDS、ClickHouse、
Galera、Group Replication、MariaDB Server、NDB、Percona Server 等,并且⽀持在不
同的硬件架构(AMD64 和 ARM64)上部署。 - 易于集成:ProxySQL 提供了丰富的 API 和管理界⾯,便于与其他系统集成,简化了数据库操
作和管理的流程。 - 社区⽀持:ProxySQL 是⼀个开源项⽬,拥有活跃的社区和⼤量的⽤户,提供了丰富的⽂档和
资源,⽅便⽤户学习和使⽤。
总之,ProxySQL 作为⼀个强⼤的 MySQL 代理,能够有效地提升数据库系统的性能、可扩展性和
⾼可⽤性,适⽤于各种规模的企业和应⽤场景。
除了ProxySQL,还有其他⼀些数据库中间件和⼯具可以实现类似的功能,例如:
- MySQL Router:这是MySQL官⽅提供的⼀款命令⾏⼯具,它可以实现MySQL的读写分离。
- MariaDB MaxScale:MaxScale是⼀个开源的数据库代理,它可以为MySQL和MariaDB提供
读写分离、负载均衡、缓存等功能。 - Tungsten Replicator:这是⼀个开源的数据复制⼯具,⽀持MySQL和MongoDB的复制。它
可以⽤来实现读写分离和数据分⽚。 - Vitess:Vitess是⼀个开源的数据库集群系统,主要⽤于⼤规模的MySQL数据库。它可以实现
读写分离、数据分⽚等功能。 - Arbitrator:Arbitrator是⼀个开源的MySQL代理,它可以实现读写分离、负载均衡等功能。
读写分离
读写分离
读写分离是⼀种数据库优化技术,主要⽬的是通过将数据库的读操作和写操作分散到不同的数据库
实例上,来提⾼数据库的整体性能和可扩展性。其基本原理是让主数据库处理事务性增、改、删操
作(即写操作),⽽从数据库处理SELECT查询操作(即读操作)。通过这种⽅式,可以有效地减
轻单⼀数据库服务器的负担,特别是当读操作远多于写操作时,能够显著提升数据库的并发处理能
⼒和响应速度。
读写分离的基本实现步骤通常包括以下⼏个⽅⾯:
- 数据库服务器搭建主从集群:可以是⼀主⼀从,也可以是⼀主多从。
- 主数据库负责读写操作:承担写操作的任务,并通过复制机制将数据变更同步到从数据库。
- 从数据库只负责读操作:接收主数据库同步过来的数据,并提供读服务。
- 数据同步机制:主数据库通过复制(Replication)等⽅式将数据变更同步到从数据库,确保
数据的⼀致性。 - 业务服务器的读写分离策略:业务服务器需要将写操作发送到主数据库,将读操作发送到从数
据库。这可以通过应⽤程序代码中的逻辑控制,或者通过使⽤中间件来实现。
安装ProxySQL
防火墙配置
#开放防⽕墙,6032是ProxySQL的管理端⼝,6033是ProxySQL的客户端接⼊端⼝
firewall-cmd --zone=public --add-port=6032/tcp--permanent
firewall-cmd --zone=public --add-port=6033/tcp--permanent
firewall-cmd --reload
下载/安装ProxySQL
wget https://github.com/sysown/proxysql/releases/download/v2.7.1/proxysql2.7.1-1-centos7.x86_64.rpm
yum localinstall -y proxysql-2.7.1-1-centos7.x86_64.rpm
启动
service proxysql start
安装MySQL
连接到ProxySQL Admin,它是⼀个伪装为MySQL的 ProxySQL服务端
mysql -u admin -padmin -h 127.0.0.1 -P 6032 --prompt='Admin> '
在MySQLGRM主节点执⾏创建监控命令,该账户会通过主 节点同步到其他从属节点
# 通过主节点的SQL客户端登录后执⾏
#MySQL降低密码强度
set global validate_password.policy=0;
set global validate_password.length=4;
create user 'proxysql_monitor'@'%' identified with mysql_native_password b
y '123456';
create user 'proxysql_work'@'%' identified with mysql_native_password by
'123456';
GRANT ALL PRIVILEGES ON *.* To 'proxysql_monitor'@'%';
GRANT ALL PRIVILEGES ON *.* TO 'proxysql_work'@'%';
flush privileges;
在n0节点创建函数与视图,这个脚本⽤于让ProxySQL知道那个节点是主服务器。
这三段代码要分开执⾏,每⼀⾏确保执⾏成功。
在ProxySQL中执行
set mysql-monitor_username='proxysql_monitor';
set mysql-monitor_password='123456';
load mysql variables to runtime;
save mysql variables to disk;
在proxySQL中配置主存分组信息
insert into mysql_group_replication_hostgroups values (10,20,30,40,1,1,0,'1 00','proxysql');
load mysql servers to runtime;
save mysql servers to disk;
# 查看信息
select * from mysql_group_replication_hostgroups;
在MySQLMGR主节点上执⾏下⾯语句来创建 gr_member_routing_candidate _status视图,这是主从故 障切换关键所在
USE sys;
DROP VIEW IF EXISTS gr_member_routing_candidate_status;
DROP FUNCTION IF EXISTS IFZERO;
DROP FUNCTION IF EXISTS LOCATE2;
DROP FUNCTION IF EXISTS GTID_NORMALIZE;
DROP FUNCTION IF EXISTS GTID_COUNT;
DROP FUNCTION IF EXISTS gr_applier_queue_length;
DROP FUNCTION IF EXISTS gr_member_in_primary_partition;
DROP FUNCTION IF EXISTS gr_transactions_to_cert;
DELIMITER $$
CREATE FUNCTION IFZERO(a INT, b INT)
RETURNS INT
DETERMINISTIC
RETURN IF(a = 0, b, a)$$
CREATE FUNCTION LOCATE2(needle TEXT(10000), haystack TEXT(10000), offset
INT)
RETURNS INT
DETERMINISTIC
RETURN IFZERO(LOCATE(needle, haystack, offset), LENGTH(haystack) + 1)$$
CREATE FUNCTION GTID_NORMALIZE(g TEXT(10000))
RETURNS TEXT(10000)
DETERMINISTIC
RETURN GTID_SUBTRACT(g, '')$$
CREATE FUNCTION GTID_COUNT(gtid_set TEXT(10000))
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE result BIGINT DEFAULT 0;
DECLARE colon_pos INT;
DECLARE next_dash_pos INT;
DECLARE next_colon_pos INT;
DECLARE next_comma_pos INT;
SET gtid_set = GTID_NORMALIZE(gtid_set);
SET colon_pos = LOCATE2(':', gtid_set, 1);
WHILE colon_pos != LENGTH(gtid_set) + 1 DO
SET next_dash_pos = LOCATE2('-', gtid_set, colon_pos + 1);
SET next_colon_pos = LOCATE2(':', gtid_set, colon_pos + 1);
SET next_comma_pos = LOCATE2(',', gtid_set, colon_pos + 1);
IF next_dash_pos < next_colon_pos AND next_dash_pos < next_comma_po
s THEN
SET result = result +
SUBSTR(gtid_set, next_dash_pos + 1,
LEAST(next_colon_pos, next_comma_pos) - (next_dash_pos +
1)) -
SUBSTR(gtid_set, colon_pos + 1, next_dash_pos - (colon_pos + 1))
+ 1;
ELSE
SET result = result + 1;
END IF;
SET colon_pos = next_colon_pos;
END WHILE;
RETURN result;
END$$
CREATE FUNCTION gr_applier_queue_length()
RETURNS INT
DETERMINISTIC
BEGIN
RETURN (SELECT sys.gtid_count( GTID_SUBTRACT( (SELECT
Received_transaction_set FROM performance_schema.replication_connection_s
tatus
WHERE Channel_name = 'group_replication_applier' ), (SELECT
@@global.GTID_EXECUTED) )));
END$$
CREATE FUNCTION gr_transactions_to_cert() RETURNS int(11)
DETERMINISTIC
BEGIN
RETURN (select performance_schema.replication_group_member_stats.COUNT
_TRANSACTIONS_IN_QUEUE AS transactions_to_cert
FROM
performance_schema.replication_group_member_stats where MEMBER_ID
=@@SERVER_UUID );
END$$
CREATE FUNCTION my_server_uuid() RETURNS TEXT(36) DETERMINISTIC NO SQL RE
TURN (SELECT @@global.server_uuid as my_id);$$
CREATE VIEW gr_member_routing_candidate_status AS
SELECT
IFNULL((SELECT
IF(MEMBER_STATE = 'ONLINE'
AND ((SELECT
COUNT(*)
FROM
performance_schema.replication_gr
oup_members
WHERE
MEMBER_STATE != 'ONLINE') >= ((SE
LECT
COUNT(*)
FROM
performance_schema.replication_gr
oup_members) / 2) = 0),
'YES',
'NO')
FROM
performance_schema.replication_group_members
JOIN
performance_schema.replication_group_member_stat
s rgms USING (member_id)
WHERE
rgms.MEMBER_ID = my_server_uuid()),
'NO') AS viable_candidate,
IF((SELECT
((SELECT
GROUP_CONCAT(performance_schema.global_va
riables.VARIABLE_VALUE
SEPARATOR ',')
FROM
performance_schema.global_variables
WHERE
(performance_schema.global_variables.VARI
ABLE_NAME IN ('read_only' , 'super_read_only'))) <> 'OFF,OFF')
),
'YES',
'NO') AS read_only,
IFNULL(sys.gr_applier_queue_length(), 0) AS transactions_behind,
IFNULL(sys.gr_transactions_to_cert(), 0) AS transactions_to_cert;
$$
DELIMITER ;
查看状态:
SELECT * FROM sys.gr_member_routing_candidate_status;
主服务器
从服务器:
在proxySQL添加服务器列表
insert into mysql_servers(hostgroup_id,hostname,port)values (10,'192.168.43.136',3306);
insert into mysql_servers(hostgroup_id,hostname,port)values (10,'192.168.43.137',3306);
insert into mysql_servers(hostgroup_id,hostname,port)values (10,'192.168.43.138',3306);
load mysql servers to runtime;
save mysql servers to disk;
# 测试
select * from mysql_servers;
status: 后端实例状态,默认为online,可取值为:
- online:当先后端实例状态正常
- shunned:临时被剔除,可能由于后端too many connections error,或者超过了可容忍延迟阀值
- max_replication_lag
- offline_soft:“软离线”状态,再也不接收新的链接,但已创建的链接会等待活跃事务完成
- offline_hard:“硬离线”状态,再也不接收新的链接,已创建的链接或被强制中断,当后端实例宕机或⽹络不可达时,会出现
weight: 后端实例权重,默认为1
max_connections: 容许链接到该后端实例的最⼤链接数,不能⼤于MySQL设置的max_connections,若是后端实例 hostname:port在多个hostgroup中,以较⼤者为准,⽽不是各⾃独⽴容许的最⼤链接数,默认为 1000 max_replication_lag: 容许的最⼤延迟,master节点不受此影响,默认为0,若是>0,monitor模块监控主从延迟⼤于阀值 时,会临时把它变为shunned
max_latency_ms: mysql_ping响应时⻓,⼤于这个阀值会把它从链接池中剔除(即便是ONLINE状态),默认为0
在proxySQL配置访问用户
insert into mysql_users(username,password,default_hostgroup) values('proxysql_work','123456',10);
load mysql users to runtime;
save mysql users to disk;
在proxySQL配置路由规则,实现读写分离
insert into mysql_query_rules(active,match_pattern,destination_hostgroup,apply) values(1,'^select.*for update$',10,1),(1,'^select',30,1);
load mysql query rules to runtime;
save mysql query rules to disk;
查看读写分离的状态
select * from runtime_mysql_servers;
使用java连接ProxySQL
连接时会出现⼀个问题: Unknown system variable ‘query_cache_size’
这个错误表明系统变量 query_cache_size 未知。这通常发⽣在尝试在MySQL 8.0及以上版本中设置或获取这个变量时,因为在MySQL 8.0版本中,查询缓存(Query Cache)已被移除。
但是ProxySQL中内置的MySQL是5版本的,所以需要在ProxySQL中进⾏设置使⽤版本,最好能与安装的MySQL版本保持⼀致:
update global_variables set variable_value="8.0.18 (ProxySQL)" where variable_name='mysql-server_version';
load mysql variables to run;
save mysql variables to disk;
接下来就可以使⽤JDBC进⾏连接操作或者navicat