MySql集群部署

## 常见MySQL集群方案

?        mysql 集群方案介绍,建议使用pxc,因为弱一致性会有问题,比如说a节点数据库显示我购买成功,b 节点数据库显示没有成功,这就麻烦了,pxc 方案是在全部节点都写入成功之后才会告诉你成功,是可读可写双向同步的,但是replication是单向的,不同节点的数据库之间都会开放端口进行通讯,如果从防火墙的这个端口关闭,pxc就不会同步成功,也不会返给你成功了。

<img src=".\Replication和PXC对比.png" style="zoom: 50%;margin-left: 0" />

**Replication**

- 速度快,但仅能保证弱一致性,适用于保存价值不高的数据,比如日志、帖子、新闻等。

- 采用master-slave结构,在master写入会同步到slave,能从slave读出;但在slave写入无法同步到master。

- 采用异步复制,master写入成功就向客户端返回成功,但是同步slave可能失败,会造成无法从slave读出的结果。

<img src=".\Replication.png" style="zoom: 50%;margin-left: 0" />

**PXC (Percona XtraDB Cluster)**

- 速度慢,但能保证强一致性,适用于保存价值较高的数据,比如订单、客户、支付等。
- 数据同步是双向的,在任一节点写入数据,都会同步到其他所有节点,在任何节点上都能同时读写。
- 采用同步复制,向任一节点写入数据,只有所有节点都同步成功后,才会向客户端返回成功。事务在所有节点要么同时提交,要么不提交。

<img src=".\RXC.png" style="zoom:50%;margin-left: 0" />

**建议PXC使用PerconaServer (MySQL改进版,性能提升很大)**

**PXC的数据强一致性**

- 同步复制,事务在所有集群节点要么同时提交,要么不提交
- Replication采用异步复制,无法保证数据的一致性

<img src=".\PXC的数据强一致性1.png" style="zoom:50%;margin-left: 0" /><img src=".\PXC的数据强一致性2.png" style="zoom:50%;" />

## PXC集群安装

在Docker中安装PXC集群,使用Docker仓库中的PXC官方镜像:https://hub.docker.com/r/percona/percona-xtradb-cluster

1. **准备镜像**
   
   
    ```bash
    docker pull percona/percona-xtradb-cluster:5.7.21
    docker tag percona/percona-xtradb-cluster:5.7.21 pxc
    docker rmi docker.io/percona/percona-xtradb-cluster:5.7.21
    ```

2. **准备docker网络**

   ```bash
   # 创建网段
   docker network create --subnet=172.91.0.0/24 mysql-network
   # 查看网段
   docker network inspect mysql-network
   # 删除网段
   docker network rm mysql-network
   ```

3. **创建数据卷**

   ```
   # 创建数据卷
   docker volume create v1
   docker volume create v2
   docker volume create v3
   docker volume create v4
   docker volume create v5
   # 查看数据卷
   docker inspect v1
   # 删除数据卷
   docker volume rm v1
   ```
   
4. **启动容器**
    ```bash
    # 创建5个PXC容器构成集群
    # 第一个节点
    docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=baowuglyk32 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=baowuglyk32 -v v1:/var/lib/mysql --name=mysqlnode1 --network=mysql-network --ip 172.91.0.2 pxc
    
    # 等一会等主节点启动完成之后在启动下面的
    # 等一会等主节点启动完成之后在启动下面的
    # 等一会等主节点启动完成之后在启动下面的
    
    # 第二个节点
    docker run -d -p 3308:3306 -e MYSQL_ROOT_PASSWORD=baowuglyk32 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=baowuglyk32 -e CLUSTER_JOIN=mysqlnode1 -v v2:/var/lib/mysql --name=mysqlnode2 --net=mysql-network --ip 172.91.0.3 pxc
    # 第三个节点
    docker run -d -p 3309:3306 -e MYSQL_ROOT_PASSWORD=baowuglyk32 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=baowuglyk32 -e CLUSTER_JOIN=mysqlnode1 -v v3:/var/lib/mysql --name=mysqlnode3 --net=mysql-network --ip 172.91.0.4 pxc
    # 第四个节点
    docker run -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=baowuglyk32 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=baowuglyk32 -e CLUSTER_JOIN=mysqlnode1 -v v4:/var/lib/mysql --name=mysqlnode4 --net=mysql-network --ip 172.91.0.5 pxc
    # 第五个节点
    docker run -d -p 3311:3306 -e MYSQL_ROOT_PASSWORD=baowuglyk32 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=baowuglyk32 -e CLUSTER_JOIN=mysqlnode1 -v v5:/var/lib/mysql --name=mysqlnode5 --net=mysql-network --ip 172.91.0.6 pxc
    ```

