这是学习笔记的第 1770篇文章
今天来简单理一下MGR和consul的组合方案,前期的准备和步骤还是比较多的,晚上完成了基础的调试,来来回回切换了好多次,还算有点意思。
首先要部署的就是consul服务,consul服务其实可以分为 consul server和consul agent, consul server的部署是分布式架构,所以最少需要3台服务器,而对于consul agent基于agent模式,部署起来也很便捷。
所以如果要完整的模拟一套consul+MGR的完整环境,我们可能需要配置如下的服务器:
6台服务器,其中3台作为consul server,另外3台作为MySQL服务器,单主模式,三个数据库实例节点的方式。其中consul server的3台服务器不是MGR集群独有,可以对接更多的业务,所以属于全局的需求,不是为了MGR特意定制。
第一阶段 consul服务部署
使用consul的方式查看集群的信息如下,可以看到是3个consul server,3台作为MGR节点。
[root@MySQL6 data]# consul members
Node Address Status Type Build Protocol DC Segment
tkconsulserver1 192.168.56.3:8301 alive server 1.2.1 2 company-b1
tkconsulserver2 192.168.56.4:8301 alive server 1.2.1 2 company-b1
tkconsulserver3 192.168.56.5:8301 alive server 1.2.1 2 company-b1
tkconsulclient4 192.168.56.6:8301 alive client 1.2.1 2 company-b1
tkconsulclient5 192.168.56.7:8301 alive client 1.2.1 2 company-b1
tkconsulclient6 192.168.56.8:8301 alive client 1.2.1 2 company-b1
consul server是这三台服务器:
192.168.56.3
192.168.56.4
192.168.56.5
主要的server的配置就需要一个server.json,这里有一个重要概念就是domain,这里是tk,也就是我们所属的一个域,通过域的方式来提供访问。
对于每台机器来说,advertise_addr是根据每台的实际IP来的,这里是192.168.56.3的服务器的配置,56.4,56.5的配置就可以按照类似的方式来做。
[root@MySQL3 consul]# cat server.json
{
"addresses": {
"http": "0.0.0.0",
"dns": "0.0.0.0"
},
"bind_addr": "0.0.0.0",
"advertise_addr": "192.168.56.3",
"bootstrap_expect": 3,
"datacenter": "company-b1",
"data_dir": "/data/consul",
"dns_config": {
"allow_stale": true,
"max_stale": "87600h",
"node_ttl": "0s",
"service_ttl": {
"*": "0s"
}
},
"domain": "tk",
"enable_syslog": false,
"leave_on_terminate": false,
"log_level": "info",
"node_name": "tkconsulserver1",
"node_meta": {
"location": "B1 in test"
},
"performance": {
"raft_multiplier": 1
},
"ports": {
"http": 8500,
"dns": 53
},
"reconnect_timeout": "72h",
"recursors": [
"192.168.56.4",
"192.168.56.5"
],
"retry_join": [
"192.168.56.4",
"192.168.56.5"
],
"retry_interval": "10s",
"server": true,
"skip_leave_on_interrupt": true,
"ui": true
}
对于客户端来说,需要的是一个client.json,这里就需要配置所有的consul server
[root@MySQL8 consul]# cat client.json
{
"addresses": {
"http": "0.0.0.0",
"dns": "0.0.0.0"
},
"bind_addr": "0.0.0.0",
"advertise_addr": "192.168.56.8",
"datacenter": "company-b1",
"data_dir": "/data/consul",
"enable_script_checks": true,
"enable_syslog": false,
"leave_on_terminate": true,
"log_level": "info",
"node_name": "tkconsulclient6",
"node_meta": {
"location": "B1 in test"
},
"ports": {
"dns": 8600,
"http": 8500
},
"rejoin_after_leave": true,
"retry_join": [
"192.168.56.3",
"192.168.56.4",
"192.168.56.5"
],
"retry_interval": "10s",
"skip_leave_on_interrupt": false
}
值得一提的是,客户端怎么去识别consul server发布的服务呢,这个是consul支持的域名服务来解决的,所以对于客户端来说,我们需要配置一下域名设置,把它们都指向consul server集群即可。
[root@MySQL6 data]# cat /etc/resolv.conf
; generated by /sbin/dhclient-script
nameserver 192.168.56.3
nameserver 192.168.56.4
nameserver 192.168.56.5
有了这种方式,我们就不用配置/etc/hosts来做本地域名解析了。
consul服务可以使用如下的命令来重启,或者可以使用supervisor来做。
/etc/init.d/consul_agent restart
第二阶段 MySQL集群MGR服务部署
部署MGR的部分完全可以做到自动化部署来快捷实现,如果本地要测试MGR,可以参考我之前写的一个开源脚本。
我们来简单说明下手工在多台服务器上部署的细节。
我们预期的架构是三个节点,单主模式
192.168.56.7 Primary 端口:24801 内部端口:24901
192.168.56.6 Secondary 端口:24801 内部端口:24901
192.168.56.8 Secondary 端口:24801 内部端口:24901
MGR的版本相对来说是越新越好,我们选择的是MySQL 5.7.23
安装的数据目录在/data/mgr/s1下面。
使用如下的方式来初始化:
/usr/local/mysql_5.7.23/bin/mysqld --no-defaults --basedir=/usr/local/mysql_5.7.23 --datadir=/data/mgr/s1 --explicit_defaults_for_timestamp --initialize-insecure
然后配置参数文件,这是一个模板,里面需要注意的就是loose-group_replication_local_address是本地的IP,loose-group_replication_group_seeds是一个子集,不包含自己,为了方便测试,我们把参数文件放到数据目录下面。
参数文件内容如下:
[mysqld]
# server configuration
datadir=/data/mgr/s1
basedir=/usr/local/mysql_5.7.23
port=24801
socket=/data/mgr/s1/s1.sock
server_id=24803
gtid_mode=ON
enforce_gtid_consistency=ON
master_info_repository=TABLE
relay_log_info_repository=TABLE
binlog_checksum=NONE
log_slave_updates=ON
log_bin=binlog
binlog_format=ROW
transaction_write_set_extraction=XXHASH64
loose-group_replication_group_name="1bb1b861-f776-11e6-be42-782bcb377193"
loose-group_replication_start_on_boot=off
loose-group_replication_local_address= "192.168.56.8:24901"
loose-group_replication_group_seeds= "192.168.56.6:24901,192.168.56.7:24901"
loose-group_replication_bootstrap_group= off
我们需要配置数据目录的属主是mysql.mysql
chown -R mysql.mysql /data/mgr/s1
然后使用如下的方式来启动MySQL服务。
/usr/local/mysql_5.7.23/bin/mysqld_safe --defaults-file=/data/mgr/s1/s1.cnf &
节点1创建复制用户:
create user rpl_user@'%';
grant replication slave on *.* to rpl_user@'%' identified by 'rpl_pass';
三个节点都执行如下的步骤,安装复制插件,配置复制关系。
INSTALL PLUGIN group_replication SONAME 'group_replication.so';
show plugins;
change master to master_user='rpl_user',master_password='rpl_pass' for channel 'group_replication_recovery';
节点1开启group replication的步骤如下:
SET GLOBAL group_replication_bootstrap_group = ON;
START GROUP_REPLICATION;
SELECT * FROM performance_schema.replication_group_members;
节点2和节点3的操作如下:
set global group_replication_allow_local_disjoint_gtids_join=ON;
START GROUP_REPLICATION;
按照这种方式启动集群基本上还是比较顺畅的。
在这个基础上,我们队集群做一些验证测试。
第三阶段 MySQL集群MGR和consul结合
MGR集群在可用的前提下,接入consul实现平滑的切换是本次测试的重中之重。根据consul的机制,我们需要提供相应的健康检查脚本。
参考了网上的一些脚本,自己稍作改进:
Primary节点的健康检查脚本如下,角色完全可以基于MGR自己的数据字典来完成。
[root@MySQL6 data]# cat /data/consul/scripts/check_mgr_primary.sh
#!/bin/bash
port=$1
user="root"
comm="/usr/local/mysql_5.7.23/bin/mysql -u$user -h 127.0.0.1 -P $port "
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';"`
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
Secondary节点的健康检查脚本如下:
[root@MySQL6 data]# cat /data/consul/scripts/check_mgr_secondary.sh
#!/bin/bash
port=$1
user="root"
comm="/usr/local/mysql_5.7.23/bin/mysql -u$user -h 127.0.0.1 -P $port "
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
这里的重点是需要配置文件,我们可以归类为两类,一类是读请求,是只能对接到Primary节点,还有两个读节点,可以通过consul域名的方式实现负载均衡。所以我们根据这个需求可以定制两个json模板。
写节点的json配置
[root@MySQL8 consul]# cat
{
"services": [
{
"id": "mysql_mgr_w",
"name": "test24801-mysql_w",
"address": "",
"port": 24801,
"enable_tag_override": false,
"checks": [
{
"id": "mysql_mgr_w-check-01",
"name": "MySQL Write Check",
"args": ["/data/consul/scripts/check_mgr_primary.sh","24801"],
"interval": "15s",
"timeout": "1s",
"service_id": "mysql_mgr_w"
}
]
}
]
}
读节点的json配置:
[root@MySQL8 consul]# cat test_mgr_read.db.json
{
"services": [
{
"id": "mysql_mgr_r",
"name": "test24801-mysql_r",
"address": "",
"port": 24801,
"enable_tag_override": false,
"checks": [
{
"id": "mysql_mgr_r-check-02",
"name": "MySQL Write Check",
"args": ["/data/consul/scripts/check_mgr_secondary.sh","24801"],
"interval": "15s",
"timeout": "1s",
"service_id": "mysql_mgr_r"
}
]
}
]
}
使用如下的域名方式可以解析得到写节点的IP:
ping test24801-mysql_w.service.tk
PING test24801-mysql_w.service.tk (192.168.56.7) 56(84) bytes of data.
64 bytes from MySQL7 (192.168.56.7): icmp_seq=1 ttl=64 time=0.299 ms
64 bytes from MySQL7 (192.168.56.7): icmp_seq=2 ttl=64 time=0.340 ms
而对于读节点来说,可以通过负载均衡来对接两个读节点
我们可以使用这种方式来解析对应的DNS
[root@MySQL8 consul]# ping test24801-mysql_r.service.tk
PING test24801-mysql_r.service.tk (192.168.56.6) 56(84) bytes of data.
64 bytes from MySQL6 (192.168.56.6): icmp_seq=1 ttl=64 time=0.281 ms
^C
--- test24801-mysql_r.service.tk ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 862ms
rtt min/avg/max/mdev = 0.281/0.281/0.281/0.000 ms
.....
[root@MySQL8 consul]# ping test24801-mysql_r.service.tk
PING test24801-mysql_r.service.tk (192.168.56.8) 56(84) bytes of data.
64 bytes from MySQL8 (192.168.56.8): icmp_seq=1 ttl=64 time=0.008 ms
64 bytes from MySQL8 (192.168.56.8): icmp_seq=2 ttl=64 time=0.029 ms
到了这个阶段开始,基本的任务就完成了。可以kill掉56.7节点上的MySQL实例进程,然后集群会依次切换,会有56.8的节点来接管,作为新的Primary。consul服务会在这个过程中完成服务的注销和自动发现,这也就是配置脚本test_mgr_read.db.json 和 test_mgr_write.db.json 来对接的。
后续根据大家的反馈来不断的细化和完善。