g6AqUK.jpg

此文档用于记录基于docker搭建mysql集群的过程。这里不介绍docker的安装,如有需要请移步到电梯直达

环境: centos7.6 docker-ce19.03.12 percona/percona-xtradb-cluster:5.7.20

pxc介绍

PXC全称Percona XtraDB Cluster,它提供了MySQL高可用的一种实现方案。PXC集群是以节点组成,推荐奇数个节点(至少3个以上),集群中的每个节点都包含完整的数据,并且所有节点都是可读可写的。PXC集群方案能够保证数据的强一致性,事务在所有集群节点要么同时提交,要么同时不提交。

环境

主机ip 主服务 安装方式 主机系统
172.16.77.46 mysql docker-ce Centos7.6

搭建pxc集群

拉取PXC镜像

1
2
3
4
# 拉取镜像
$ docker pull percona/percona-xtradb-cluster:5.7.20
#修改镜像名称
$ docker tag percona/percona-xtradb-cluster:5.7.20 pxc

创建docker内部网络

1
2
3
4
5
6
# 创建内部网段
$ docker network create --subnet=172.18.0.0/24 net1
# 查看网段相关信息
$ docker network inspect net1
# 下面为删除网段
# $ docker network rm net1

创建docker卷

pxc运行在docker容器中,如果直接使用宿主机目录映射数据目录,会导致容器启动闪退。这里就需要使用docker卷来映射目录。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 创建数据卷
$ docker volume create v1
$ docker volume create v2
$ docker volume create v3
$ docker volume create v4
$ docker volume create v5
# 查看docker卷信息
$ docker volume inspect volume_name
# 下面命令为删除docker卷
# $ docker volume rm volume_name

创建pxc容器

注意:这里启动时,我将mysql的配置文件的目录映射到本地目录了,因为我们可能有修改配置文件的需要。经实际操作发现映射到本地时会清除容器内对应目录下的文件,需要提前单独起一个容器将该目录下的文件取出来放在宿主机的对应目录下即可。如果没有此需求,就将下面命令中的-v /home/mysql/conf.d:/etc/mysql/conf.d删除

1
2
3
4
5
6
7
8
$ docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=bnsbdlmysql -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=bnsbdlmysql -v v1:/var/lib/mysql -v /home/mysql/conf.d:/etc/mysql/conf.d  --privileged --name=node1 --net=net1 --ip 172.18.0.2 pxc
$ docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=bnsbdlmysql -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=bnsbdlmysql -e CLUSTER_JOIN=node1 -v v2:/var/lib/mysql -v /home/mysql/conf.d:/etc/mysql/conf.d  --privileged --name=node2 --net=net1 --ip 172.18.0.3 pxc
$ docker run -d -p 3308:3306 -e MYSQL_ROOT_PASSWORD=bnsbdlmysql -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=bnsbdlmysql -e CLUSTER_JOIN=node1 -v v3:/var/lib/mysql -v /home/mysql/conf.d:/etc/mysql/conf.d  --privileged --name=node3 --net=net1 --ip 172.18.0.4 pxc
$ docker run -d -p 3309:3306 -e MYSQL_ROOT_PASSWORD=bnsbdlmysql -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=bnsbdlmysql -e CLUSTER_JOIN=node1 -v v4:/var/lib/mysql -v /home/mysql/conf.d:/etc/mysql/conf.d  --privileged --name=node4 --net=net1 --ip 172.18.0.5 pxc
$ docker run -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=bnsbdlmysql -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=bnsbdlmysql -e CLUSTER_JOIN=node1 -v v5:/var/lib/mysql -v /home/mysql/conf.d:/etc/mysql/conf.d  --privileged --name=node5 --net=net1 --ip 172.18.0.6 pxc

# 查看正在运行的容器
$ docker ps

使用Navicat测试连接pxc集群节点

wDt92t.jpg

可以创建个数据库看看是否其他节点都有,测试成功后再进行以下配置。

负载均衡方案

负载均衡的必要性

  • 如果不使用数据库负载均衡,单节点处理所有请求,负载高,性能差

wDUSjP.jpg

  • 使用Haproxy做负载均衡,请求被均匀分发给每个节点,单节点负载低,性能好