## Haproxy负载

1. **拉取镜像**

   ```bash
   docker pull haproxy:2.1.7
   ```

2. 创建Haproxy配置文件

   ```bash
   mkdir -p /home/haproxy
   tee /home/haproxy/haproxy.cfg <<-EOF
   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     Global\ 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.91.0.2:3306 check weight 1 maxconn 2000  
       server  MySQL_2 172.91.0.3:3306 check weight 1 maxconn 2000  
       server  MySQL_3 172.91.0.4:3306 check weight 1 maxconn 2000 
       server  MySQL_4 172.91.0.5:3306 check weight 1 maxconn 2000
       server  MySQL_5 172.91.0.6:3306 check weight 1 maxconn 2000
       #使用keepalive检测死链
       option  tcpka  
   EOF
   ```

3. **在数据库集群中创建空密码、无权限用户haproxy,来供Haproxy对MySQL数据库进行心跳检测**

   ```bash
   docker exec -it mysqlnode1 mysql -u root -pbaowuglyk32
   create user haproxy@% identified by ‘‘;
   ```

4. **创建Haproxy容器**

   ```bash
   docker run -it -d -p 4001:8888 -p 4002:3306 --restart=always -v /home/haproxy:/usr/local/etc/haproxy --name haproxy1 --net=mysql-network --ip 172.91.0.7 --privileged haproxy:2.1.7
   
   docker exec -it haproxy1 bash
   haproxy -f /usr/local/etc/haproxy/haproxy.cfg
   ```

## Нaproxy双机热备

### 热备原理

?        关键就是虚拟ip,定义一个虚拟ip,然后比如两个haproxy分别安装keepalive镜像,keepalive是作用是抢占虚拟ip,抢到的就是主服务器,没有抢到的就是备用服务器,然后两个keepalive进行心跳检测,如果挂掉抢占ip。而我们的程序就去访问这个虚拟IP就行了。

**总结**

- 定义虚拟IP
- 在Docker中启动两个Haproxy容器,每个容器中还需要安装Keepalived程序(以下简称KA)
- 两个KA会争抢虚拟IP,一个抢到后,另一个没抢到就会等待,抢到的作为主服务器,没抢到的作为备用服务器
- 两个KA之间会进行心跳检测,如果备用服务器没有受到主服务器的心跳响应,说明主服务器发生故障,那么备用服务器就可以争抢虚拟IP,继续工作
- 我们向虚拟IP发送数据库请求,一个Haproxy挂掉,可以有另一个接替工作

<img src=".\双机热备.png" style="zoom:50%;margin-left: 0" />

### 安装Keepalived

1. **进入Haproxy容器,安装Keepalived**

   ```
   docker exec -it haproxy1 bash
   apt-get update
   apt-get install keepalived
   
   vi ./keepalived.conf
   docker cp ./keepalived.conf haproxy1:/etc/keepalived
   ```

2. **Keepalived配置文件**

   ```bash
   vrrp_instance  VI_1 {
       state  MASTER  # Keepalived的身份(MASTER主服务要抢占IP,BACKUP备服务器不会抢占IP)。
       interface  br-979f81083d09    # docker网卡设备,虚拟IP所在
       virtual_router_id  51  # 虚拟路由标识,MASTER和BACKUP的虚拟路由标识必须一致。从0~255
       priority  100  # MASTER权重要高于BACKUP数字越大优先级越高
       advert_int  1  # MASTER和BACKUP节点同步检查的时间间隔,单位为秒,主备之间必须一致
       authentication {  # 主从服务器验证方式。主备必须使用相同的密码才能正常通信
           auth_type  PASS
           auth_pass  123456
       }
       virtual_ipaddress {  # 虚拟IP。可以设置多个虚拟IP地址,每行一个
           172.91.0.101
       }
   }
   ```
   
3. **启动Keepalived**

   ```bash
   service keepalived start
   service keepalived stop
   update-rc.d keepalived defaults
   ```

### 安装第二个Haproxy

1. **创建Haproxy容器**

   ```bash
   docker run -it -d -p 4003:8888 -p 4004:3306 --restart=always -v /home/haproxy:/usr/local/etc/haproxy --name haproxy2 --net=mysql-network --ip 172.91.0.8 --privileged haproxy:2.1.7
   ```

