实战 MySQL 高可用架构
业界流传一句话:没有做过运维的程序员不是好架构师。
不知是真是假。
前言
对于 MySQL 数据库作为各个业务系统的存储介质,在系统中承担着非常重要的职责,如果数据库崩了,那么对于读和写数据库的操作都会受到影响。如果不能迅速恢复,对业务的影响是非常大的。之前 B 站不是出过一次事故么,2 小时才恢复过来,详细可以看之前写的文章。
B 站崩了,总结下「高可用」和「异地多活」
上次折腾完 ELK 日志检索平台后,开发环境可以正常查询日志了。最近在做系统高可用相关的工作,这次我来分享下 MySQL 双主 Keepalived 的高可用落地和踩坑之路。
一文带你搭建一套 ELK Stack 日志平台
一、方案选择
对于 MySQL 的高可用,主要分为两步,配置 MySQL 主主模式和 keepalived 软件。拓扑图如下所示:
MySQL 数据库的主主模式
两个数据库分别部署在两台服务器上,相互同步数据,但是只有一个提供给外部访问,当一个宕机后,另外一个可以继续提供服务,在没有 keepalived 软件的帮助下,只能手动切换
keepalived 监测、自动重启、流量切换检测和重启:两台服务器上都部署 keepalived 软件,定时检测 MySQL 服务是否正常,如果一个数据库服务崩了,keepalived 会用脚本尝试重启 mysql 服务。备份:两个 keepalived 服务都提供了虚拟 IP 供客户端使用,但是流量只会转到一台 MySQL 服务上。虚拟 IP:keepalived 配置好了后,会有一个 虚拟 IP,对于客户端来说,不关心连接的是哪台 MySQL,访问虚拟 IP 就可以了。流量切换:如果客户端正在访问的 MySQL 服务崩了后,keepalived 会用我们写的脚本自动重启 MySQL,如果重启失败,脚本主动停掉 keepalived,客户端的流量就不会访问到这台服务器上的 MySQL 服务,后续访问的流量都会切到另外一台 MySQL 服务。
检测和重启的原理如下所示:
需要配置的内容如下:
两台 Ubuntu 服务器上启动 MySQL 容器。配置 MySQL 主从复制架构。将 MySQL 主从改为主主复制架构。两台服务器搭建 keepalived 环境监控 MySQL 和自动重启 MySQL。
二、主主复制的原理
对于 MySQL 的主主架构,其实原理就是两台服务器互为主从,双向复制。而复制的原理如下:
主从复制主要有以下流程:
主库将数据的改变记录到 binlog 中;从库会在一定时间间隔内对master 的 binlog 进行检查,如果发生改变,则开始一个 I/O Thread 请求读取 master 中 binlog ;同时主库为每个 I/O 线程启动一个 dump 线程,用于向其发送二进制事件,并保存至从节点本地的中继日志中,从库将启动 SQL 线程从中继日志中读取二进制日志,在本地重放,使得其数据和主节点的保持一致,最后 I/O Thread 和 SQL Thread 将进入睡眠状态,等待下一次被唤醒;
大白话就是:
从库会生成两个线程,一个 I/O 线程,一个 SQL 线程;
I/O 线程会去请求主库的 binlog,并将得到的 binlog 写到本地的 relay-log (中继日志)文件中;
主库会生成一个 dump 线程,用来给从库 I/O 线程传 binlog;
SQL 线程,会读取 relay log 文件中的日志,并解析成 SQL 语句逐一执行;
接下来我们先把 MySQL 的基础环境在两台 Ubuntu 服务器上搭建好,后续操作都是基于这个来做的。
三、配置 MySQL 环境
作为演示,我在本机启动了两台 Ubuntu 虚拟机,安装有 docker。因为我们的测试和生产环境是用 Docker 跑的,所以我将环境的镜像打包后,还原到我的虚拟机上面。
3.1 备份和还原 mysql 镜像
保存测试环境的 mysql 镜像
sudo docker save -o mysql.tar hcr:5000/hschub/hscmysql:0.0.2
sudo chmod 777 mysql.tar
两台机器导入镜像
sudo docker load -i mysql.tar
启动容器,需要注意的是需要映射本地文件夹。
sudo docker run -p 3306:3306 --name mysql \
-v /home/hss/mysql/data:/var/lib/mysql \
-v /home/hss/mysql/etc/mysql:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-d 46b
-v 代表映射的文件夹,-d 表示后台运行,46b 代表镜像 id。
进入容器,连接 mysql,node1的mysql 密码是 123456,node2 是 123456
# 查询容器 id
docker ps
# 进入 mysql 容器
docker exec -it