一 软件版本
maxscale-2.2.21.centos.7.tar.gz
mariadb-10.4.14-linux-x86_64.tar.gz
CentOS Linux release 7.2.1511 (Core)
二 环境
Maxsclae:127.0.0.1 端口:4006
Master:127.0.0.1 端口:5510
Slave1:127.0.0.1 端口:5511
Slave2:127.0.0.1 端口:5512
三 安装过程
1)安装MaxScale
程序安装目录:mkdir -p /opt/software
#cd /opt/software
#wget https://dlm.mariadb.com/656923/MaxScale/2.2.21/centos/7/x86_64/maxscale-2.2.21.centos.7.tar.gz
#tar zxvf maxscale-2.2.21.centos.7.tar.gz -C .
# groupadd maxscale
# useradd -g maxscale maxscale
# ln -s /opt/software/maxscale-2.2.21.centos.7 /usr/local/maxscale
# mkdir -p /usr/local/maxscale/var/mysql/plugin
# chown -R maxscale.maxscale /usr/local/maxscale
2)创建密钥文件
# maxkeys /usr/local/maxscale/var/lib/maxscale/
密钥文件.secrets存放在/usr/local/maxscale/var/lib/maxscale/目录下
3)创建加密密码
# maxpasswd /usr/local/maxscale/var/lib/maxscale/ 123456
这里是对密码123456做加密,会生成如下加密字符串:
5CD3AF1688D20ECED2BECEF15C075BC6B02375FE27FFCAC3A12A5FFCBE4FB16C
这些加密后的字符串请保存好,之后要粘贴在maxscale.cnf配置文件里。
4)修改文件描述符65535
# vim /etc/security/limits.conf
* soft nofile 65535
* hard nofile 65535
# vim /etc/sysctl.conf
fs.file-max=65535
net.ipv4.ip_local_port_range = 1025 65000
net.ipv4.tcp_tw_reuse = 1
# 修改完毕后,reboot重启服务器生效
5)创建Maxscale监控账号和程序读写账号
CREATE USER 'monitor_user'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION CLIENT on *.* to 'monitor_user'@'%';
GRANT SUPER, RELOAD on *.* to 'monitor_user'@'%';
CREATE USER 'app_user'@'%' IDENTIFIED BY '123456';
GRANT all on *.* to 'app_user'@'%';
程序用户根据自己的实际情况授权,指定到库和具体权限。
6)配置MaxScale服务
# cat /usr/local/maxscale/etc/maxscale.cnf
[maxscale] #全局模板
threads=auto #根据服务器的CPU核数,自动设置CPU线程数
log_info=1 #打开日志
log_warning=1
log_notice=1
[server1] #主机模板
type=server
address=192.168.0.148
port=5510
protocol=MySQLBackend
[server2]
type=server
address=192.168.0.148
port=5511
protocol=MySQLBackend
serv_weight=1
#serversize=1
[server3]
type=server
address=192.168.0.148
port=5512
protocol=MySQLBackend
serv_weight=1
#serversize=1
[MySQL Monitor] #故障转移监控模板
type=monitor
module=mysqlmon #核心监控模块
servers=server1,server2,server3
user=monitor_user #监控使用的账号密码
password=123456
monitor_interval=2000 #每隔2秒探测一次
auto_failover=true #故障自动切换
auto_rejoin=true #自动重新加入
failcount=3 #一共检测3次
failover_timeout=90
switchover_timeout=90
verify_master_failure=true #防止抖动,maxscale连接主库有问题,会通过从库连接主库
master_failure_timeout=10
[Read-Write Service] #服务模板
type=service
router=readwritesplit #读写分离模块
servers=server1,server2,server3
user=app_user #读写分离的用户
password=5CD3AF1688D20ECED2BECEF15C075BC6B02375FE27FFCAC3A12A5FFCBE4FB16C
max_slave_connections=100%
weightby=serv_weight #指定权重,serv_weight在主机模版中配置了权重比
master_accept_reads=true #主库是否用于读
max_slave_replication_lag=60 #从库延迟超过60秒,把请求转发给master
max_slave_connections=2 #允许两个slave读取
max_connections=5000 #配置最大连接数
[MaxAdmin Service]
type=service
router=cli
[Read-Write Listener] #服务监听
type=listener
service=Read-Write Service
protocol=MySQLClient
port=4006
[MaxAdmin Listener]
type=listener
service=MaxAdmin Service
protocol=maxscaled
# socket=default
port=6603
配置详解:
maxscale.cnf配置文件分为全局模板、主机模板、故障转移监控模板、服务模板和服务监听模板,五大部分。
重要参数详解:
① 故障转移监控模板
[MariaDB-Monitor]
auto_failover=true
#打开自动故障转移,false为关闭,需要人工执行命令去做故障转移,通常为true。
auto_rejoin=true
#打开自动重新加入,false为关闭,需要人工执行CHANGE MASTER TO NEW_MASTER, MASTER_USE_GTID = current_pos命令,通常为true。
failcount=3
# 3次连接失败,认定主库down掉,开始启动故障转移,默认是5次尝试。
failover_timeout=90
# 假定slave库有延迟,在默认90秒时间内,没有同步完,自动关闭故障转移。通常默认值即可。
switchover_timeout=90
# 假定slave库有延迟,在默认90秒时间内,没有同步完,自动关闭在线切换。通常默认值即可。
verify_master_failure=true
# 当Maxscale连接不上master时,开启其他slave再次验证master是否故障。这样的好处是:防止网络抖动误切换(脑裂),造成数据不一致,其实现原理为:投票机制,当Maxscale无法连接MySQL主库,会试图从其他slave机器上去连接MySQL主库,只有双方都连接失败,才认定MySQL主库宕机。假如有一方可以连接MySQL主库,都不会切。
类似MHA的masterha_secondary_check命令二次检查,默认开启,无需关闭。
master_failure_timeout=10
# 这个参数依赖于verify_master_failure,当开启后,从库在默认10秒内无法连接master,认定主库down掉。通常默认值即可。
② 服务模板
这里我们要定义一个服务,路由选择读写分离模块。你可以分离一部分select读取操作到slave从库上。它是基于statement的,解析SQL语句。在这里前端程序不需要修改代码,通过MaxScale对SQL语句解析,把读写请求自动路由到后端数据库节点上,从而实现读写分离。开源Percona ProxySQL中间件也是基于statement方式实现读写分离。
[RW_Split_Router]
master_accept_reads=true
# 如果你担心数据有延迟,担心数据准确性问题,可以设置在主库上查询。默认读是不被路由到master,设置为true允许master用于读取。
max_slave_connections=2
# 允许两个slave进行读取
max_slave_replication_lag=1
# 定义超过延迟1秒,把请求转发给master
causal_reads=local
# 由于Maxscale通过参数monitor_interval=2000,每隔2秒探测一次,可能存在主从延迟检测不到的情况。
例如主库上写入了一条数据,从库还没来得写入该记录。那么可以通过设置causal_reads=local,此时客户端在从库上查询会hang住,直至等待causal_reads_timeout=10,默认10秒,超时后请求会强制转发给master。
③ 服务监听模板
我们在上面已经完成了服务定义,那么为了让客户端可以请求访问,我们需再定义一个tcp协议端口。
[RW_Split_Listener]
service=RW_Split_Router
# 这里的RW_Split_Router模块名,要对应服务模块的名字
port=4006
# 读写分离端口,应用连接这个端口,可以自定义端口。
7)启动服务
#/usr/local/maxscale/bin/maxscale --user=maxscale --basedir=/usr/local/maxscale/ --config=/usr/local/maxscale/etc/maxscale.cnf
日志信息会记到到/usr/local/maxscale/var/log/maxscale/maxscale.log
此时所有的slave机器都自动设置为只读模式,可通过select @@read_only查看。
8)查看Maxscale后台管理信息
我们可以通过maxctrl后台管理命令查看主从复制集群状态信息,命令如下:
# maxctrl list servers
查看我们刚才注册的服务,命令如下:
#maxctl list services
四 读写分离测试
控制读写比重的权重参数:serv_weight,weightby
官方文档对这两个参数的解释:
https://mariadb.com/kb/en/mariadb-maxscale-14/maxscale-configuration-usage-scenarios/
serv_weight和weightby 配合使用,看下边官方的例子:
server1 配置serv_weight=3 server2 配置 serv_weight=1 server1将分配3/4的连接数,server2 将获得1/4的连接数。
主库是server1,从库是 server2,server3
测试普通查询操作:
select * from t1; 被路由到从库server2上。
[root@localhost ~]# mysql -h192.168.0.148 -uapp_user -p123456 -P 4006 test
(app_user@192.168.0.148:)[test]> select * from t1;
+------+------+---------------------+
| id | name | changetime |
+------+------+---------------------+
| 1 | a | NULL |
| 2 | bb | 2020-09-11 08:39:24 |
| 3 | cc | NULL |
| 3 | cc | NULL |
| 3 | cc | NULL |
+------+------+---------------------+
5 rows in set (0.02 sec)
测试DML操作:
insert into t1 values (6,'dd','2020-09-17 00:00:00'); 被路由到主库server1上。
(app_user@192.168.0.148:)[test]> insert into t1 values (6,'dd','2020-09-17 00:00:00');
Query OK, 1 row affected (0.02 sec)
事物中的查询走主库:
(app_user@192.168.0.148:)[test]> begin;select * from t1;
Query OK, 0 rows affected (0.00 sec)
+------+------+---------------------+
| id | name | changetime |
+------+------+---------------------+
| 1 | a | NULL |
| 2 | bb | 2020-09-11 08:39:24 |
| 3 | cc | NULL |
| 3 | cc | NULL |
| 3 | cc | NULL |
| 6 | dd | 2020-09-17 00:00:00 |
+------+------+---------------------+
6 rows in set (0.01 sec)
HINT语法
样例:
[Read Service]
type=service
router=readconnroute
router_options=master
servers=server1
user=maxuser
passwd=maxpwd
filters=Hint
[Hint]
type=filter
module=hintfilter
---------------------------------------------
Comments and comment types
The client connection will need to have comments enabled. For example the mysql command line client has comments disabled by default.
For comment types, use either -- (notice the whitespace) or # after the semicolon or /* .. */ before the semicolon. All comment types work with routing hints.
The MySQL manual doesnt specify if comment blocks, i.e./ .. /`, should contain a w whitespace character before or after the tags, so adding whitespace at both the start and the end is advised.
比如:
SELECT * from table1; -- maxscale route to master --可以换成# 或者 /* */
Mysql client 命令行中测试 需要开启注解,否则测不出来,默认是关闭的。
日志:
五 故障切换场景模拟
场景一:故障切换
通过mysqladmin shutdown命令关闭主库。
故障切换细节:
1)选择最新的slave作为master,依照以下顺序标准排列:
gtid_IO_pos(中继日志中的最新事件)。
gtid_current_pos(处理最多的事件)。
log_slave_updates已开启。
磁盘空间不低。
如果以上条件都满足,按照maxscale.cnf主机模板的顺序进行故障转移,例如server2挂了,将切换到server3上,依次类推。
2)如果最新的slave具有未处理的中继日志,会根据参数failover_timeout=90等待90秒,超过90秒数据未同步完,则关闭故障转移。通过判断gtid_binlog_pos和gtid_current_pos值是否相等。
3)准备新的master
① 在最新的slave上,关闭复制进程执行命令:
SET STATEMENT max_statement_time=1 FOR STOP SLAVE;
并清空同步复制信息执行命令。
SET STATEMENT max_statement_time=1 FOR RESET SLAVE ALL;
② 在最新的slave上,关闭只读read_only 执行命令。
SET STATEMENT max_statement_time=1 FOR SET GLOBAL
read_only=0;
③ 在最新的slave上,启用EVENT事件(MySQL定时任务)。
④ 接收客户端读写请求。
4)重定向所有slave指向新的master进行同步复制
① 停止同步复制,执行命令
SET STATEMENT max_statement_time=1 FOR STOP SLAVE
② 指向新的master进行复制,执行命令
SET STATEMENT
max_statement_time=1 FOR CHANGE MASTER '' TO
MASTER_HOST = '127.0.0.1', MASTER_PORT = 5510,
MASTER_USE_GTID = current_pos, MASTER_USER = 'monitor_user',
MASTER_PASSWORD = '123456';
③ 开启同步复制,执行命令
SET STATEMENT max_statement_time=1 FOR START SLAVE
5)检查所有slave复制是否正常,执行命令SHOW ALL SLAVES STATUS判断Slave_IO_Running和Slave_SQL_Running值是否都为双Yes。
切换日志:
场景二:手动在线切换
maxctrl call command mariadbmon switchover mysql_monitor server1 server3
server3是主库,server1是从库,执行上边的命令后,server1变成新主库,server3变成从库。
切换后原主的read_only 会打开, 新主的read_only会关闭
切换细节:
1)在旧的master上,开启只读read_only 执行命令。
read_only=1 禁止数据写入。
2)终止SUPER权限超级用户的连接,通过以下命令找到超级用户连接Id:
SELECT DISTINCT * FROM (SELECT P.id,P.user FROM
information_schema.PROCESSLIST as P INNER JOIN mysql.user
as U ON (U.user = P.user) WHERE (U.Super_priv = 'Y' AND
P.COMMAND != 'Binlog Dump' AND P.id != (SELECT
CONNECTION_ID()))) as tmp;
然后执行KILL命令,因为read_only只读不影响SUPER权限超级用户更改数据。
3)执行FLUSH TABLES把所有表强制关闭。
4)执行FLUSH LOGS刷新二进制日志,以便所有binlog都刷到磁盘上。
5)在旧master上执行:SELECT @@gtid_current_pos, ,@@gtid_binlog_pos记录gtid事务号。
在新master上执行:SELECT MASTER_GTID_WAIT('GTID');如果执行结果都为0,表示已经完成数据同步,可以进行下一步切换,否则需要一直等待完成。
场景三:故障库恢复测试
当宕机的主库恢复后,会重新加入到主从环境中,作为从库。
#官方文档
https://mariadb.com/kb/en/mariadb-maxscale-22-automatic-failover-with-mariadb-monitor/
总结:
Maxscale可以部署多台挂在云服务SLB后面做负载均衡。
由于GTID实现方式不同,Maxscale暂不支持MySQL和Percona的故障转移切换,仅支持读写分离功能。
Mariadb版本:
Domain_id + server_id + seq
mysql官方版本:
使用server_uuid和transaction_id两个共同组成一个GTID。
即:GTID = server_uuid:transaction_id
server_uuid 是数据库启动自动生成的数据库实例唯一标识,保存在auto.cnf中;
而transaction_id 则是事务执行的序列号。