使用ProxySQL实现MySQL Group Replication的故障转移、读写分离(一)


image


导读:html

在以前,咱们搭建了MySQL组复制集群环境,MySQL组复制集群环境解决了MySQL集群内部的自动故障转移,可是,组复制并无解决外部业务的故障转移。举个例子,在A、B、C 3台机器上搭建了组复制环境,且运行在单主模式下,这里假设A为主节点,应用程序链接A写数据,若是A节点发生宕机,主节点切换到B机器上,此时,应用程序是不会自动链接到B服务器上的,须要人工进行切换。node

Snipaste_2020-07-29_22-00-09

在这篇文章中,咱们要介绍的ProxySQL就可以解决上面的问题,ProxySQL可以实现业务层面故障转移、读写分离功能,固然ProxySQL不只仅只有这两项功能,还有更多的其它功能。其架构以下:mysql

Snipaste_2020-07-29_22-10-45

咱们不妨来了解一下。git




(一)ProxySQL简介

ProxySQL是一款MySQL代理软件,其核心特色为读写分离、故障转移,详细其功能以下:github

  • 应用层代理。ProxySQL不只可以实现负载均衡,还可提供端到端链接处理、实时信息统计和数据库流量检查;
  • 零停机时间变动。ProxySQL在内存中直接进行配置修改,而后能够持久存储到磁盘和推送到运行中;
  • 数据库防火墙。可充当应用程序与数据库之间的防火墙,使DBA能够保护数据库免受恶意活动或有问题的程序的影响;
  • 高级查询规则。使用ProxySQL丰富的查询规则定义查询路由,有效的分发和缓存数据,从而最大的提升数据库服务缓存效率;
  • 数据分片与转换
  • 故障转移检测。ProxySQL经过连续监视数据库后端并在拓扑更改时将流量从新路由到运行正常的节点。


这里,咱们使用ProxySQL来对MySQL组复制环境实现读写分离以及故障转移。个人环境以下:sql

IP地址 主机名 用途
192.168.10.11 mgr-node1 MySQL组复制成员
192.168.10.12 mgr-node2 MySQL组复制成员
192.168.10.13 mgr-node3 MySQL组复制成员
192.168.10.10 proxysql ProxySQL代理服务器

MySQL采用多主模式,搭建过程见文档:《MySQL组复制MGR(二)-- 组复制搭建》,本文把重点放在ProxySQL的搭建与配置上。shell


(二)安装ProxySQL数据库

安装ProxySQL,有2种方法,若是有网络,能够直接使用yum安装,若是没有网络,能够下载ProxySQL发行包安装,下载地址为:https://github.com/sysown/proxysql/releases。这里为了方便,直接使用yum在线安装。
添加yum源,使用Linux root用户执行以下配置:后端

cat <<EOF | tee /etc/yum.repos.d/proxysql.repo
[proxysql_repo]
name= ProxySQL YUM repository
baseurl=https://repo.proxysql.com/ProxySQL/proxysql-2.0.x/centos/\$releasever
gpgcheck=1
gpgkey=https://repo.proxysql.com/ProxySQL/repo_pub_key
EOF

安装proxysql:centos

yum install -y proxysql OR yum install proxysql-version

若是要查看安装的文件在哪,可使用以下命令:

[root@proxysql yum.repos.d]# rpm -ql proxysql
/etc/logrotate.d/proxysql
/etc/proxysql.cnf
/etc/systemd/system/proxysql-initial.service
/etc/systemd/system/proxysql.service
/usr/bin/proxysql
/usr/share/proxysql/tools/proxysql_galera_checker.sh
/usr/share/proxysql/tools/proxysql_galera_writer.pl

查看ProxySQL进程:

[root@proxysql yum.repos.d]# ps -ef|grep proxy
avahi 740 1 0 15:52 ? 00:00:00 avahi-daemon: registering [proxysql-65.local]
root 761 1 0 15:52 ? 00:00:00 /usr/sbin/gssproxy -D
proxysql 2058 1 0 16:09 ? 00:00:00 /usr/bin/proxysql --idle-threads -c /etc/proxysql.cnf
proxysql 2059 2058 1 16:09 ? 00:00:00 /usr/bin/proxysql --idle-threads -c /etc/proxysql.cnf
root 2087 1589 0 16:09 pts/0 00:00:00 grep --color=auto proxy

