MySQL用中间件ProxySQL实现读写分离和主节点故障应用无感应

昨天做的用proxysql实现的读写分离,但是在实际的应用中这样的结构还很不完整,如果主节点出现故障那么整个拓扑的数据库也无法通过proxysql来调用了,所以还需要增加主节点故障后proxysql能够自动切换到新的主节点的功能。

(MGR)组复制能够完成主节点故障后推选出来新的主节点,不过在应用层不可能通过改新的主节点的IP来连接新的主节点,通过mgr+proxysql可能实际主节点故障时应用无感应自动切换到新的主节点。


描述下上面的实现思路:三个节点使multi-primary的方式连接,应用通过连接ProxySQL中间件,根据sql的属性(是否为select语句)来决定连接哪一个节点,一个可写节点,两个只读节点(其实三个都是可写节点,只不过通过proxysql进行了读写分离)。如果默认的可写节点挂掉的话,proxysql通过定期运行的调度器会将另一个只读节点的其中一台设为可写节点,实际主节点故障应用无感应的要求。

上述的整个过程中,应用无需任何变动。应用从意识发生了故障,到连接重新指向新的主,正常提供服务,秒级别的间隔。


下面做一下这个配置:


1.各server说明:

qht131    172.17.61.131    master1

qht132    172.17.61.132    master2

qht133    172.17.61.133    master3

qht134    172.17.61.134    proxysql

multi-primary的主从复制结构 :

mysql>  SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | bb0dea82-58ed-11e8-94e5-000c29e8e89b | qht131      |        3306 | ONLINE       |
| group_replication_applier | bb0dea82-58ed-11e8-94e5-000c29e8e90b | qht132      |        3306 | ONLINE       |
| group_replication_applier | bb0dea82-58ed-11e8-94e5-000c29e8e91b | qht133      |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
3 rows in set (0.00 sec)

2.在数据库端建立proxysql登入需要的帐号(如之前已建立好的话直跳过此步骤)

mysql> CREATE USER 'proxysql'@'%' IDENTIFIED BY 'proxysql';    
Query OK, 0 rows affected (0.41 sec)    
    
mysql> GRANT ALL ON * . * TO  'proxysql'@'%';
Query OK, 0 rows affected (0.00 sec)
    
mysql> create user 'sbuser'@'%' IDENTIFIED BY 'sbpass';    
Query OK, 0 rows affected (0.00 sec)    
    
mysql> GRANT ALL ON * . * TO 'sbuser'@'%';    
Query OK, 0 rows affected (0.00 sec)    
    
mysql> FLUSH PRIVILEGES;    
Query OK, 0 rows affected (0.07 sec) 

3.创建检查MGR节点状态的函数和视图

参照前面的博客,在MGR主节点上执行下面链接中的SQL

https://github.com/lefred/mysql_gr_routing_check/blob/master/addition_to_sys.sql

USE sys;

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_member_in_primary_partition()
RETURNS VARCHAR(3)
DETERMINISTIC
BEGIN
  RETURN (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 USING(member_id));
END$$

CREATE VIEW gr_member_routing_candidate_status AS SELECT
sys.gr_member_in_primary_partition() as viable_candidate,
IF( (SELECT (SELECT GROUP_CONCAT(variable_value) FROM
performance_schema.global_variables WHERE variable_name IN ('read_only',
'super_read_only')) != 'OFF,OFF'), 'YES', 'NO') as read_only,
sys.gr_applier_queue_length() as transactions_behind, Count_Transactions_in_queue as 'transactions_to_cert' from performance_schema.replication_group_member_stats;$$

DELIMITER ;

4.在proxysql中增加帐号

    mysql> INSERT INTO MySQL_users(username,password,default_hostgroup) VALUES ('proxysql','proxysql',1);    

Query OK, 1 row affected (0.00 sec)    
mysql> UPDATE global_variables SET variable_value='proxysql' where variable_name='mysql-monitor_username';    
Query OK, 1 row affected (0.00 sec)    
    