wDUWb8.jpg

安装Haproxy

  • 创建编写配置文件
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
$ mkdir /home/haproxy
$ vim /home/haproxy/haproxy.cfg

global
    # 工作目录
    chroot /usr/local/etc/haproxy
    # 日志文件,使用rsyslog服务中local5日志设备(/var/log/local5),等级info
    log 127.0.0.1 local5 info
    # 守护进程运行
    daemon

defaults
    log global
    mode http
    # 日志格式
    option httplog
    # 日志中不记录负载均衡的心跳检测记录
    option dontlognull
    # 连接超时(毫秒)
    timeout connect 5000
    # 客户端超时(毫秒)
    timeout client 50000
    # 服务器超时(毫秒)
    timeout server 50000

# 监控界面
listen admin_stats
    # 监控界面的访问的IP和端口
    bind 0.0.0.0:8888
    # 访问协议
    mode http
    # URI相对地址
    stats uri /dbs
    # 统计报告格式
    stats realm Clobal\ statistics
    # 登录账户信息
    stats auth admin:123456
# 数据库负载均衡
listen proxy-mysql
    # 访问的IP和端口
    bind 0.0.0.0:3306
    # 网络协议
    mode tcp
    # 负载均衡算法(轮询算法)
    # 轮询算法:roundrobin
    # 权重算法:static-rr
    # 最少连接算法:leastconn
    # 请求源IP算法:source
    balance roundrobin
    # 日志格式
    option tcplog
    # 在MySQL中创建一个没有权限的haproxy用户,密码为空。Haproxy使用这个账户对MySQL数据库心跳检测
    option mysql-check user haproxy
    server MySQL_1 172.18.0.2:3306 check weight 1 maxconn 2000
    server MySQL_2 172.18.0.3:3306 check weight 1 maxconn 2000
    server MySQL_3 172.18.0.4:3306 check weight 1 maxconn 2000
    server MySQL_4 172.18.0.5:3306 check weight 1 maxconn 2000
    server MySQL_5 172.18.0.6:3306 check weight 1 maxconn 2000
    # 使用keepalive检测死链
    option tcpka
  • 创建haproxy容器
1
2
3
4
5
$ docker run -it -d -p 4001:8888 -p 4002:3306 -v /home/haproxy:/usr/local/etc/haproxy --name haproxy-1 --privileged --net=net1 --ip 172.18.0.7 haproxy

#进入容器后,加载配置文件
$ docker exec -it haproxy-1 /bin/bash
$ haproxy -f /usr/local/etc/haproxy/haproxy.cfg 
  • 在数据库创建一个haproxy的用户,不需要设置密码。Haproxy使用这个账号对mysql数据库心跳检测

wDfNYn.png

  • 登录haproxy网页端,http://172.16.77.46:4001/dbs

wDhCkj.png

wDhn74.png

  • 客户端连接haproxy-mysql数据库

wD4uKf.png

高可用负载均衡方案

单节点haproxy不具备高可用,需要有冗余设计

wDoxoD.png

虚拟IP技术

haproxy双机互备离不开一个关键的技术,这个技术是虚拟IP,linux可以在一个网卡内定义多个虚拟IP,得把这些IP地址定义到一个虚拟IP。

利用keepalived实现双机热备

定义出来一个虚拟IP,这个方案叫双机热备,准备2个keepalived,keepalived 就是为了抢占虚拟IP的,谁手快谁能抢到,没抢到的处于等待的状态。抢到的叫做主服务器,未抢到的叫做备服务器。两个keepalived之前有心跳检测的,当备用的检测到主服务挂了,就立马抢占虚拟IP。

wDTlyq.png

Haproxy双机热备方案

wD7mB6.jpg

安装keepalived

  • keepalived必须在haproxy所在的容器之内,也可以在docker仓库里面下载一个haproxy-keepalived的镜像。这里直接在容器内安装keepalived。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ docker exec -it haproxy-1 /bin/bash
$ apt-get update -y
$ apt-get install iputils-ping vim   net-tools procps -y
$ apt-get install keepalived -y

# 编写keeplived配置文件,路径为/etc/keepalived/keepalived.conf
$ vi /etc/keepalived/keepalived.conf
    # VI_1 名称可以自定义