查看端口,6032是proxysql的管理端口,6033是对外服务端口

[root@proxysql yum.repos.d]# netstat -anlp | grep proxysql
tcp 0 0 0.0.0.0:6032 0.0.0.0:* LISTEN 2059/proxysql
tcp 0 0 0.0.0.0:6033 0.0.0.0:* LISTEN 2059/proxysql

(三)启动关闭ProxySQL

启动ProxySQL

service proxysql start

关闭ProxySQL

service proxysql stop

重启ProxySQL

service proxysql restart

查看ProxySQL的状态

service proxysql status


(四)ProxySQL基础知识了解

ProxySQL的配置,相对而言仍是比较复杂的。所以,在配置ProxySQL以前,咱们须要对其架构有一些了解,这样在配置的时候,才不会一脸懵逼。

(4.1)ProxySQL多层配置系统

前面咱们说到ProxySQL具备“零停机时间变动”功能,它是经过3层配置来实现的,3层配置包括:Runtime、Memory、Disk & Configuration File。

  • Runtime层表示ProxySQL工做线程使用的内存数据结构;
  • Memory(也被称为main)层经由一个MySQL兼容接口露出的内存数据库,用户可使用MySQL客户端链接到管理界面,查看、编辑ProxySQL配置表;
  • Disk & Configuration File。Disk层是一个存放在磁盘上的SQLite3数据库,Disk层可将内存中的配置信息保存到磁盘,以便ProxySQL从新启动后配置还可用。

3个层面的信息有什么区别呢?我我的的理解是:3个层面保存的都是ProxySQL的配置信息,若是管理员未做修改,那么3个层面的配置信息是相同的。若是管理员要修改配置信息,首先须要修改Memory层,要让修改的信息马上生效,则须要把Memory层的变动信息推到Runtime层;要让修改的配置信息在ProxySQL重启后还能保存下来,则须要把Memory层的信息推到Disk层。Runtime层是ProxySQL正在使用的配置信息,Memory层是用户能够编辑的信息,Disk层能够把配置信息永久保存在磁盘上。

Snipaste_2020-07-29_21-31-12

各层之间数据如何同步呢?咱们能够看上图的箭头部分,经过load/save命令来实现同步。具体命令以下:

[1] LOAD <item> FROM MEMORY/LOAD <item> TO RUNTIME
将配置项从内存数据库加载到运行时数据结构

[2] SAVE <item> TO MEMORY/SAVE <item> FROM RUNTIME
将配置项从运行时保存到内存数据库中

[3] LOAD <item> TO MEMORY/LOAD <item> FROM DISK
将持久性配置项目从磁盘数据库加载到内存数据库

[4] SAVE <item> FROM MEMORY/SAVE <item> TO DISK
将配置项从内存数据库保存到磁盘数据库

[5] LOAD <item> FROM CONFIG
将配置项从配置文件加载到内存数据库中

经常使用的配置有:

# 激活用户配置到RUNTIME
LOAD MYSQL USERS TO RUNTIME;

# 保存用户信息到磁盘上
SAVE MYSQL USERS TO DISK;

---------------------------------
# 激活MySQL服务器信息到RUNTIME
LOAD MYSQL SERVERS TO RUNTIME;

# 保存MySQL服务器信息到磁盘
SAVE MYSQL SERVERS TO DISK;

---------------------------------
# 激活查询路由规则到RUNTIME
LOAD MYSQL QUERY RULES TO RUNTIME;

# 保存查询路由规则到磁盘
SAVE MYSQL QUERY RULES TO DISK;

----------------------------------
# 激活MySQL变量到RUNTIME
LOAD MYSQL VARIABLES TO RUNTIME;

# 保存MySQL变量到磁盘
SAVE MYSQL VARIABLES TO DISK;

