IT基础设施:基于docker的Mysql集群搭建及性能对比

前言

在高可用的需求下,我们通常用集群和负载均衡来解决问题,通过实时热备的多台主机提供相同的服务,即使部分节点故障,对外仍然能正常提供服务。本文探索在docker环境下快速构建Mysql集群,并与docker单节点、宿主机单节点进行写入性能对比。

本文默认看官懂得 docker 知识,有Mysql,C#实践基础。

Percona XtraDB Cluster

简称 PXC,是针对MySQL 用户的高可用性和扩展性解决方案,基于Percona Server,特点为:
  (1)同步复制,事务在所有集群节点要么同时提交,要么不提交。
  (2)多主复制,可以在任意一个节点写入。
  (3)从服务器上的并行应用事件,真正的“并行复制”。
  (4)自动配置节点。
  (5)数据一致性,没有不同步的从服务器。

HAProxy

HAProxy是一款提供高可用性、负载均衡以及基于TCP(第四层)和HTTP(第七层)应用的代理软件,HAProxy是完全免费的、借助HAProxy可以快速并且可靠的提供基于TCP和HTTP应用的代理解决方案。

Mysql通信工作在TCP层,所以这里选择了HAProxy做为负载代理。

过程

拉取percona-xtradb-cluster镜象

docker pull percona/percona-xtradb-cluster

原名称太长,我们使用tag功能,给他取个别名

 docker tag percona/percona-xtradb-cluster pxc

创建专用网络

docker network create --subnet=172.1.0.0/16 net1

分别为各节点创建本地卷

docker volume create mysql_data1
docker volume create mysql_data2
docker volume create mysql_data3
docker volume create mysql_data4
docker volume create mysql_data5

创建主节点

docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=abc12345 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc12345 -v mysql_data1:/var/lib/mysql -v backup:/data --privileged --name=mysql_node1 --net=net1 --ip 172.1.0.2 pxc

创建第2个MySQL节点

通过CLUSTER_JOIN联接主节点

docker run -d -p 3308:3306 -e MYSQL_ROOT_PASSWORD=abc12345 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc12345 -e CLUSTER_JOIN=mysql_node1 -v mysql_data2:/var/lib/mysql -v backup:/data --privileged --name=mysql_node2 --net=net1 --ip 172.1.0.3 pxc

创建第3个MySQL节点

docker run -d -p 3309:3306 -e MYSQL_ROOT_PASSWORD=abc12345 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc12345 -e CLUSTER_JOIN=mysql_node1 -v mysql_data3:/var/lib/mysql --privileged --name=mysql_node3 --net=net1 --ip 172.1.0.4 pxc

创建第4个MySQL节点

docker run -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=abc12345 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc12345 -e CLUSTER_JOIN=mysql_node1 -v mysql_data4:/var/lib/mysql --privileged --name=mysql_node4 --net=net1 --ip 172.1.0.5 pxc

创建第5个MySQL节点

docker run -d -p 3311:3306 -e MYSQL_ROOT_PASSWORD=abc12345 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc12345 -e CLUSTER_JOIN=mysql_node1 -v mysql_data5:/var/lib/mysql -v backup:/data --privileged --name=mysql_node5 --net=net1 --ip 172.1.0.6 pxc

负载均衡网关布署

拉取镜象

docker pull haproxy

创建配置文件

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     Global\ statistics
    #WEB管理帐号
    stats auth  admin:abc12345
#数据库负载均衡
listen  proxy-mysql
    #访问的IP和端口
    bind  0.0.0.0:3306
    #网络协议
    mode  tcp
    #负载均衡算法(轮询算法)
    #轮询算法:roundrobin
    #权重算法:static-rr
    #最少连接算法:leastconn
    #请求源IP算法:source 
    balance  roundrobin
    #日志格式
    option  tcplog
    option  mysql-check user haproxy
    server  MySQL_1 172.1.0.2:3306 check weight 1 maxconn 2000  
    server  MySQL_2 172.1.0.3:3306 check weight 1 maxconn 2000  
    server  MySQL_3 172.1.0.4:3306 check weight 1 maxconn 2000 
    server  MySQL_4 172.1.0.5:3306 check weight 1 maxconn 2000
    server  MySQL_5 172.1.0.6:3306 check weight 1 maxconn 2000
    #使用keepalive检测死链
    option  tcpka  

运行haproxy

docker run -it -d -p 9001:8888 -p 3306:3306 -v /home/haproxy:/usr/local/etc/haproxy --name haproxy_1 --privileged --net=net1 --ip 172.1.0.7 haproxy

通过访问http://宿主机地址:9001/dbs即可查看网关dashboard

数据写入测试

创建测试数据库,以及表

CREATE SCHEMA `Awp` DEFAULT CHARACTER SET utf8mb4 ;

用户表

CREATE TABLE `Users` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `Username` varchar(45) DEFAULT NULL,
  `Password` varchar(45) DEFAULT NULL,
  `Locked` bit(1) DEFAULT NULL,
  `CreateDate` datetime DEFAULT NULL,
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB AUTO_INCREMENT=49999 DEFAULT CHARSET=utf8mb4;

单线程写入

