介绍一下基本概念
🤔基于上文配置的MGR会出现一个问题
虽然我们配置完mgr实现了主从切换,主节点负责写,主从节点都可读 但是由于mgr的特性,主节点宕机之后会自动选举新的主节点,此时我们应用的mysql配置就存在需要修改的情况,频繁的去修改配置重启肯定是不实际的,在生产环境这么搞,估计老板晚上都睡不好了!
为了解决这个问题,proxysql是的香!!!
proxysql是什么:
proxysql是实现数据库负载均衡和流量路由的工具,是在应用服务和mysql服务之间的一个代理层,应用服务通过配置proxysql节点的ip+端口,实现访问mysql的多个节点
传统方式
使用proxysql代理
接下来让我手把手教你如何配置最基本的proxysql+mgr
首先进行规划
节点1 | 节点2 | 节点3 |
---|---|---|
172.28.15.52 | 172.28.5.229 | 172.28.2.171 |
首先是安装proxysql,这个在任何节点安装都可以,我们选择在节点1安装,后续统一使用节点1、2、3称呼
注:6032 是 ProxySal的管理端口号,6033 是对外服务的端口号
这个是proxysql的下载地址,下载地址 github.com/sysown/prox... 下载完成之后直接上传,用命令安装,这块比较容易不做过多解释
yum localinstall proxysql-2.3.2-1-centos8.x86 64.rpm
启动proxysql
sql
启动
systemctl start proxysql
启动之后开始我们的重头戏 首先我们使用命令登录到proxysql内置的mysql中
css
在节点1,即proxysql的节点上,使用6032管理端口访问,6033是对外的端口
mysql -uadmin -padmin -h127.0.0.1 -P 6032
将我们的mgr集群三台节点的信息存到proxysql中
sql
insert into mysql_servers(hostgroup_id,hostname,port) values
(10,'节点1'3306);
insert into mysql_servers(hostgroup_id,hostname,port) values
(10,'节点2'3306);
insert into mysql_servers(hostgroup_id,hostname,port) values
(10,'节点3'3306);
css
LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;
LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;
LOAD MYSQL USERS TO RUNTIME;
SAVE MYSQL USERS TO DISK;
然后我们创建两个用户,monitor和proxysql,monitor用于proxysql去监控我们集群的状态,proxysql用于给我们的应用服务配置访问proxysql
sql
这一块的命令在我们mgr集群的主节点上使用
CREATE USER 'monitor'@'%' IDENTIFlED with mysql_native_password By "monitor@2021";
CREATE USER 'proxysql'@'%' IDENTIFlED with mysql_native_password By "proxysql@2021";
GRANT ALL PRIVILEGES ON *.* TO 'monitor'@'%';
GRANT ALL PRIVILEGES ON *.* TO 'proxysq!'@'%';
flush privileges;
然后回到我们proxysql的终端中操作,这块是设置监控账号以及给proxysql插入能够访问mgr的账号
less
set mysql-monitor_username='monitor' ;
set mysal-monitor_password='monitor@2021';
Insert into mysql_users(username,password,active,default_hostgroup,transaction_persistent)
values('proxysql',proxysql@2021',1,10,1);
接下来是重重重头戏,在mgr主节点创建视图,用于监控账号访问,使proxysql能够监听到mgr的状态
sql
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;
DROP FUNCTION IF EXISTS my_server_uuid;
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_pos 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_status 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 RETURN ( 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_group_members WHERE MEMBER_STATE != 'ONLINE' ) >= ( ( SELECT COUNT(*) FROM `performance_schema`.replication_group_members ) / 2 ) =0),
'YES',
'NO'
)
FROM
`performance_schema`.replication_group_members
JOIN `performance_schema`.replication_group_member_stats rgms USING ( member_id )
WHERE
rgms.MEMBER_ID = my_server_uuid ()),
'No'
) AS viable_candidate,
IFNULL(`sys`.gr_applier_queue_length(), 0 ) AS transactions_behind,
IFNULL(`sys`.gr_transactions_to_cert(), 0 ) AS transactions_to_cert,
IF
(
(
SELECT((select
GROUP_CONCAT( `performance_schema`.global_variables.VARIABLE_VALUE SEPARATOR ',' )
FROM
`performance_schema`.global_variables
WHERE
(
`performance_schema`.global_variables.VARIABLE_NAME IN ( 'read_only', 'super_read_only' ))) != 'OFF,OFF'
)) ,
'YES',
'No'
) AS read_only;$$
DELIMITER;
最后面的view可能会执行报错,不用管,只要保证最后一个view有建起来即可
下面这个命令在mgr中执行 如果视图和function都创建成功是可以查询出这个的
csharp
在mgr中执行查询语句
select * from sys.gr_member_routing_candidate_status;
接下来我们回到proxysql终端操作
首先设置读写组
sql
insert into mysql_group_replication_hostgroups(writer_hostgroup,backup_writer_hostgroup,reader_hostgroup,offline_hostgroup,active,max_writers,writer_is_also_reader,max_transactions_behind) values(10,20,30,40,1,1,0,100);
执行语句将配置都刷新proxysql
css
LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;
LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;
LOAD MYSQL USERS TO RUNTIME;
SAVE MYSQL USERS TO DISK;
proxysql执行语句,此时可以看到,proxysql查询到了我们的mgr集群,10、20、30、40是我们设置的主写,备写,主读,备读的组id,
sql
select hostgroup_id, hostname, port,status from runtime_mysql_servers;
此时可以停掉主节点,看这个语句是否改变,我们执行systemctl stop mysqld,停掉我们的mgr主节点 此时可以看到监控到了节点挂了,并且52节点变成了10,主写节点
执行命令查看节点情况
sql
select hostname, port, viable_candidate, read_only, transactions_behind, error from mysql_server_group_replication_log order by time_start_us desc limit 6;
接下来我们要配置读写分离规则,这个语句不要输入错了,否则无法对我们写的sql进行读写代理
sql
INSERT INTO mysql_query_rules (rule_id, active, match_digest, destination_hostgroup, apply)VALUES (1, 1, '^SELECT.*FOR UPDATES$', 10, 1),(2, 1, '^SELECT', 30, 1);
加载配置
css
LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;
LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;
LOAD MYSQL USERS TO RUNTIME;
SAVE MYSQL USERS TO DISK;
接下来我们在任意一台节点访问proxysql的对外6033端口
css
mysql -u proxysql -p'xxxx' -P 6033 -h172.28.15.52 -e 'select user,host from mysql.user where 1=1;'
在proxysql中执行查询语句,查看路由的情况,我们查看到查询语句被转发到读节点上,组id为30代表主读节点组
csharp
select hostgroup,digest_text,username from stats_mysql_query_digest;
执行建表语句可以看到是代理到了主节点上
sql
CREATE TABLE `mgrtest2` (
`id` int NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=231232 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
至此我们就完成了proxysql对mgr集群的代理和监控,我们只需要在我们的应用服务配置proxysql节点的ip+6033端口,使用proxysql这个用户,或者自己建一个新用户,授权,并且把这个用户配置到proxysql中,即可实现访问proxysql代理到mgr,注意6032为proxysql的内部端口,只有admin/admin可访问。6033为对外端口