----------------------------------
# 激活proxySQL admin变量到RUNTIME
LOAD ADMIN VARIABLES TO RUNTIME;

# 保存proxySQL admin变量到磁盘
SAVE ADMIN VARIABLES TO DISK;


(4.2)ProxySQL的配置管理接口

ProxySQL有2种配置方式:

  • 使用ProxySQL的命令行管理接口进行配置
  • 使用配置文件进行配置

一般使用第一种方法进行配置,这里咱们只了解第1种方法。

ProxySQL管理界面使用的是MySQL协议的界面,经过使用mysql客户端链接到SQLite3进行配置的查询、管理。可使用默认的admin用户链接到proxySQL数据库。

[root@proxysql ~]# mysql -uadmin -padmin -h127.0.0.1 -P6032

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 |
 +-----+---------------+-------------------------------------+

这些数据库做用以下:

  • main:内存配置数据库,使用此数据库,能够方便的查询和更新ProxySQL的配置。与上面所曾配置系统的Memory层对应;
  • disk:“main”数据库的磁盘镜像。从新启动ProxySQL时,main中的数据就是从该数据库加载的。与上面所曾配置系统的disk层对应;
  • stats:ProxySQL收集的一些指标。如每一个查询规则的匹配次数,当前正在运行的查询等;
  • monitor:包含于ProxySQL链接的后端服务器的指标。如链接带后端服务器对其进行ping操做的最小、最大时间;

ProxySQL设定了2个用户来管理配置数据库:

  • 帐号admin  密码admin : 该用户具备所有标的读写权限;
  • 帐号stats  密码stats : 该用户具备统计信息表的只读权限;


(五)一步一步配置ProxySQL--基础配置

(5.1)检查配置信息

查看相关配置表是否存在信息,由于还没开始配置,因此是不存在信息的,若是已经配置过了,能够先删除信息。

mysql> select * from mysql_servers;
Empty set (0.00 sec)

mysql> select * from mysql_users;
Empty set (0.01 sec)

mysql> select * from mysql_query_rules;
Empty set (0.00 sec)

mysql> select * from mysql_group_replication_hostgroups;
Empty set (0.00 sec)


(5.2)组的配置

所谓组的配置,即定义读组、写组等,可使用以下两个表来定义读写组:

  • mysql_replication_hostgroups:该表用于传统的master/slave的异步复制或者半同步复制的配置。
  • mysql_group_replication_hostgroups:该表用于MySQL Group Replication、InnoDB Cluster or Galera/Percona XtraDB Cluster的配置

由于咱们这里是使用proxySQL来实现MGR集群业务层面的实现故障转移以及读写分离的,因此配置mysql_group_replication_hostgroups表便可,该表定义以下:

show create table mysql_group_replication_hostgroups;
------------------------------------------------------------
CREATE TABLE mysql_group_replication_hostgroups (
    writer_hostgroup INT CHECK (writer_hostgroup>=0) NOT NULL PRIMARY KEY,
    backup_writer_hostgroup INT CHECK (backup_writer_hostgroup>=0 AND backup_writer_hostgroup<>writer_hostgroup) NOT NULL,
    reader_hostgroup INT NOT NULL CHECK (reader_hostgroup<>writer_hostgroup AND backup_writer_hostgroup<>reader_hostgroup AND reader_hostgroup>0),
    offline_hostgroup INT NOT NULL CHECK (offline_hostgroup<>writer_hostgroup AND offline_hostgroup<>reader_hostgroup AND backup_writer_hostgroup<>offline_hostgroup AND offline_hostgroup>=0),
    active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 1,
    max_writers INT NOT NULL CHECK (max_writers >= 0) DEFAULT 1,
    writer_is_also_reader INT CHECK (writer_is_also_reader IN (0,1,2)) NOT NULL DEFAULT 0,
    max_transactions_behind INT CHECK (max_transactions_behind>=0) NOT NULL DEFAULT 0,
    comment VARCHAR,
    UNIQUE (reader_hostgroup),
    UNIQUE (offline_hostgroup),
    UNIQUE (backup_writer_hostgroup))