mysql> UPDATE global_variables SET variable_value='proxysql' where variable_name='mysql-monitor_password';    
Query OK, 1 row affected (0.00 sec)    
mysql> LOAD MYSQL SERVERS TO RUNTIME;  
Query OK, 0 rows affected (0.23 sec)  
  
mysql> SAVE MYSQL SERVERS TO DISK;  
Query OK, 0 rows affected (0.08 sec)  
测试一下能否正常登入数据库
[root@qht134 proxysql]# mysql -uproxysql -pproxysql -h 127.0.0.1 -P6033 -e"select @@hostname"
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |
+------------+
| qht131     |
+------------+

5.配置proxysql


mysql>  delete from mysql_servers;
Query OK, 6 rows affected (0.00 sec)

mysql>  insert into mysql_servers (hostgroup_id, hostname, port) values(1,'172.17.61.131',3306);
Query OK, 1 row affected (0.00 sec)

mysql>  insert into mysql_servers (hostgroup_id, hostname, port) values(1,'172.17.61.132',3306);
Query OK, 1 row affected (0.00 sec)

mysql>  insert into mysql_servers (hostgroup_id, hostname, port) values(1,'172.17.61.133',3306);
Query OK, 1 row affected (0.00 sec)

mysql>  insert into mysql_servers (hostgroup_id, hostname, port) values(2,'172.17.61.131',3306);
Query OK, 1 row affected (0.00 sec)

mysql>  insert into mysql_servers (hostgroup_id, hostname, port) values(2,'172.17.61.132',3306);
Query OK, 1 row affected (0.00 sec)

mysql>  insert into mysql_servers (hostgroup_id, hostname, port) values(2,'172.17.61.133',3306);
Query OK, 1 row affected (0.00 sec)

mysql> select * from  mysql_servers ;
+--------------+---------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| hostgroup_id | hostname      | port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+---------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| 1            | 172.17.61.131 | 3306 | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 172.17.61.132 | 3306 | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 172.17.61.133 | 3306 | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.131 | 3306 | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.132 | 3306 | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.133 | 3306 | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
+--------------+---------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
6 rows in set (0.00 sec)

hostgroup_id = 1代表write group,针对我们提出的限制,这个地方只配置了一个节点;hostgroup_id = 2代表read group,包含了MGR的所有节点,目前只是Onlinle的,等配置过scheduler后,status就会有变化 。

对于上面的hostgroup配置,默认所有的写操作会发送到hostgroup_id为1的online节点,也就是发送到写节点上。所有的读操作,会发送为hostgroup_id为2的online节点。


需要确认一下没有使用proxysql的读写分离规则。因为我昨天配置了这个地方,所以需要删除,以免影响后面的测试。

