这是学习笔记的第 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  <all>

tkconsulserver2  192.168.56.4:8301  alive   server  1.2.1  2         company-b1  <all>

tkconsulserver3  192.168.56.5:8301  alive   server  1.2.1  2         company-b1  <all>

tkconsulclient4  192.168.56.6:8301  alive   client  1.2.1  2         company-b1  <default>

tkconsulclient5  192.168.56.7:8301  alive   client  1.2.1  2         company-b1  <default>

tkconsulclient6  192.168.56.8:8301  alive   client  1.2.1  2         company-b1  <default>

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": {

"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

"http": 8500,

"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,

对于客户端来说,需要的是一个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"

"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是一个子集,不包含自己,为了方便测试,我们把参数文件放到数据目录下面。

参数文件内容如下:

# server configuration

datadir=/data/mgr/s1

basedir=/usr/local/mysql_5.7.23

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-782bcb"

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

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 ]

echo "mysql $port is down....."

# 判断节点状态

node_state=`$comm -Nse "select MEMBER_STATE from performance_schema.replication_group_members where MEMBER_ID='$server_uuid'"`

if [ $node_state != "ONLINE" ]

echo "MySQL $port state is not online...."

# 判断是不是主节点

if [[ $server_uuid == $primary_member ]]

echo "MySQL $port  Instance is master ........"

echo "MySQL $port  Instance is slave ........"

Secondary节点的健康检查脚本如下:

[root@MySQL6 data]# cat  /data/consul/scripts/check_mgr_secondary.sh

#!/bin/bash

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 ]

echo "mysql $port is down....."

# 判断节点状态

node_state=`$comm -Nse "select MEMBER_STATE from performance_schema.replication_group_members where MEMBER_ID='$server_uuid'"`

if [ $node_state != "ONLINE" ]

echo "MySQL $port state is not online...."

# 判断是不是主节点

if [[ $server_uuid != $primary_member ]]

echo "MySQL $port  Instance is slave ........"

node_num=`$comm -Nse "select count(*) from  performance_schema.replication_group_members"`

# 判断如果没有任何从节点,主节点也注册从角色服务。

if [ $node_num -eq 1 ]

echo "MySQL $port  Instance is slave ........"

echo "MySQL $port  Instance is master ........"

这里的重点是需要配置文件,我们可以归类为两类,一类是读请求,是只能对接到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

--- 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 来对接的。

后续根据大家的反馈来不断的细化和完善。