这些字段含义以下:

  • write_hostgroup:默认状况下会将全部流量发送到这个组。具备read_only=0的节点也将分配到这个组;
  • backup_writer_hostgroup:若是集群有多个写节点(read_only=0)且超过了max_writers规定数量,则会把多出来的写节点放到备用写组里面;
  • reader_hostgroup:读取的流量应该发送到该组,只读节点(read_only=1)会被分配到该组;
  • offline_hostgroup:当ProxySQL监视到某个节点不正常时,会被放入该组;
  • active:是否启用主机组,当启用时,ProxySQL将监视主机在各族之间移动;
  • max_writers:最大写节点的数量,超过该值的节点应该被放入backup_write_hostgroup;
  • writer_is_also_reader:一个节点既作写节点也作读节点,若是该值为2,则backup_writer_hostgroup的节点作读写点,可是writer_hostgroup不会作读节点;

咱们对该表进行以下配置:

mysql> select * from mysql_group_replication_hostgroups;
+------------------+-------------------------+------------------+-------------------+--------+-------------+-----------------------+-------------------------+---------+
| writer_hostgroup | backup_writer_hostgroup | reader_hostgroup | offline_hostgroup | active | max_writers | writer_is_also_reader | max_transactions_behind | comment |
+------------------+-------------------------+------------------+-------------------+--------+-------------+-----------------------+-------------------------+---------+
| 1                | 2                       | 3                | 4                 | 1      | 1           | 0                     | 100                     | NULL    |
+------------------+-------------------------+------------------+-------------------+--------+-------------+-----------------------+-------------------------+---------+


(5.3)视图添加

若是ProxySQL是与组复制MGR一块儿使用的,那么还须要在MGR集群添加以下视图:

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 ;

而后受权给监控用户,这里须要特别注意,个人监控用户在5.5.1步才建立,所以这一步须要放到5.5.1后执行:

grant select on sys.* to monitoring_user;


(5.4)MySQL服务器添加

mysql_server表是用来存储ProxySQL路由转换的MySQL节点的信息。

mysql>  insert into mysql_servers (hostgroup_id, hostname, port) values(1,'192.168.10.11',3306);
mysql>  insert into mysql_servers (hostgroup_id, hostname, port) values(1,'192.168.10.12',3306);
mysql>  insert into mysql_servers (hostgroup_id, hostname, port) values(1,'192.168.10.13',3306);

mysql> 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.10.11 | 3306 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 192.168.10.12 | 3306 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 192.168.10.13 | 3306 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
+--------------+---------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+

而后执行下面的命令生效:

LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;


(5.5)监控配置及检查

这里配置监控信息,用来监控ProxySQL与后端的MySQL通讯是否正常

(5.5.1)监控用户配置

在ProxySQL的变量表里面设定监控用户密码,用于ProxySQL监控后端MySQL服务器的用户信息

mysql> UPDATE global_variables SET variable_value='monitor' WHERE variable_name='mysql-monitor_username';
Query OK, 1 row affected (0.00 sec)

mysql> UPDATE global_variables SET variable_value='monitor' WHERE variable_name='mysql-monitor_password';
Query OK, 1 row affected (0.00 sec)

mysql> select variable_name,variable_value from global_variables where variable_name in ('mysql-monitor_username','mysql-monitor_password');
+------------------------+----------------+
| variable_name          | variable_value |
+------------------------+----------------+
| mysql-monitor_password | monitor        |
| mysql-monitor_username | monitor        |
+------------------------+----------------+

须要注意,既然使用该用户监控后台MySQL数据库,那么后台MySQL数据库也须要建立该用户并受权,monitor用户须要有usage权限去链接、ping和检查read_only信息,若是要检测复制延迟,还须要具备replication client权限。特别注意,不能使用mysql_users里面的用户来作监控用户。

--  在MySQL服务器上建立监控用户
--  须要注意,这里MySQL使用的是MGR,因此只须要在一台节点建立用户便可,其它节点会自动同步用户信息