2. **进入Haproxy容器,安装Keepalived**

   ```bash
   docker exec -it haproxy2 bash
   apt-get update
   apt-get install keepalived
   # 先退出容器将配置文件拷贝到宿主机
   docker cp ./keepalived.conf haproxy2:/etc/keepalived
   ```

3. **Keepalived配置文件**

   ```bash
   vim /etc/keepalived/keepalived.conf
   vrrp_instance  VI_1 {
       state  MASTER  # Keepalived的身份(MASTER主服务要抢占IP,BACKUP备服务器不会抢占IP)。
       interface  br-979f81083d09    # docker网卡设备,虚拟IP所在
       virtual_router_id  52  # 虚拟路由标识,MASTER和BACKUP的虚拟路由标识必须一致。从0~255
       priority  100  # MASTER权重要高于BACKUP数字越大优先级越高
       advert_int  1  # MASTER和BACKUP节点同步检查的时间间隔,单位为秒,主备之间必须一致
       authentication {  # 主从服务器验证方式。主备必须使用相同的密码才能正常通信
           auth_type  PASS
           auth_pass  123456
       }
       virtual_ipaddress {  # 虚拟IP。可以设置多个虚拟IP地址,每行一个
           172.91.0.101
       }
   }
   ```

4. **启动Keepalived**

   ```bash
   service keepalived start
   service keepalived stop
   update-rc.d keepalived defaults
   ```

## 实现外网访问虚拟IP

1. 在宿主机中安装Keepalived

   ```
   yum install keepalived
   ```

2. 宿主机Keepalived配置如下(/etc/keepalived/keepalived.conf):

   ```bash
vrrp_instance VI_1 {
       state MASTER
#这里是宿主机的网卡,可以通过ip a查看当前自己电脑上用的网卡名是哪个
       interface em2
       virtual_router_id 101
       priority 100
       advert_int 1
       authentication {
           auth_type PASS
           auth_pass 1111
       }
       virtual_ipaddress {
   #这里是指定的一个宿主机上的虚拟ip,一定要和宿主机网卡在同一个网段,
   #我的宿主机网卡ip是192.168.1.100,所以指定虚拟ip是143
              192.168.1.143
       }
   }
    
   #接受监听数据来源的端口,网页入口使用
   virtual_server 192.168.1.165 8888 {
       delay_loop 3
       lb_algo rr 
       lb_kind NAT
       persistence_timeout 50
       protocol TCP
   #把接受到的数据转发给docker服务的网段及端口,由于是发给docker服务,所以和docker服务数据要一致
       real_server 172.91.0.101 8888 {
           weight 1
       }
   }
    
   #接受数据库数据端口,宿主机数据库端口是3306,所以这里也要和宿主机数据接受端口一致
   virtual_server 192.168.1.165 3306 {
       delay_loop 3
       lb_algo rr 
       lb_kind NAT
       persistence_timeout 50
       protocol TCP
   #同理转发数据库给服务的端口和ip要求和docker服务中的数据一致
       real_server 172.91.0.101 3306 {
           weight 1
       }
   }
   ```
   
3. 启动Keepalived服务

   ```bash
   systemctl start keepalived
   systemctl status keepalived
   systemctl stop keepalived
   ```

   之后其他电脑便可以通过虚拟IP 192.168.1.165的8888和3306端口来访问宿主机Docker中的 172.91.0.101的相应端口。

### 遇到问题

ip address associated with VRID 51 not present in MASTER advert

```bash
virtual_router_id 101
这里要保证唯一性,实体机之前测试装过,导致两者冲突
```

## 常用命令

1. 清空配置

   ```bash
   docker stop `docker ps -a| grep mysqlnode | awk {print $1} `
   docker rm `docker ps -a| grep mysqlnode | awk {print $1} `
   docker stop `docker ps -a| grep haproxy | awk {print $1} `
   docker rm `docker ps -a| grep haproxy | awk {print $1} `
   docker volume rm v1
   docker volume rm v2
   docker volume rm v3
   docker volume rm v4
   docker volume rm v5
   rm -rf /home/haproxy
   ```

## 单机安装mysql5.7.30

### 下载

```
docker pull mysql:5.7.30

mkdir -p /home/mysql/data /home/mysql/logs /home/mysql/conf
```

### 启动

```bash
docker run -p 3306:3306  --restart=always --name mysql -v /home/mysql/conf:/etc/mysql -v /home/mysql/logs:/logs -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=baowuglyk32 -d mysql:5.7.30
```

 

MySql集群部署

上一篇:SqlServer生成实体类,包含Display和StringLength


下一篇:SpringBoot使用druid的monitor工具查看sql执行性能(20)