mysql> delete from mysql_query_rules;
Query OK, 2 rows affected (0.50 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

最后我们需要将global_variables,mysql_servers、mysql_users表的信息加载到RUNTIME,更进一步加载到DISK:

mysql> LOAD MYSQL VARIABLES TO RUNTIME;  
Query OK, 0 rows affected (0.00 sec)  
  
mysql> SAVE MYSQL VARIABLES TO DISK;  
Query OK, 94 rows affected (0.02 sec)  
  
mysql> LOAD MYSQL SERVERS TO RUNTIME;  
Query OK, 0 rows affected (0.00 sec)  
  
mysql> SAVE MYSQL SERVERS TO DISK;  
Query OK, 0 rows affected (0.03 sec)  
  
mysql> LOAD MYSQL USERS TO RUNTIME;  
Query OK, 0 rows affected (0.00 sec)  
  
mysql> SAVE MYSQL USERS TO DISK;  
Query OK, 0 rows affected (0.01 sec)  

6.配置scheduler

首先,请在Github地址https://github.com/ZzzCrazyPig/proxysql_groupreplication_checker下载相应的脚本

这个地址有三个脚本可供下载:

proxysql_groupreplication_checker.sh:用于multi-primary模式,可以实现读写分离,以及故障切换,同一时间点多个节点可以多写

gr_mw_mode_cheker.sh:用于multi-primary模式,可以实现读写分离,以及故障切换,不过在同一时间点只能有一个节点能写

gr_sw_mode_checker.sh:用于single-primary模式,可以实现读写分离,以及故障切换

由于我的环境是multi-primary模式,所以选择/proxysql_groupreplication_checker.sh脚本。

接着,将我们提供的脚本proxysql_groupreplication_checker.sh放到目录/var/lib/proxysql/下,并增加可以执行的权限(重要) 。

[root@qht134 ~]# chmod a+x /var/lib/proxysql/proxysql_groupreplication_checker.sh

最后,我们在proxysql的scheduler表里面加载如下记录,然后加载到RUNTIME使其生效,同时还可以持久化到磁盘:

mysql> INSERT INTO scheduler(id,interval_ms,filename,arg1,arg2,arg3,arg4, arg5)
    -> VALUES (1,'10000','/var/lib/proxysql/proxysql_groupreplication_checker.sh','1','2','1','0','/var/lib/proxysql/proxysql_groupreplication_checker.log');
Query OK, 1 row affected (0.00 sec)
mysql> LOAD SCHEDULER TO RUNTIME;
Query OK, 0 rows affected (0.00 sec)

mysql> SAVE SCHEDULER TO DISK;
Query OK, 0 rows affected (0.03 sec)

scheduler各column的说明:

active : 1: enable scheduler to schedule the script we provide

interval_ms : invoke one by one in cycle (eg: 5000(ms) = 5s represent every 5s invoke the script)
filename: represent the script file path

arg1~arg5: represent the input parameters the script received

脚本proxysql_groupreplication_checker.sh对应的参数说明如下:

arg1 is the hostgroup_id for write

arg2 is the hostgroup_id for read
arg3 is the number of writers we want active at the same time
arg4 represents if we want that the member acting for writes is also candidate for reads

arg5 is the log file

schedule信息加载后,就会分析当前的环境,mysql_servers中显示出当前只有qht131是可以写的,qht132以及qht133是用来读的。

mysql>  select * from  mysql_servers ;
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| hostgroup_id | hostname      | port | status       | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| 1            | 172.17.61.131 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 172.17.61.132 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 172.17.61.133 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.131 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.132 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.133 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
6 rows in set (0.00 sec)

因为schedule的arg4我设为了0,就表示可写的节点不能用于读。那我将arg4设置为1试一下:

mysql> update scheduler set arg4=1;
Query OK, 1 row affected (0.00 sec)

mysql> select * from scheduler;
+----+--------+-------------+--------------------------------------------------------+------+------+------+------+---------------------------------------------------------+---------+
| id | active | interval_ms | filename                                               | arg1 | arg2 | arg3 | arg4 | arg5                                                    | comment |
+----+--------+-------------+--------------------------------------------------------+------+------+------+------+---------------------------------------------------------+---------+
| 1  | 1      | 10000       | /var/lib/proxysql/proxysql_groupreplication_checker.sh | 1    | 2    | 1    | 1    | /var/lib/proxysql/proxysql_groupreplication_checker.log |         |
+----+--------+-------------+--------------------------------------------------------+------+------+------+------+---------------------------------------------------------+---------+
1 row in set (0.00 sec)

mysql> SAVE SCHEDULER TO DISK;
Query OK, 0 rows affected (0.01 sec)

mysql> LOAD SCHEDULER TO RUNTIME;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from  mysql_servers;
+--------------+---------------+------+--------------+--------+-------------+-----------------+----------   -----------+---------+----------------+---------+
| hostgroup_id | hostname      | port | status       | weight | compression | max_connections | max_repli   cation_lag | use_ssl | max_latency_ms | comment |
+--------------+---------------+------+--------------+--------+-------------+-----------------+----------   -----------+---------+----------------+---------+
| 1            | 172.17.61.131 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                      | 0       | 0              |         |
| 1            | 172.17.61.132 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                      | 0       | 0              |         |
| 1            | 172.17.61.133 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                      | 0       | 0              |         |
| 2            | 172.17.61.131 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                      | 0       | 0              |         |
| 2            | 172.17.61.132 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                      | 0       | 0              |         |
| 2            | 172.17.61.133 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                      | 0       | 0              |         |
+--------------+---------------+------+--------------+--------+-------------+-----------------+----------   -----------+---------+----------------+---------+
6 rows in set (0.00 sec)

arg4设置为1之后,qht131节点用来写的同时也可以被用来写。

便于下面的测试还是将arg4设为0:

mysql>  update scheduler set arg4=0;
Query OK, 1 row affected (0.00 sec)

mysql>  SAVE SCHEDULER TO DISK;
Query OK, 0 rows affected (0.02 sec)

mysql>  LOAD SCHEDULER TO RUNTIME;
Query OK, 0 rows affected (0.00 sec)
mysql>  select * from  mysql_servers;
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| hostgroup_id | hostname      | port | status       | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| 1            | 172.17.61.131 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 172.17.61.132 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 172.17.61.133 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.131 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.132 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.133 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
6 rows in set (0.00 sec)

各个节点的gr_member_routing_candidate_status视图也显示了当前节点是否是正常状态的,proxysql就是读取的这个视图的信息来决定此节点是否可用。

mysql> select * from sys.gr_member_routing_candidate_status\G
*************************** 1. row ***************************
    viable_candidate: YES
           read_only: NO
 transactions_behind: 0
transactions_to_cert: 0
1 row in set (0.01 sec)

7.设置读写分离:

mysql> insert into mysql_query_rules (active, match_pattern, destination_hostgroup, apply)
    -> values (1,"^SELECT",2,1);
Query OK, 1 row affected (0.00 sec)

mysql> LOAD MYSQL QUERY RULES TO RUNTIME;
Query OK, 0 rows affected (0.00 sec)

mysql> SAVE MYSQL QUERY RULES TO DISK;
Query OK, 0 rows affected (0.03 sec)

match_pattern的规则是基于正则表达式的,

active表示是否启用这个sql路由项,

match_pattern就是我们正则匹配项,
destination_hostgroup表示我们要将该类sql转发到哪些mysql上面去,这里我们将select转发到group 2,。

apply为1表示该正则匹配后,将不再接受其他匹配,直接转发。

对于for update需要在gruop1上执行,可以加上规则:

insert into mysql_query_rules(active,match_pattern,destination_hostgroup,apply) values(1,'^SELECT.*FOR UPDATE$',1,1); 

通过一个循环连接proxysql,由于是select 语句,一直连接的是qht132和qht133

[root@qht133 ~]# while true; do mysql -h 172.17.61.134 -u proxysql -pproxysql -P 6033 -e "select @@hostname, sleep(3)" 2>/dev/null; done
+------------+----------+
| @@hostname | sleep(3) |
+------------+----------+
| qht132     |        0 |
+------------+----------+
+------------+----------+
| @@hostname | sleep(3) |
+------------+----------+
| qht133     |        0 |
+------------+----------+
+------------+----------+
| @@hostname | sleep(3) |
+------------+----------+
| qht132     |        0 |
+------------+----------+
+------------+----------+
| @@hostname | sleep(3) |
+------------+----------+
| qht133     |        0 |
+------------+----------+

8.设置故障应用无感应:

在读写分离中,我设置了qht131为可写节点,qht132,qht133为只读节点

如果此时qht131变成只读模式的话,应用能不能直接连到其它的节点进行写操作?

现手动将qht131变成只读模式:

mysql> set global read_only=1;
Query OK, 0 rows affected (0.00 sec)

观察一下mysql_servers的状态,自动将group1的qht132改成了online,group2的qht131,qht133变成online了,就表示将qht132变为可写节点,其它两个节点变为只读节点了。

mysql> select * from  mysql_servers;
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| hostgroup_id | hostname      | port | status       | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| 1            | 172.17.61.131 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 172.17.61.132 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 172.17.61.133 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.131 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.132 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.133 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
6 rows in set (0.00 sec)

通过模拟的连接也可以看到select语句都连接到qht131和qht133进行了。

[root@qht133 ~]# while true; do mysql -h 172.17.61.134 -u proxysql -pproxysql -P 6033 -e "select @@hostname, sleep(3)" 2>/dev/null; done
+------------+----------+
| @@hostname | sleep(3) |
+------------+----------+
| qht133     |        0 |
+------------+----------+
+------------+----------+
| @@hostname | sleep(3) |
+------------+----------+
| qht131     |        0 |
+------------+----------+
+------------+----------+
| @@hostname | sleep(3) |
+------------+----------+
| qht133     |        0 |
+------------+----------+
+------------+----------+
| @@hostname | sleep(3) |
+------------+----------+
| qht131     |        0 |
+------------+----------+

将qht131变为可写模式后,mysql_servers也恢复过来了。

mysql> set global read_only=0;
Query OK, 0 rows affected (0.00 sec)
mysql>  select * from  mysql_servers;
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| hostgroup_id | hostname      | port | status       | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| 1            | 172.17.61.131 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 172.17.61.132 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 172.17.61.133 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.131 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.132 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.133 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
6 rows in set (0.00 sec)

经过测试将qht131节点停止组复制(stop group_replication)后,mysql_servers表的信息也会正常的切换新的节点。待qht131再加入到组复制后,mysql_servers也会正常的将qht131改成online状态。

mysql> select * from  mysql_servers;
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| hostgroup_id | hostname      | port | status       | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| 1            | 172.17.61.131 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 172.17.61.132 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 172.17.61.133 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.131 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.132 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.133 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
6 rows in set (0.00 sec)


容易出现的错误:

mysql>  select * from  mysql_servers ;
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| hostgroup_id | hostname      | port | status       | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| 1            | 172.17.61.131 | 3306 | OFFLINE_HARD | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.131 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.132 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.133 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
4 rows in set (0.00 sec)

所有节点都offline了,错误日志如下:

[2018-05-22 23:57:52] read node [hostgroup_id: 2, hostname: 172.17.61.133, port: 3306, isOK: 0] is not OK, we will set it's status to be 'OFFLINE_SOFT'
ERROR 1142 (42000) at line 1: SELECT command denied to user 'proxysql'@'qht134' for table 'gr_member_routing_candidate_status'
[2018-05-22 23:57:55] current write node [hostgroup_id: 2, hostname: 172.17.61.131, port: 3306, isOK: 0] is not OK, we need to do switch over
ERROR 1142 (42000) at line 1: SELECT command denied to user 'proxysql'@'qht134' for table 'gr_member_routing_candidate_status'
[2018-05-22 23:57:55] read node [hostgroup_id: 2, hostname: 172.17.61.132, port: 3306, isOK: 0] is not OK, we will set it's status to be 'OFFLINE_SOFT'
ERROR 1142 (42000) at line 1: SELECT command denied to user 'proxysql'@'qht134' for table 'gr_member_routing_candidate_status'

从错误日志上看出是权限的问题,proxysql用户没有足够的权限读取数据。

解决:

mysql> GRANT ALL ON * . * TO  'proxysql'@'%';  mysql> flush privileges;
mysql>  select * from  mysql_servers;
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| hostgroup_id | hostname      | port | status       | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| 1            | 172.17.61.131 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 172.17.61.132 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 172.17.61.133 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.131 | 3306 | OFFLINE_SOFT | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.132 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.17.61.133 | 3306 | ONLINE       | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
+--------------+---------------+------+--------------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
6 rows in set (0.00 sec)

参考:

http://lefred.be/content/ha-with-mysql-group-replication-and-proxysql/

https://blog.csdn.net/d6619309/article/details/54602556


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第1节 课程概述 [免费观看] 00:12:22分钟 | 第2节 课程背景 [免费观看] 00:09:12分钟 | 第3节 纵观大型网站架构发展,总结持久化部分需要应对的问题 [免费观看] 00:27:12分钟 | 第4节 操作系统安装以及配置 00:31:22分钟 | 第5节 在CentOS上通过yum安装mysql5.7 00:15:32分钟 | 第6节 mysql初次见面-mysql5.7的用户以及安全策略 00:05:34分钟 | 第7节 mysql初次见面续-mysql基本操作 00:37:36分钟 | 第8节 认识从复制 00:15:01分钟 | 第9节 从复制的准备工作01-mysql用户以及权限 00:12:11分钟 | 第10节 从复制的准备工作02-binlog日志详解 00:33:23分钟 | 第11节 从实战01-准备环境 00:26:06分钟 | 第12节 从实战02-节点配置 00:06:19分钟 | 第13节 从实战03-从节点配置 00:10:45分钟 | 第14节 java操作从01 00:24:26分钟 | 第15节 java操作从02 00:13:48分钟 | 第16节 复制 00:32:23分钟 | 第17节 负载均衡概述以及环境准备 00:20:42分钟 | 第18节 搭建负载均衡-01 00:22:54分钟 | 第19节 搭建负载均衡-02 00:06:06分钟 | 第20节 启动haproxy的监控功能 00:14:52分钟 | 第21节 高可用以及环境准备 00:40:14分钟 | 第22节 搭建keepalived 00:19:42分钟 | 第23节 Keepalived配置简介 00:11:01分钟 | 第24节 Keepalived配置邮件 00:42:27分钟 | 第25节 Keepalived其他配置 00:12:13分钟 | 第26节 分库分表概述 00:12:18分钟 | 第27节 逻辑分表01-水平分表 00:32:43分钟 | 第28节 逻辑分表02-水平分表续及垂直分表 00:13:36分钟 | 第29节 表分区 00:42:19分钟 | 第30节 数据库中间件01-认识mycat 00:22:32分钟 | 第31节 数据库中间件02-mycat安装 00:18:18分钟 | 第32节 数据库中间件03-mycat的helloworld 00:31:11分钟 | 第33节 数据库中间件04-mycat的初识 00:13:57分钟 | 第34节 数据库中间件05-mycat的数据切分 00:13:50分钟 | 第35节 数据库中间件06-mycat的读写分离-01 00:11:16分钟 | 第36节 数据库中间件06-mycat的读写分离-02 00:24:06分钟 | 第37节 数据库中间件06-mycat的读写分离03-读写分离补充 00:03:37分钟 | 第38节 数据库中间件07-mycat的高可用-01 00:10:01分钟 | 第39节 数据库中间件08-mycat的高可用-02 00:06:13分钟 | 第40节 数据库中间件09-mycat集群 00:08:08分钟 | 第41节 mysql查询缓存 00:08:17分钟 | 第42节 数据库切分概述 00:37:09分钟 | 第43节 java环境配置 00:13:42分钟 | 第44节 水平切分原理及单表切分后的操作 00:47:46分钟 | 第45节 水平切分原理及单表切分后的操作-2 00:19:32分钟 | 第46节 水平切分多表关联操作 00:38:14分钟 | 第47节 垂直切分原理及操作 00:17:23分钟 | 第48节 全局序列号 00:21:35分钟 | 第49节 数据库切分策略-分片枚举 00:35:49分钟 | 第50节 数据库切分策略-hash 00:41:16分钟 | 第51节 数据库切分策略-范围约定 00:17:20分钟 | 第52节 数据库切分策略-取模 00:13:54分钟 | 第53节 数据库切分策略-按日期分片 00:17:43分钟 | 第54节 全局表 00:04:27分钟 | 第55节 认识MyCat 00:13:55分钟 | 第56节 部署MyCat 00:20:20分钟 | 第57节 使用MyCat完成简单的数据库分片 00:28:58分钟 | 第58节 MyCat分片策略 00:13:08分钟 | 第59节 MyCat全局表配置 00:05:18分钟 | 第60节 MyCatER表配置 00:20:27分钟 | 第61节 另外一种切分方式-使用客户端组件的方式实现数据库分 00:06:20分钟 |
分布式架构 漫谈分布式架构 初识分布式架构与意义 如何把应用从单机扩展到分布式 大型分布式架构演进过程 分布式架构设计 流架构模型-SOA架构和微服务架构 领域驱动设计及业务驱动规划 分布式架构的基本理论CAP、BASE以及其应用 什么是分布式架构下的高可用设计 构架高性能的分布式架构 构建分布式架构最重要因素 CDN静态文件访问 分布式存储 分布式搜索引擎 应用发布与监控 应用容灾及机房规划 系统动态扩容 分布式架构策略-分而治之 从简到难,从网络通信探究分布式通信原理 基于消息方式的系统间通信 理解通信协议传输过程中的序列化和反序列化机制 基于框架的RPC通信技术 WebService/ApacheCXF RMI/Spring RMI Hession 传统RPC技术在大型分布式架构下面临的问题 分布式架构下的RPC解决方案 Zookeeper 分布式系统的基石 从0开始搭建3个节点额度zookeeper集群 深入分析Zookeeper在disconf配置中心的应用 基于Zookeeper Watcher 核心机制深入源码分析 Zookeeper集群升级、迁移 基于Zookeeper实现分布式服务器动态上下线感知 深入分析Zookeeper Zab协议及选举机制源码解读 Dubbo 使用Dubbo对单一应用服务化改造 Dubbo管理中心及及监控平台安装部署 Dubbo分布式服务模块划分(领域驱动) 基于Dubbo的分布式系统架构实战 Dubbo负载均衡策略分析 Dubbo服务调试之服务只订阅及服务只注册配置 Dubbo服务接口的设计原则(实战经验) Dubbo设计原理及源码分析 基于Dubbo构建大型分布式电商平台实战雏形 Dubbo容错机制及扩展性分析 分布式解决方案 分布式全局ID生成方案 session跨域共享及企业级单点登录解决方案实战 分布式事务解决方案实战 高并发下的服务降级、限流实战 基于分布式架构下分布式锁的解决方案实战 分布式架构实现分布式定时调度 分布式架构-中间件 分布式消息通信 消息中间件在分布式架构中的应用 ActiveMQ ActiveMQ高可用集群企业及部署方案 ActiveMQ P2P及PUB/SUB模式详解 ActiveMQ消息确认及重发策略 ActiveMQ基于Spring完成分布式消息队列实战 Kafka Kafka基于Zookeeper搭建高可用集群实战 kafka消息处理过程剖析 Java客户端实现Kafka生产者与消费者实例 kafka的副本机制及选举原理剖析 基于kafka实现应用日志实时上报统计分析 RabbitMQ 初步认识RabbitMQ及高可用集群部署 详解RabbitMQ消息分发机制及题消息分发 RabbitMQ消息路由机制分析 RabbitMQ消息确认机制 Redis redis数据结构分析 Redis从复制原理及无磁盘复制分析 Redis管道模式详解 Redis缓存与数据库一致性问题解决方案 基于redis实现分布式实战 图解Redis中的AOF和RDB持久化策略的原理 redis读写分离架构实践 redis哨兵架构及数据丢失问题分析 redis Cluster数据分布算法之Hash slot redis使用常见问题及性能优化思路 redis高可用及高并发实战 缓存击穿、缓存雪崩预防策略 Redis批量查询优化 Redis高性能集群之Twemproxy of Redis 数据存储 MongoDB NOSQL简介及MongoDB支持的数据类型分析 MongoDB可视化客户端及JavaApi实践 手写基于MongoDB的ORM框架 MongoDB企业级集解决方案 MongoDB聚合、索引及基本执行命令 MongoDB数据分片、转存及恢复策略 MyCat MySQL从复制及读写分离实战 MySQL+keepalived实现高可用方案实践 MySQL高性能解决方案之分库分表 数据库中间件初始Mycat 基于Mycat实习MySQL数据库读写分离 基于Mycat实战之数据库切分策略剖析 Mycat全局表、Er表、分片预警分析 Nginx 基于OpenResty部署应用层Nginx以及Nginx+lua实战 Nginx反向代理服务器及负载均衡服务器配置实战 利用keepalived+Nginx实战Nginx高可用方案 基于Nginx实现访问控制、连接限制 Nginx动静分离实战 Nginx Location ReWrite 等语法配置及原理分析 Nginx提供https服务 基于Nginx+lua完成访问流量实时上报Kafka的实战 Netty 高性能NIO框架 IO 的基本概念、NIO、AIO、BIO深入分析 NIO的核心设计思想 Netty产生的背景及应用场景分析 基于Netty实现的高性能IM聊天 基于Netty实现Dubbo多协议通信支持 Netty无锁化串行设计及高并发处理机制 手写实现多协议RPC框架
奇虎360公司开源的Atlas是优秀的数据库中间件,美团点评DBA团队针对公司内部需求,在其上做了很多改进工作,形成了新的高可靠、高可用企业级数据库中间件DBProxy,已在公司内部生产环境广泛使用,较为成熟、稳定。 DBProxy的优点 支持多语言MySQL客户端 读写分离 负载均衡 Slave故障感知与摘除(Master需要MHA等其他联动) 后端连接池 自定义SQL拦截与过滤 流量分组与控制 丰富的监控状态 支持分表(分库版本正在内测中) Client IP限制 DBProxy对Atlas的改进 新增功能点 新增参数 backend-max-thread-running用于指定每个MySQL后台的最大thread running数 thread-running-sleep-delay用于指定在thread running数超过backend-max-thread-running时,客户端连接等待的时间 添加到黑名单中需要满足两个条件:SQL执行的时间和频率 提供了查看、修改、添加、删除黑名单的功能 黑名单管理提供了将黑名单保存到文件以及从文件中Load到内存中的功能 在手动添加黑名单时,只需要将用户的SQL语句输入,在内部自动转化成过滤条件,手动添加时是否生效由参数 manual-filter-flag 来控制,OFF:不生效,ON:立即生效 手动添加与自动添加两种情况下的过滤条件是否生效是分别由不同参数控制,这个要区分清楚。另外,也可以使用 admin 的命令来设置是否开启/关闭某个过滤条件 SQL执行的时间 由参数 query-filter-time-threshold 来指定,如果SQL执行时间超过此值,则满足条件 SQL执行频率 由参数 query-filter-frequent-threshold 来指定,如果SQL执行频率超过此值,则满足条件 频率就是在时间窗口内执行的次数。时间窗口则是由频率阈值和最小执行次数来计算出来的,当时间窗口小于60s时,扩展到60s 参数 access-num-per-time-window 用来指定在时间窗口内的最小执行次数,添加此参数是考虑到执行时间长的SQL在计算频率时同时参考其执行的次数,只有执行一定次数时才去计算其频率。当执行时间与执行频率都满足时条件时,会自动将查询作为过滤项放到黑名单中,加入到黑名单中是否生效由参数 auto-filter-flag 来控制,OFF:不生效,ON:立即生效 黑名单的管理 从库流量配置 指定查询发送到某个从库 参数动态设置(完善show proxy status/variables) 支持save config,动态增加、删除分表 响应时间percentile统计 统计最近时间段DBProxy的响应时间 kill session 支持DBProxy的admin接口kill session操作 backend平滑上下线 支持平滑的backend上下线 DBProxy非root用户启动 使用非root用户启动 admin账号的安全限制 admin账号密码的动态修改及host限制 增加异步刷日志的功能 增加日志线程、异步刷日志,提高响应时间 支持DBProxy平滑重启功能 支持SQL过滤的黑名单功能 支持对于MySQL后台的thread running限制功能 该功能通过在DBProxy内限制每个后台MySQL的并发查询,来控制对应MySQL的thread running数 当发向某个MySQL后台的的并发查询超过某个阈值时,会进行超时等待,直到有可用的连接,其中阈值与超时等待的时间都已经参数化,可以动态配置 set backend offline不再显示节点状态 支持set transaction isolation level 支持use db 支持set option语句 支持set session级系统变量 支持建立连接时指定连接属性 改进连接池的连接管理,增加超时释放机制。当连接池中的空闲连接闲置超过一定时

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值