create user monitor@'%' identified by 'monitor';
grant usage,replication client on *.* to monitor@'%';
flush privileges;

注意:由于ProxySQL+组复制添加了新的视图,见”5.3 视图添加”,所以还需受权:

grant select on sys.* to monitor;


(5.5.2)配置监控间隔

这里把链接、ping、read_only监控间隔改成2s,也能够根据须要改为其它,也能够不作修改

mysql> update global_variables set variable_value='2000' 
    -> where variable_name in('mysql-monitor_connect_interval','mysql-monitor_ping_interval','mysql-monitor_read_only_interval'); Query OK, 3 rows affected (0.00 sec) mysql> select * from global_variables where variable_name like 'mysql-monitor%'; +--------------------------------------------------------------+----------------+
| variable_name                                                | variable_value |
+--------------------------------------------------------------+----------------+
| mysql-monitor_enabled                                        | true           |
| mysql-monitor_connect_timeout                                | 600            |
| mysql-monitor_ping_max_failures                              | 3              |
| mysql-monitor_ping_timeout                                   | 1000           |
| mysql-monitor_read_only_max_timeout_count                    | 3              |
| mysql-monitor_replication_lag_interval                       | 10000          |
| mysql-monitor_replication_lag_timeout                        | 1000           |
| mysql-monitor_groupreplication_healthcheck_interval          | 5000           |
| mysql-monitor_groupreplication_healthcheck_timeout           | 800            |
| mysql-monitor_groupreplication_healthcheck_max_timeout_count | 3              |
| mysql-monitor_groupreplication_max_transactions_behind_count | 3              |
| mysql-monitor_galera_healthcheck_interval                    | 5000           |
| mysql-monitor_galera_healthcheck_timeout                     | 800            |
| mysql-monitor_galera_healthcheck_max_timeout_count           | 3              |
| mysql-monitor_replication_lag_use_percona_heartbeat          |                |
| mysql-monitor_query_interval                                 | 60000          |
| mysql-monitor_query_timeout                                  | 100            |
| mysql-monitor_slave_lag_when_null                            | 60             |
| mysql-monitor_threads_min                                    | 8              |
| mysql-monitor_threads_max                                    | 128            |
| mysql-monitor_threads_queue_maxsize                          | 128            |
| mysql-monitor_wait_timeout                                   | true           |
| mysql-monitor_writer_is_also_reader                          | true           |
| mysql-monitor_username                                       | monitor        |
| mysql-monitor_password                                       | monitor        |
| mysql-monitor_history                                        | 600000         |
| mysql-monitor_connect_interval                               | 2000           |
| mysql-monitor_ping_interval                                  | 2000           |
| mysql-monitor_read_only_interval                             | 2000           |
| mysql-monitor_read_only_timeout                              | 500            |
+--------------------------------------------------------------+----------------+
30 rows in set (0.01 sec)

在修改完变量以后,必定要加载到内存中生效以及永久保存到磁盘中:

LOAD MYSQL VARIABLES TO RUNTIME;
SAVE MYSQL VARIABLES TO DISK;


(5.5.3)检查监控信息是否存在异常

监控配置完成后,咱们须要检查ProxySQL与后端MySQL通讯是否有异常,monitor数据库中的表用于存储监视信息,须要注意的是,这些表并不是都已经被使用。

mysql> show tables from monitor;
+--------------------------------------+
| tables                               |
+--------------------------------------+
| mysql_server_aws_aurora_check_status |
| mysql_server_aws_aurora_failovers    |
| mysql_server_aws_aurora_log          |
| mysql_server_connect_log             |
| mysql_server_galera_log              |
| mysql_server_group_replication_log   |
| mysql_server_ping_log                |
| mysql_server_read_only_log           |
| mysql_server_replication_lag_log     |
+--------------------------------------+


查看ProxySQL与后台服务器链接是否正常:

mysql> select * from monitor.mysql_server_connect_log order by time_start_us desc limit 10;
 +---------------+------+------------------+-------------------------+---------------+
 | hostname      | port | time_start_us    | connect_success_time_us | connect_error |
 +---------------+------+------------------+-------------------------+---------------+
 | 192.168.10.13 | 3306 | 1596263409501584 | 2191                    | NULL          |
 | 192.168.10.11 | 3306 | 1596263409480641 | 1911                    | NULL          |
 | 192.168.10.12 | 3306 | 1596263409459524 | 3671                    | NULL          |
 | 192.168.10.13 | 3306 | 1596263407504677 | 1451                    | NULL          |
 | 192.168.10.11 | 3306 | 1596263407481776 | 1398                    | NULL          |
 | 192.168.10.12 | 3306 | 1596263407458859 | 1378                    | NULL          |
 | 192.168.10.12 | 3306 | 1596263405490389 | 3480                    | NULL          |
 | 192.168.10.13 | 3306 | 1596263405474367 | 2804                    | NULL          |
 | 192.168.10.11 | 3306 | 1596263405458569 | 1612                    | NULL          |
 | 192.168.10.13 | 3306 | 1596263403497485 | 2132                    | NULL          |
 +---------------+------+------------------+-------------------------+---------------+
 10 rows in set (0.00 sec)


查看组复制是否正常,检查节点是否只读和交易滞后时间:

mysql> select * from mysql_server_group_replication_log order by time_start_us desc limit 10;
 +---------------+------+------------------+-----------------+------------------+-----------+---------------------+-------+
 | hostname      | port | time_start_us    | success_time_us | viable_candidate | read_only | transactions_behind | error |
 +---------------+------+------------------+-----------------+------------------+-----------+---------------------+-------+
 | 192.168.10.13 | 3306 | 1596263494597039 | 5671            | YES              | NO        | 0                   | NULL  |
 | 192.168.10.12 | 3306 | 1596263494596052 | 3231            | YES              | NO        | 0                   | NULL  |
 | 192.168.10.11 | 3306 | 1596263494595139 | 3245            | YES              | NO        | 0                   | NULL  |
 | 192.168.10.13 | 3306 | 1596263489596357 | 3027            | YES              | NO        | 0                   | NULL  |
 | 192.168.10.12 | 3306 | 1596263489595491 | 3306            | YES              | NO        | 0                   | NULL  |
 | 192.168.10.11 | 3306 | 1596263489594645 | 3110            | YES              | NO        | 0                   | NULL  |
 | 192.168.10.13 | 3306 | 1596263484595710 | 3680            | YES              | NO        | 0                   | NULL  |
 | 192.168.10.12 | 3306 | 1596263484594839 | 3618            | YES              | NO        | 0                   | NULL  |
 | 192.168.10.11 | 3306 | 1596263484594114 | 3214            | YES              | NO        | 0                   | NULL  |
 | 192.168.10.13 | 3306 | 1596263479595072 | 1887            | YES              | NO        | 0                   | NULL  |
 +---------------+------+------------------+-----------------+------------------+-----------+---------------------+-------+
 10 rows in set (0.01 sec)


查看ProxySQL ping后端MySQL服务器是否正常:

mysql> select * from mysql_server_ping_log order by time_start_us desc limit 10;
+---------------+------+------------------+----------------------+------------+
 | hostname      | port | time_start_us    | ping_success_time_us | ping_error |
 +---------------+------+------------------+----------------------+------------+
 | 192.168.10.12 | 3306 | 1596263541810631 | 496                  | NULL       |
 | 192.168.10.11 | 3306 | 1596263541786903 | 612                  | NULL       |
 | 192.168.10.13 | 3306 | 1596263541762973 | 749                  | NULL       |
 | 192.168.10.12 | 3306 | 1596263539796079 | 565                  | NULL       |
 | 192.168.10.13 | 3306 | 1596263539779040 | 403                  | NULL       |
 | 192.168.10.11 | 3306 | 1596263539762769 | 1141                 | NULL       |
 | 192.168.10.12 | 3306 | 1596263537797512 | 848                  | NULL       |
 | 192.168.10.11 | 3306 | 1596263537779520 | 845                  | NULL       |
 | 192.168.10.13 | 3306 | 1596263537761840 | 742                  | NULL       |
 | 192.168.10.12 | 3306 | 1596263535814945 | 843                  | NULL       |
 +---------------+------+------------------+----------------------+------------+
 10 rows in set (0.00 sec)