vrrp_instance  VI_1 {
  #定义节点属性 Keepalived的身份(MASTER主服务,BACKUP备服务器)。主服务要抢占虚拟IP,备服务器不会抢占虚拟IP。
  state  MASTER
  #定义网卡设备 eth0是网卡名字,Docker虚拟机的网卡。可以在容器用 ip a查看
  interface  eth0
  #定义组vriid 虚拟路由标识,MASTER和BACKUP的虚拟路由标识必须一致。标识可以是0~255
  virtual_router_id  51
  #定义权重 MASTER权重 要 高于BACKUP,数据越大优先级越高
  priority  100
  #定义心跳检测时间1秒 MASTER与BACKUP节点间同步检查(心跳检测)的时间间隔,单位为秒。主备之间必须一致。
  advert_int  1
  #定义组用户密码 主从服务器验证方式。主备必须使用相同的密码才能正常通信。心跳检测登录Keepalived节点,开放账号密码。
  authentication {
      auth_type  PASS
      auth_pass  123456
  }
  #定义docker内ip地址,必须要在和haproxy同一个网段  两个keepalived同时抢一个虚拟ip  可以设置多个虚拟IP地址,每行一个
  virtual_ipaddress {
      172.18.0.201
  }
}
  • 启动keeplived,容器内启动
1
2
3
4
5
6
7
$ service keepalived start

# 宿主机ping这个ip
$ ping 172.18.0.201
PING 172.18.0.201 (172.18.0.201) 56(84) bytes of data.
64 bytes from 172.18.0.201: icmp_seq=1 ttl=64 time=0.044 ms
64 bytes from 172.18.0.201: icmp_seq=2 ttl=64 time=0.038 ms

创建haproxy2容器。并配置和haproxy相同的环境,这里不再过多赘述。

注意:每次如果某一个haproxy服务宕机,重启的时候需要重新进入paroxy容器加载配置文件 并且重启keepalived

宿主机安装配置keeplived

  • 安装keeplived
1
$ yum -y install keepalived$ mv /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak$ vi /etc/keepalived/keepalived.confvrrp_instance VI_1 {    state MASTER    interface eth0    virtual_router_id 51    priority 100    advert_int 1    authentication {        auth_type PASS        auth_pass 1111    }    virtual_ipaddress {       	172.16.77.47  #虚拟ip 需要和宿主机ip在同一网段    }}#接受监听数据来源的端口,网页入口使用virtual_server 172.16.77.47 8888 {    delay_loop 3    lb_algo rr    lb_kind NAT    persistence_timeout 50    protocol TCP#把接受到的数据转发给docker服务的网段及端口,由于是发给docker服务,所以和docker服务数据要一致    real_server 172.18.0.201 8888 {        weight 1    }}#接受数据库数据端口,宿主机数据库端口是3306,所以这里也要和宿主机数据接受端口一致virtual_server 172.16.77.47 3306 {    delay_loop 3    lb_algo rr    lb_kind NAT    persistence_timeout 50    protocol TCP#同理转发数据库给服务的端口和ip要求和docker服务中的数据一致    real_server 172.18.0.201 3306 {        weight 1    }}
  • 启动keeplived
1
 $ systemctl start keepalived $ systemctl enable keepalived
  • 访问haproxy页面,http://172.16.77.47:8888/dbs

wsfBm8.png

  • 连接mysql

wsfXX6.png

相关问题处理

mysql节点启动闪退

  • 现象:重启pxc节点发现节点容器无法启动
  • 解决办法
1
2
3
4
5
6
7
8
# 进入到容器挂载点的目录下,例如node1 这里取决于你的docker存储目录
$ cd  /home/docker/docker-data/volumes/v1/_data
$ vi grastate.dat
# GALERA saved state
version: 2.1
uuid:    dfc7776f-f628-11ea-907f-9f2f320bb959
seqno:   -1
safe_to_bootstrap: 0  #将这里的0改为1 然后保存再启动

参考链接

https://idig8.com/2019/02/01/shizhanpiankaiyuanxiangmudockerhuayunweibushu-dajianmysqljiqunsi/