测试用代码(dotnet core C#)

        static void Main(string[] args)
        {
            DapperExtensions.DapperExtensions.SqlDialect = new MySqlDialect();
            DapperExtensions.DapperExtensions.DefaultMapper = typeof(PluralizedAutoClassMapper<>);

            const int total = 10000;
            var Ctx = new MySqlConnection("server=192.168.0.226;database=Awp;uid=root;pwd=abc12345;charset='utf8';Character Set=utf8");
            var st = new Stopwatch();
            st.Start();
            for (var i = 0; i < total; i++)
            {
                var user = new User
                {
                    Username = $"testuser{i}",
                    Password = "12345678901234567890123456789022",
                    Locked = false,
                    CreateDate = DateTime.Now
                };
                Ctx.Insert(user);
            }
            st.Stop();
            Console.WriteLine($"Insert {total} users paid {st.ElapsedMilliseconds / 1000.0} seconds.");
            
        }

测试结果

# Mysql docker cluster(Mysql 5.7)
E:\Workspace\Repos\ConsoleCore\ConsoleCore\bin\Release\netcoreapp2.0>dotnet ConsoleCore.dll
Insert 10000 users paid 46.069 seconds.

# 物理机 Mariadb (5.5.60)
E:\Workspace\Repos\ConsoleCore\ConsoleCore\bin\Release\netcoreapp2.0>dotnet ConsoleCore.dll
Insert 10000 users paid 17.061 seconds.

# Mariadb docker (10.3.15)
E:\Workspace\Repos\ConsoleCore\ConsoleCore\bin\Release\netcoreapp2.0>dotnet ConsoleCore.dll
Insert 10000 users paid 31.782 seconds.

多线程写入

测试用代码(dotnet core C#)

        static void Main(string[] args)
        {
            DapperExtensions.DapperExtensions.SqlDialect = new MySqlDialect();
            DapperExtensions.DapperExtensions.DefaultMapper = typeof(PluralizedAutoClassMapper<>);

            const int total = 10000;
            var st = new Stopwatch();
            st.Start();

            Parallel.For(0, total, i =>
            {
                using (var db = new MySqlConnection("server=192.168.0.226;database=Awp;uid=root;pwd=abcd123456;charset='utf8';Character Set=utf8"))
                {
                    var user = new User
                    {
                        Username = $"testuser{i}",
                        Password = "12345678901234567890123456789022",
                        Locked = false,
                        CreateDate = DateTime.Now
                    };
                    db.Insert(user);
                }
            });
            st.Stop();
            Console.WriteLine($"Insert {total} users paid {st.ElapsedMilliseconds / 1000.0} seconds.");
            
        }

测试结果

# Mysql docker cluster(Mysql 5.7)
E:\Workspace\Repos\ConsoleCore\ConsoleCore\bin\Release\netcoreapp2.0>dotnet ConsoleCore.dll
Insert 10000 users paid 6.601 seconds.

# 物理机 Mariadb (5.5.60)
E:\Workspace\Repos\ConsoleCore\ConsoleCore\bin\Release\netcoreapp2.0>dotnet ConsoleCore.dll
Insert 10000 users paid 4.047 seconds.

# Mariadb docker (10.3.15)
E:\Workspace\Repos\ConsoleCore\ConsoleCore\bin\Release\netcoreapp2.0>dotnet ConsoleCore.dll
Insert 10000 users paid 6.444 seconds.

结论

由于测试环境有限,目前只能看出在docker环境下,集群化并不会导致吞吐量的下降,写入性能较物理机相对较弱,后续有米加机器了再尝试物理机集群。

问题

当我停止了集群,去测试宿主机Mysql和docker mariadb之后,想重新启动集群,结果node1无法启动,日志是显示2019-05-21T22:17:16.289015Z 0 [ERROR] WSREP: It may not be safe to bootstrap the cluster from this node. It was not the last one to leave the cluster and may not contain all the updates. To force cluster bootstrap with this node, edit the grastate.dat file manually and set safe_to_bootstrap to 1 .,这里需要到相应的卷下编辑grastate.dat文件,修改safe_to_bootstrapsafe_to_bootstrap,例如:

vim /var/lib/docker/volumes/mysql_data1/_data/grastate.dat

修改如下:

# GALERA saved state
version: 2.1
uuid:    e5b2c3e9-7c16-11e9-8115-975d6d143cf4
seqno:   -1
safe_to_bootstrap: 1

这个修改是一次性的,当节点运行后,它还会变回0

额外闲得蛋痛的测试

# 树莓派3B 两台(一台跑脚本,一台单独Mariadb)
root@imud-web01:/home/test# /root/dotnet/dotnet ConsoleCore.dll
Insert 10000 users paid 189.774 seconds.

# 树莓派3B一台跑脚本,Mariadb为1C1G虚拟机)
root@imud-web01:/home/test# /root/dotnet/dotnet ConsoleCore.dll
Insert 10000 users paid 81.676 seconds.

# 树莓派3B一台跑脚本,Mariadb为2C2G虚拟机)
root@imud-web01:/home/test# /root/dotnet/dotnet ConsoleCore.dll
Insert 10000 users paid 88.178 seconds.

# i5-6600K(宿主机跑脚本,Mariadb为1C1G虚拟机)
E:\publish>dotnet ConsoleCore.dll
Insert 10000 users paid 27.46 seconds.

# i5-6600K(宿主机跑脚本,Mariadb为2C2G虚拟机)
E:\publish>dotnet ConsoleCore.dll
Insert 10000 users paid 26.32 seconds.

# 2C2G虚拟机本机
E:\publish>dotnet ConsoleCore.dll
Insert 10000 users paid 22.79 seconds.

引用

1. docker 搭建Mysql集群

你可能感兴趣的:(IT基础设施:基于docker的Mysql集群搭建及性能对比)