经过监控信息,咱们能够得出结论,全部配置都是健康的,继续下一步。


(5.6)用户配置

(5.6.1)ProxySQL的双层用户认证机制

若是使用了ProxySQL来作中间路由,那么与咱们平时登陆数据库有一些区别:平时咱们直接使用数据库的用户密码,便可访问到数据库,若是使用了ProxySQL,则要先使用帐号密码访问到ProxySQL的数据库,而后再由ProxySQL进行用户请求的转发,那么,ProxySQL中的用户与数据库层的用户有什么关联呢?很奇怪,这部分ProxySQL竟然没在文档里面给出来。

Snipaste_2020-08-01_18-00-42

只能本身测试了,通过我的测试,发现:当中间件用户与数据库用户以及密码一致时,才能正常访问数据库。测试结果以下:

MySQL数据库用户(mysql.user表) ProxySQL用户(main.mysql_users表) 使用ProxySQL的6033端口访问数据库
usera usera 正常访问
userb 没法登入proxysql
userc 能够登入proxysql,可是没法读写

这里是个人测试过程:

在MySQL数据库上建立用户:usera和userb

create user `usera`@`%` identified by '123456';
grant all privileges on *.* to `usera`@`%`;

create user `userb`@`%` identified by '123456';
grant all privileges on *.* to `userb`@`%`;

flush privileges;

在ProxySQL上建立用户:usera和userc

insert into mysql_users(username,password,default_hostgroup) values('usera','123456',1);
insert into mysql_users(username,password,default_hostgroup) values('userc','123456',1);
load mysql users to runtime;
save mysql users to disk;

登入测试(分为2步:先登入,再查询):
(1)usera用户登入无问题,查询无问题

[root@proxysql ~]# mysql -uusera -p123456 -P6033 -h192.168.10.10

mysql> select count(*) from lijiamandb.test03;
 +----------+
 | count(*) |
 +----------+
 |        1 |
 +----------+
1 row in set (0.01 sec)

(2)userb没法登入,提示用户名密码错误

[root@proxysql ~]# mysql -uuserb -p123456 -P6033 -h192.168.10.10
 mysql: [Warning] Using a password on the command line interface can be insecure.
 ERROR 1045 (28000): ProxySQL Error: Access denied for user 'userb'@'192.168.10.10' (using password: YES)

(3)userc能够正常登入,可是查询的时候提示密码不对

[root@proxysql ~]# mysql -uuserc -p123456 -P6033 -h192.168.10.10
mysql>
mysql> select count(*) from lijiamandb.test03;
ERROR 1045 (28000): Access denied for user 'userc'@'192.168.10.10' (using password: YES)

用户认证小结:只有ProxySQL中的用户名密码与MySQL中的用户名密码相同时,才能正常访问底层MySQL数据库。所以,若是要使用ProxySQL访问数据库,须要在MySQL和ProxySQL中都要建立相同的帐号,而且密码也要保持一致。


(5.6.2)ProxySQL用户建立

ProxySQL的用户保存在mysql_users表中,用户建立直接执行insert插入便可。如建立一个用户名为“lijiaman”,密码为“123456”,默认用户组为1的用户:

insert into mysql_users(username,password,default_hostgroup) values('lijiaman','123456',1);
须要特别注意,如今该用户只在Memory层进行了修改,没有同步到RUNTIME层生效,也没有保存到磁盘,须要使用下面的命令来完成操做。
load mysql users to runtime;
save mysql users to disk;


mysql_users表最重要的字段为:

  • username
  • password
  • default_hostgroup:默认组。若是此用户发送的查询没有匹配的规则,则它生成的流量将发送到指定的主机组
  • transaction_persistent:若是为与MySQL客户端链接到ProxySQL的用户设置了此选项,则在主机组内启动的事务将保留在该主机组内,而无论其余任何规则。例如,一个事务中存在读与写操做,若是不指定该选项,可能会把读与写请求分发到不一样的主机上,形成数据不一致。


