MySQL MGR+ Consul之数据库高可用方案

时间:2023-08-18 18:57:50

背景说明: 
    基于目前存在很多MySQL数据库单点故障,传统的MHA,PXC等方案用VIP或者DNS切换的方式可以实现、基于数据库的数据强一致性考虑,采用MGR集群,采用consul服务注册发现实现应用端通过动态DNS 访问MGR集群,实现数据库高可用,自动化切换的方案 
MGR简介

MySQL Group Replication(MGR)是MySQL官方在5.7.17版本引进的一个数据库高可用与高扩展的解决方案,以插件形式提供,实现了分布式下数据的最终一致性,总结MGR特点如下: 
高一致性:基于分布式paxos协议实现组复制,保证数据一致性; 
高容错性:自动检测机制,只要不是大多数节点都宕机就可以继续工作,内置防脑裂保护机制; 
高扩展性:节点的增加与移除会自动更新组成员信息,新节点加入后,自动从其他节点同步增量数据,直到与其他节点数据一致; 
高灵活性:提供单主模式和多主模式,单主模式在主库宕机后能够自动选主,所有写入都在主节点进行,多主模式支持多节点写入。 
MGR原理说明: 
组复制是一种可用于实现容错系统的技术。 复制组是一个通过消息传递相互交互的 server 集群。通信层提供了原子消息(atomic message)和完全有序信息交互等保障机制 
实现了基于复制协议的多主更新 
复制组由多个 server成员构成,并且组中的每个 server 成员可以独立地执行事务。但所有读写(RW)事务只有在冲突检测成功后才会提交。只读(RO)事务不需要在冲突检测,可以立即提交。句话说,对于任何 RW 事务,提交操作并不是由始发 server 单向决定的,而是由组来决定是否提交。准确地说,在始发 server 上,当事务准备好提交时,该 server 会广播写入值(已改变的行)和对应的写入集(已更新的行的唯一标识符)。然后会为该事务建立一个全局的顺序。最终,这意味着所有 server 成员以相同的顺序接收同一组事务。因此,所有 server 成员以相同的顺序应用相同的更改,以确保组内一致。组复制是一种 share-nothing 复制方案,其中每个 server 成员都有自己的完整数据副本。

MGR的局限性: 
仅支持InnodDB存储引擎的表,并且每个表必须有主键ID, 用做wirte set的冲突检测 
必须启用GTID特性,binlog日志格式必须为row模式 
目前一个MGR集群最多支持9个节点 
不支持外健的save point特性,无法做全局间的约束检测和部分回滚 
二进制日志不支持binlog event checksum

consul简介 
微服务架构中非常重的一个模块,提供服务注册、服务发现等,常用的服务发现模块有,zookeeper、enreka、etcd、cunsul等。 
MySQL MGR+ Consul之数据库高可用方案
cousul是分布式、高可用、可横向发展的中间键,其特性如下: 
1、service discovery:通过dns或者http接口提供服务注册和发现 
2、health checking:自带健康检查,可提供服务故障时的转移 
3、key/value storage:可存储动态配置的系统,提供http接口, 
4、multi-datacenter:可以支持多数据中心

环境说明: 
192.168.202.177 consul server 目前只部署了一个server,可部署集群模式 
192.168.202.174 mysql server  node1、consul client 
192.168.202.175 mysql server  node2、consul client 
192.168.202.176 mysql server  node3、consul client 
系统版本:centos 7.5 
Mysql version:5.7.25 
consul version:1.4.4

MGR集群环境搭建 (单主模式)

MGR的搭建请参考https://www.cnblogs.com/EikiXu/p/10676652.html

搭建consul 使其mysql-primary和mysql-slave 注册到服务发现上

consul-server:192.168.202.177 
consul-client:192.168.202.174、192.168.202.175、192.168.202.176

在官网:https://www.consul.io/downloads.html下载对应的版本,解压后copy consul 到/usr/local/bin/下即可

分别在4台机器上安装然后运行 
mkdir -pv /etc/consul.d/  && mkdir -pv /data/consul/ 
mkdir -pv /data/consul/shell

在consul server 192.168.202.177上 编写配置文件

