目录
mysql单机性能测试
1 2 3 4 5 6 7 8 9 10 |
mysqlslap \ --concurrency=5000 \ --iterations=1 \ --auto-generate-sql \ --auto-generate-sql-load-type=mixed \ --auto-generate-sql-add-autoincrement \ --engine=innodb \ --number-of-queries=5000 \ --debug-info \ -hlocalhost -uroot -p3721uc -P3306 |
关于这个测试命令呢,我简单讲一下几个关键参数
--concurrency=5000
: 表示启动5000个线程连接数据库
--iterations=1
: 测试执行次数
--number-of-queries=5000
: 总的执行次数
这个mysqlslap
是mysql自带的测试工具,大家可以试一下。
1. 前言
随着mysql存储的数据量越来越大,mysql查询单表时的响应速度也会随之变慢,尤其是当单节点承载的数据量超出一定的范围后,比如单表超过2000万之后,查询响应速度会下降的很快,因此,一方面可以考虑mysql集群,另一方面可以考虑读写分离,这两种方案的出发点不同,集群更多是从单节点可容纳的并发连接数考虑,比如单节点的mysql服务器支持的最大连接数是有限的;而读写分离可以提升mysql服务总体的读写性能,避免读请求和写请求都打到同一个节点上,分摊压力
总结来说,可以归纳为单节点的mysql服务始终是有瓶颈的,因此需要考虑集群化的解决方案,业界比较成熟的方案包括PXC集群和replication集群。
2. pxc集群
2.1 PXC介绍
Percona XtraDB Cluster(简称PXC集群)提供了MySQL高可用的一种实现方法
- 集群是有节点组成的,推荐配置至少3个节点,但是也可以运行在2个节点上,生产环境建议不要超过15个,否则整体性能下降的很快
- 每个节点都是普通的mysql/percona服务器,可以将现有的数据库服务器组成集群,反之,也可以将集群拆分成单独的服务器
- 每个节点都包含完整的数据副本
PXC集群主要由两部分组成:Percona Server with XtraDB和Write Set Replication patches(使用了Galera library,一个通用的用于事务型应用的同步、多主复制插件)
2.2 PXC特性
- 速度慢,但能保证强一致性,适用于保存价值较高的数据,比如订单、客户、支付等。
- 数据同步是双向的,在任一节点写入数据,都会同步到其他所有节点,在任何节点上都能同时读写。
- 采用同步复制,向任一节点写入数据,只有所有节点都同步成功后,才会向客户端返回成功。事务在所有节点要么同时提交,要么不提交。
建议PXC使用PerconaServer (MySQL改进版,性能提升很大) - PXC的数据强一致性
2.3 PXC优势
- 服务高可用
- 数据同步复制(并发复制),几乎无延迟
- 多个可同时读写节点,可实现写扩展,不过最好事先进行分库分表,让各个节点分别写不同的表或者库,避免让galera解决数据冲突
- 新节点可以自动部署,部署操作简单
- 数据严格一致性,尤其适合电商类应用
- 完全兼容MySQL
3. pxc集群搭建
在Docker中安装PXC集群,使用Docker仓库中的PXC官方镜像:
1 |
docker pull percona/percona-xtradb-cluster:5.7.21 |
重命名镜像:(名称太长,可以重命名一下)
1 |
docker tag percona/percona-xtradb-cluster:5.7.21 pxc |
删除原镜像:
1 |
docker rmi percona/percona-xtradb-cluster:5.7.21 |
创建docker内部网络
1 2 3 4 5 6 7 8 9 |
# 创建内部网段 docker network create --driver bridge \ --subnet 172.22.33.0/24 \ --gateway 172.22.33.1 \ mysql_cluster_net # 查看网段相关信息 $ docker network inspect mysql_cluster_net # 下面为删除网段 # $ docker network rm mysql_cluster_net |
创建docker卷
使用Docker时,业务数据应保存在宿主机中,采用目录映射,这样可以使数据与容器独立。但是容器中的PXC无法直接使用映射目录,解决办法是采用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容器
创建5个PXC容器构成集群,第一个节点作为主节点,要确保第一个节点启动成功。
创建主节点
1 2 3 4 5 6 7 8 9 |
docker run -d \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=123456 \ -e CLUSTER_NAME=PXC \ -e XTRABACKUP_PASSWORD=123456 \ -v v1:/var/lib/mysql --privileged \ --name=node1 \ --net=mysql_cluster_net \ --ip 172.22.33.6 pxc |
参数解析:
-p 3306:3306
:将docker容器的mysql的3306端口映射到宿主机的3306端口
-e MYSQL_ROOT_PASSWORD=123456
:设置mysql客户端连接密码
-e XTRABACKUP_PASSWORD=123456
:设置复制访问密码
-e CLUSTER_NAME=PXC
:给PXC集群起一个名字,这里叫做PXC
-v v1:/var/lib/mysql --privileged
:宿主机的v1数据卷目录挂载容器1的mysql目录
--net=mysql_cluster_net
:使用指定的网络
--name=node1
:节点名称(自定义)
--ip 172.22.33.6
:指定ip,如果需要自动分配ip,把这行删除
pxc
:使用的镜像名
创建从节点
从节点需要加入主节点(第一个节点),下面是一个示例:
1 2 3 4 5 6 7 8 9 10 11 |
docker run -d \ -p 3307:3306 \ # 这里需要修改端口 -e MYSQL_ROOT_PASSWORD=123456\ -e CLUSTER_NAME=PXC \ # 必须和主节点一致 -e XTRABACKUP_PASSWORD=123456\ # 必须和主节点一致 -e CLUSTER_JOIN=node1 \ # 必须加入主节点 -v v2:/var/lib/mysql \ # 这里需要修改挂载卷 --privileged \ --name=node2 \ # 这里需要修改节点名 --net=mysql_cluster_net \ # 必须和主节点一致 --ip 172.22.33.7 pxc # 这里需要修改ip,如果需要自动分配IP,把--ip ip地址删除 |
从节点使用参数:-e CLUSTER_JOIN=node1
加入名为node1
的主节点(第一个节点)
查看正在运行的容器
1 |
docker ps |
负载均衡方案
负载均衡的必要性
如果不使用数据库负载均衡,单节点处理所有请求,负载高,性能差
使用Haproxy做负载均衡,请求被均匀分发给每个节点,单节点负载低,性能好
安装Haproxy
从Docker仓库拉取haproxy镜像:
1 |
docker pull haproxy |
在宿主机创建Haproxy配置文件。供Haproxy容器使用( haproxy.cfg )
1 2 3 |
mkdir /home/haproxy vim /home/haproxy/haproxy.cfg |
haproxy.cfg内容如下:
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 |
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 node1:3306 check weight 1 maxconn 2000 server MySQL_2 node2:3306 check weight 1 maxconn 2000 server MySQL_3 node3:3306 check weight 1 maxconn 2000 server MySQL_4 node4:3306 check weight 1 maxconn 2000 server MySQL_5 node5:3306 check weight 1 maxconn 2000 # 使用keepalive检测死链 option tcpka |
server MySQL_1 node1:3306 check weight 1 maxconn 2000
:把所有节点都加上去。需要修改MySQL_1
和IP
即可。
在数据库集群中创建空密码、无权限用户haproxy,来供Haproxy对MySQL数据库进行心跳检测:
1 2 3 4 5 6 7 8 9 10 11 12 |
#示例 #进入node1容器 docker exec -it node1 bash #登录mysql mysql -u root -p #指定数据库 use mysql; #创建用户 create user 'haproxy'@'%' identified by ''; |
创建Haproxy容器:
1 2 3 4 5 6 7 8 |
docker run -d \ -p 4001:8888 \ -p 4002:3306 \ -v /home/haproxy:/usr/local/etc/haproxy:ro \ --net=mysql_cluster_net \ --privileged \ --ip 172.22.33.3 \ --name haproxy-1 haproxy |
参数解析:
-p 4001:8888
:映射端口。8888是haproxy监控页面端口。
-p 4002:3306
:映射端口。haproxy转发端口,访问4002端口会转发到3306端口。
-v /home/haproxy:/usr/local/etc/haproxy:ro
:挂载haproxy配置文件。
--net=mysql_cluster_net
:指定网络。
--ip 172.22.33.3
:指定IP,如果需要自动分配IP,把这行删除。
容器启动后,haproxy自动启动,如果没启动使用下面命令启动)进入容器并启动haproxy:
1 2 3 4 5 |
#进入容器 docker exec -it h1 bash #启动haproxy haproxy -f /usr/local/etc/haproxy/haproxy.cfg |
浏览器中打开Haproxy监控界面
根据配置文件和启动容器设置的端口,我的访问路径为:http://192.168.63.144:4001/dbs ,用户名admin,密码123456
尝试宕掉一台数据库
Haproxy不存储数据,只转发数据。可以在通过Haproxy连接数据库,端口4002,用户名和密码为数据库集群的用户名和密码:
高可用负载均衡方案
虚拟IP技术
haproxy双机互备离不开一个关键的技术,这个技术是虚拟IP,linux可以在一个网卡内定义多个虚拟IP,得把这些IP地址定义到一个虚拟IP。
利用keeplived实现双机热备
定义出来一个虚拟IP,这个方案叫双机热备,准备2个keepalived,keepalived 就是为了抢占虚拟IP的,谁手快谁能抢到,没抢到的处于等待的状态。抢到的叫做主服务器,未抢到的叫做备服务器。两个keepalived之前有心跳检测的,当备用的检测到主服务挂了,就立马抢占虚拟IP。
Haproxy双机热备方案
安装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 30 |
$ 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.22.33.244 } } |
启动keeplived,容器内启动
1 2 3 4 5 6 7 |
$ service keepalived start # 宿主机ping这个ip $ ping 172.22.33.244 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 |
可以按照以上步骤,再另外创建一个Haproxy容器,注意映射的宿主机端口不能重复,Haproxy配置一样。
宿主机安装配置keeplived
首先查看当前局域网IP分配情况
1 2 3 4 5 |
#下载nmap工具 yum install nmap -y #查看当前宿主机网段所有占用的IP nmap -sP 192.168.1.0/24 |
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 |
$ yum -y install keepalived $ mv /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak $ vi /etc/keepalived/keepalived.conf vrrp_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 { 192.168.0.210 #虚拟ip 需要和宿主机ip在同一网段 } } #接受监听数据来源的端口,网页入口使用 virtual_server 192.168.0.210 8888 { delay_loop 3 lb_algo rr lb_kind NAT persistence_timeout 50 protocol TCP #把接受到的数据转发给docker服务的网段及端口,由于是发给docker服务,所以和docker服务数据要一致 real_server 172.22.33.244 8888 { weight 1 } } #接受数据库数据端口,宿主机数据库端口是3306,所以这里也要和宿主机数据接受端口一致 virtual_server 192.168.0.210 3306 { delay_loop 3 lb_algo rr lb_kind NAT persistence_timeout 50 protocol TCP #同理转发数据库给服务的端口和ip要求和docker服务中的数据一致 real_server 172.22.33.244 3306 { weight 1 } } |
启动keeplived
1 2 |
$ systemctl start keeplived $ systemctl enable keeplived |
访问haproxy页面,http://ip:8888/dbs