(六)故障转移(failover)测试

在上一节,咱们已经配置了:

  • 组:写组、备用写组、读组、离线组。而且读组最多只有1台server;
  • MySQL Server:配置了3台Server,而且将其放入到了写组中;
  • 监控信息:
  • 用户信息

此时,ProxySQL已经具有故障转移的能力了,咱们进行测试一下。

STEP1:如今的配置以下,192.168.10.13主机是写节点,其它2个节点是备用写节点:

-- mysql_serve在memory层r的配置信息
mysql>  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.10.11 | 3306 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 192.168.10.12 | 3306 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 192.168.10.13 | 3306 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
+--------------+---------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
3 rows in set (0.00 sec)


--加载到RUNTIME后,因为组定义中最多只有1个写节点,其他的主节点移动到备用写组里面
mysql>  select * from runtime_mysql_servers;
+--------------+---------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| hostgroup_id | hostname      | port | gtid_port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+---------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| 2            | 192.168.10.11 | 3306 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 192.168.10.13 | 3306 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 192.168.10.12 | 3306 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
+--------------+---------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
3 rows in set (0.01 sec)

使用ProxySQL来访问MyQSL集群,发现能够支持读写

--  使用ProxySQL 6033端口访问MySQL数据库
[root@proxysql ~]# mysql -uusera -p123456 -P6033 -h192.168.10.10

mysql> use testdb

--  经过主机名,额能够看到,咱们访问到的是写节点
mysql> select @@hostname;
+------------+
| @@hostname |
+------------+
| mgr-node3  |
+------------+
1 row in set (0.00 sec)

-- 能够此次插入、查询数据
mysql> insert into test01 values(1,'a');
Query OK, 1 row affected (0.00 sec)

mysql> select * from test01;
+----+------+
| id | name |
+----+------+
|  1 | a    |
+----+------+
1 row in set (0.00 sec)


STEP2:关闭写节点

# 直接关闭主机
[root@mgr-node3 ~]# reboot

Connection closed by foreign host.
Disconnected from remote host(mgr-node3) at 19:00:31.
Type `help' to learn how to use Xshell prompt.
[c:\~]$ 


-- 须要注意的是,之前链接在主节点上的会话会断开,不会转移到新的主节点,很正常,Oracle也不会
 mysql> select * from test01;
 ERROR 2013 (HY000): Lost connection to MySQL server during query


STEP3:查看是否会有备用写节点转为写节点,能够看到192.168.10.12服务器已经转为写节点,而已经关闭的192.168.10.13服务器已经进入离线组。

mysql>  select * from runtime_mysql_servers;
+--------------+---------------+------+-----------+---------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| hostgroup_id | hostname      | port | gtid_port | status  | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+---------------+------+-----------+---------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| 2            | 192.168.10.11 | 3306 | 0         | ONLINE  | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 192.168.10.12 | 3306 | 0         | ONLINE  | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 4            | 192.168.10.13 | 3306 | 0         | SHUNNED | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
+--------------+---------------+------+-----------+---------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
3 rows in set (0.00 sec)


STEP4:再次使用ProxySQL来访问MyQSL集群,发现能够支持读写,业务不会因主节点的改变而受影响。

--  使用ProxySQL 6033端口访问MySQL数据库
[root@proxysql ~]#  mysql -uusera -p123456 -P6033 -h192.168.10.10

mysql>  use testdb

--  经过主机名,额能够看到,咱们访问到的是新的写节点
mysql> select @@hostname;
+------------+
| @@hostname |
+------------+
| mgr-node2  |
+------------+
1 row in set (0.00 sec)

-- 能够此次插入、查询数据
mysql> insert into test01 values(2,'b');
Query OK, 1 row affected (0.00 sec)

经过上面的测试,能够看到,MGR结合ProxySQL已经能够实现业务的自动故障转移。


接下来,咱们开始研究ProxySQL的读写分离功能。

相关文章
相关标签/搜索