[root@consul-server consul]# cat /etc/consul.d/server.json
{
"data_dir": "/data/consul",
"datacenter": "dc1",
"log_level": "INFO",
"server": true,
"node_name": "Server",
"bootstrap_expect": 1,
"bind_addr": "192.168.202.177",
"client_addr": "192.168.202.177",
"ui":true
}

在consul client 192.168.202.174、192.168.202.175、192.168.202.176上编写配置文件,三台服务器的上bind_addr 修改为响应IP即可

[root@node1 consul]# cat /etc/consul.d/client.json
{
"data_dir": "/data/consul",
"enable_script_checks": true,
"bind_addr": "192.168.202.174",
"retry_join": ["192.168.202.177"],
"retry_interval": "30s",
"rejoin_after_leave": true,
"start_join": ["192.168.202.177"] ,
"node_name": "node1"
}

在consul client 192.168.202.174、192.168.202.175、192.168.202.176上编写检测primay 脚本 和检测slave 脚本

[root@node1 consul]# cat /data/consul/shell/check_mysql_mgr_master.sh
#!/bin/bash
port=3306
user="root"
passwod="iforgot"
comm="/usr/local/mysql/bin/mysql -u$user -hlocalhost -P $port -p$passwod"
value=`$comm -Nse "select 1"`
primary_member=`$comm -Nse "select variable_value from performance_schema.global_status WHERE VARIABLE_NAME= 'group_replication_primary_member'"`
server_uuid=`$comm -Nse "select variable_value from performance_schema.global_variables where VARIABLE_NAME='server_uuid';"`
# 判断MySQL是否存活
if [ -z $value ]
then
echo "mysql $port is down....."
exit 2
fi
# 判断节点状态,是否存活
node_state=`$comm -Nse "select MEMBER_STATE from performance_schema.replication_group_members where MEMBER_ID='$server_uuid'"`
if [ $node_state != "ONLINE" ]
then
echo "MySQL $port state is not online...."
exit 2
fi
# 判断是不是主节点
if [[ $server_uuid == $primary_member ]]
then
echo "MySQL $port Instance is master ........"
exit 0
else
echo "MySQL $port Instance is slave ........"
exit 2
fi
[root@node1 consul]# cat /data/consul/shell/check_mysql_mgr_slave.sh
#!/bin/bash
port=3306
user="root"
passwod="iforgot"
comm="/usr/local/mysql/bin/mysql -u$user -hlocalhost -P $port -p$passwod"
value=`$comm -Nse "select 1"`
primary_member=`$comm -Nse "select variable_value from performance_schema.global_status WHERE VARIABLE_NAME= 'group_replication_primary_member'"`
server_uuid=`$comm -Nse "select variable_value from performance_schema.global_variables where VARIABLE_NAME='server_uuid';"`
# 判断mysql是否存活
if [ -z $value ]
then
echo "mysql $port is down....."
exit 2
fi
# 判断节点状态
node_state=`$comm -Nse "select MEMBER_STATE from performance_schema.replication_group_members where MEMBER_ID='$server_uuid'"`
if [ $node_state != "ONLINE" ]
then
echo "MySQL $port state is not online...."
exit 2
fi
# 判断是不是主节点
if [[ $server_uuid != $primary_member ]]
then
echo "MySQL $port Instance is slave ........"
exit 0
else
node_num=`$comm -Nse "select count(*) from performance_schema.replication_group_members"`
# 判断如果没有任何从节点,主节点也注册从角色服务。
if [ $node_num -eq 1 ]
then
echo "MySQL $port Instance is slave ........"
exit 0
else
echo "MySQL $port Instance is master ........"
exit 2
fi
fi

启动consul server 在192.168.202.177上 
nohup consul agent -config-dir=/etc/consul.d > /data/consul/consul.log &

启动consul client 在192.168.202.174、192.168.202.175、192.168.202.176
nohup consul agent -config-dir=/etc/consul.d > /data/consul/consul.log &

观察consul server的log日志3个client自动注册到了consul上了

查看consul成员

[root@consul-server consul]# consul members -http-addr='192.168.202.177:8500'
Node Address Status Type Build Protocol DC Segment
Server 192.168.202.177:8301 alive server 1.4.4 2 dc1 <all>
node1 192.168.202.174:8301 alive client 1.4.4 2 dc1 <default>
node2 192.168.202.175:8301 alive client 1.4.4 2 dc1 <default>
node3 192.168.202.176:8301 alive client 1.4.4 2 dc1 <default>

访问consulserver的web页面 http://192.168.202.177:8500/ui/

MySQL MGR+ Consul之数据库高可用方案

到此为止consul 集群已经搭建成功了

下面我们继续为实现mysql的高可用集群

MGR+Consul高可用实现

检测MGR集群状态 
MySQL MGR+ Consul之数据库高可用方案
查看那个是主节点

MySQL MGR+ Consul之数据库高可用方案

基于不同consul版本配置可能不太一样,三台机器都需要相应的json脚本检测mysql是否为主或从,配置文件修改相应的IP即可使用

查看consul server ui界面即可看到三台mysql的mgr集群已经注册到consul服务上了

MySQL MGR+ Consul之数据库高可用方案

注意:由于每台mysql server 上都有master、slave 检测脚本、而mysql server 只能是master 或者slave、所以存在失败的检测,master检测只有一个成功,slave检测只有一个失败

consul dns配置 
查看dns信息

MySQL MGR+ Consul之数据库高可用方案

App端配置域名服务器IP来解析consul后缀的域名,DNS解析及跳转, 有三个方案:


1. 原内网dns服务器,做域名转发,consul后缀的,都转到consul server上,目前采用的这种方式 
2. dns全部跳到consul DNS服务器上,非consul后缀的,使用 recursors 属性跳转到原DNS服务器上


3. dnsmaq 转: server=/consul/10.16.X.X#8600 解析consul后缀的 
我们内网dns是用的bind,对于bind的如何做域名转发consul官网也有栗子:https://www.consul.io/docs/guides/forwarding.html

构建bind域名解析:

yum install bind -y
配置name服务做解析:
[root@consul-server consul]# cat /etc/named.conf
//
// named.conf
//
// Provided by Red Hat bind package to configure the ISC BIND named(8) DNS
// server as a caching only nameserver (as a localhost DNS resolver only).
//
// See /usr/share/doc/bind*/sample/ for example named configuration files.
//
// See the BIND Administrator's Reference Manual (ARM) for details about the
// configuration located in /usr/share/doc/bind-{version}/Bv9ARM.html options {
listen-on port 53 { 192.168.202.177; };
listen-on-v6 port 53 { ::1; };
directory "/var/named";
dump-file "/var/named/data/cache_dump.db";
statistics-file "/var/named/data/named_stats.txt";
memstatistics-file "/var/named/data/named_mem_stats.txt";
recursing-file "/var/named/data/named.recursing";
secroots-file "/var/named/data/named.secroots";
allow-query { any; }; /*
- If you are building an AUTHORITATIVE DNS server, do NOT enable recursion.
- If you are building a RECURSIVE (caching) DNS server, you need to enable
recursion.
- If your recursive DNS server has a public IP address, you MUST enable access
control to limit queries to your legitimate users. Failing to do so will
cause your server to become part of large scale DNS amplification
attacks. Implementing BCP38 within your network would greatly
reduce such attack surface
*/
recursion yes; dnssec-enable no;
dnssec-validation no; /* Path to ISC DLV key */
bindkeys-file "/etc/named.iscdlv.key"; managed-keys-directory "/var/named/dynamic"; pid-file "/run/named/named.pid";
session-keyfile "/run/named/session.key";
}; logging {
channel default_debug {
file "data/named.run";
severity dynamic;
};
}; zone "." IN {
type hint;
file "named.ca";
}; include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";
include "/etc/named/consul.conf";
[root@consul-server consul]# cat /etc/named/consul.conf
zone "consul" IN {
type forward;
forward only;
forwarders { 192.168.202.177 port 8600; };
};
[root@consul-server consul]# cat /etc/resolv.conf
# Generated by NetworkManager
search localdomain
nameserver 192.168.202.177 [root@consul-server consul]# systemctl start named
[root@consul-server consul]# systemctl enable named

  


参考来源:

http://blog.itpub.net/29987453/viewspace-2637608/

https://blog.51cto.com/xiaoluoge/2134126

https://blog.csdn.net/miouqi/article/details/76422700

http://www.imooc.com/article/274897

http://www.cnblogs.com/gomysql/p/8010552.html