若发现文章有误,欢迎提出宝贵的建议,敬请指教,感谢
文章目录
- 运行环境
- 一、MySQL相关概念
- 1.1 中继日志 relay log
- 1.2 主从架构 & 读写分离
- 1.2.1 如何提高数据库的并发能力
- 1.2.2 主从架构的三大作用
- 1.2.3 主从复制的原理
- 二、Docker实现MySQL主从架构
- 2.1 创建、配置Master库容器
- 2.2 创建、配置Slave库容器
- 总结
- 参 考 资 料
中继日志 relay log
只在主从master/slave
服务器架构的从服务器上存在。
slave
为了与master
保持一致,要从master
读取二进制日志的内容,并且把读取到的信息写入本地的日志文件中,slave
本地的日志文件就叫做中继日志(relay log)
。
slave
读取relay log
,并根据其内容对slave
的数据进行更新,完成master
与slave
的数据同步。
搭建好master/slave
之后,relay log
默认会保存在slave
的数据目录下。
relay log 存储文件名的格式是:slave_name -relay-bin.序号
。
relay log 还有一个索引文件:slave_name-relay-bin.index
, 用于定位当前正在使用的 relay log
relay log 与 二进制日志(bin log)的格式相同,可以用mysqlbinlog
工具进行查看
在实际工作中,通常使用 Redis 作为缓存与MySQL配合使用,当有请求的时候,首先会从缓存中进行查找,如果存在就直接取出,如果不存在的话再访问数据库,这样就提升了读取的效率,也减少了对后端数据库的访问压力,Redis的缓存架构是高并发架构中非常重要的一环。
此外,一般对数据库而言都是“读取多,写入少”,即数据库读取数据的压力比较大,解决思路之一就是采用数据库集群的方案,做主从架构,进行读写分离,这样同样可以提升数据库的并发处理能力。
提升数据库高并发访问的步骤,根据需求依次选择其中一种,使用和维护成本是逐渐升高的:
主从同步设计不仅可以提高数据库的吞吐量,还有以下3个方面的作用。
1.读写分离
可通过主从复制的方式来同步数据,然后通过读写分离提高数据库并发处理能力
其中一个为Master主库,负责写入数据,简称为:写库
其他都是Slave从库,负责读取数据,简称为:读库
如图,当Master进行更新时,会自从将数据复制到Slave中,而我们在客户端读取数据时,会从Slave中读取。
面对"读多写少"的需求,采用读写分离的方式,可以实现更高的并发访问,同时我们还能对服务器进行负载均衡,让不同的读请求按照策略均匀的分发到不同的Slave上,让读取更加流畅,读取流畅的另一个原因就是减少了锁表的影响,比如:Master负责写,当Master锁表时,不会影响到Slave进行SELECT的读取。
2.数据备份
将Master的数据复制到Slave上,相当于是一种热备份机制,即在Master正常运行的情况下进行备份,不会影响到服务
3.高可用性
数据备份实际上是一种冗余的机制,通过这种冗余的方式可以换取数据库的高可用性。
当Master服务器出现故障或宕机的情况下,可以切换到Slave上,保证服务的正常运行。
关于高可用的程度,可用一个指标衡量,即 正常可用时间 / 全年时间
,比如要达到全年99.999%的时间都可以使用,这意味着系统在一年中的不可用时间不得超过`3652460*(1-99.999%) = 5.256 分钟(含系统崩溃的日志、日常维护操作导致的停机时间等),其他时间都需要保证高可用的状态。
原理:
Slave 会从Master读取bin log (二进制日志)来进行数据同步。
在主从复制过程中,会基于三个线程来操作,一个主库线程,两个从库线程。
二进制日志转储线程(BinLog Dump Thread)是一个Master库线程。当slave库线程连接时,Master库可以将二进制日志发送给Slave。当Master库读取事件(Event)的时候,会在BinLog上加锁,读取完成后,再将锁释放。
Slave库 I / O 线程会连接到Master库,向Master发送请求更新BinLog。这时Slave的I/O线程就可以读取到Master的BinLog Dump Thread 发送的BinLog更新部分,并且拷贝到本地的Relay Log(中继日志)。
Slave库 SQL 线程 会读取库中的中继日志,并且执行日志中的事件,将Slave库中的数据与Master库保持同步。
注:不是所有版本的MySQl都默认开启服务器的二进制日志。在进行主从同步的时候,首先需检查服务器是否已开启二进制日志。
除非特殊指定,默认情况下Slave会执行所有Master服务器中保存的事件,也可以通过配置,使Slave服务器只执行特定的事件。
同步复制的三步骤:
- Master将写操作记录到二进制日志(binlog),这些记录叫做二进制日志事件(binary log envents)
- Slave将Master的binary log events 拷贝到它的中继日志(relay log )
- Slave 重做中继日志中的事件,将改变应用到自己的数据库中。
MySQL复制是异步并且串行化的,而且重启后会从接入点开始复制。
同步复制的最大问题是延时
同步复制的原则:
- 每个Slave只能有一个Master
- 每个Slave只能由一个唯一的服务器ID
- 每个Master可以有多个Slave
拉取Mysql5.7的镜像
$ sudo docker pull mysql:5.7
注:由于是在同一个宿主机上使用Docker搭建,所以端口映射不能都为3306,否则会发生冲突,这里则采用Master 3307、Slave 3308的端口映射方式。
第一步,创建Master库容器
$ sudo docker run -p 3307:3306 --name mysql-master \
-v /uni/docker/mysql-master/log:/var/log/mysql \
-v /uni/docker/mysql-master/data:/var/lib/mysql \
-v /uni/docker/mysql-master/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
第二步,宿主机进入与容器卷同步的目录,添加MySQL配置文件
$ cd /uni/docker/mysql-master/conf
$ vim my.cnf
配置内容如下:
[mysqld]
## 设置server_id,同一局域网中需要唯一
server_id=1
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能
log-bin=mall-mysql-bin
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
## 二进制日志过期清理时间。默认值为0,表示不自动清理。
expire_logs_days=7
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
修改完后重启Master库容器
$ sudo docker restart mysql-master
第三步,进入Master库容器、创建数据同步的用户:
$ sudo docker exec -it mysql-master /bin/bash
myslq -uroot -proot
# 创建 slave用户
mysql> CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
# 赋予 slave用户权限
mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
第一步,创建Slave库容器
$ sudo docker run -p 3308:3306 --name mysql-slave \
-v /uni/docker/mysql-slave/log:/var/log/mysql \
-v /uni/docker/mysql-slave/data:/var/lib/mysql \
-v /uni/docker/mysql-slave/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
第二步,和之前一样,先去宿主机配置的容器卷位置创建Slave库的配置文件
$ cd /uni/docker/mysql-slave/conf
$ vim my.cnf
配置的内容如下:
[mysqld]
## 设置server_id,同一局域网中需要唯一
server_id=2
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能,以备Slave作为其它数据库实例的Master时使用
log-bin=mall-mysql-slave1-bin
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
## 二进制日志过期清理时间。默认值为0,表示不自动清理。
expire_logs_days=7
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
## relay_log配置中继日志
relay_log=mall-mysql-relay-bin
## log_slave_updates表示slave将复制事件写进自己的二进制日志
log_slave_updates=1
## slave设置为只读(具有super权限的用户除外)
read_only=1
Salve库配置与Master库配置的区别如下:
配置好后重启Slave库容器
$ sudo docker restart mysql-slave
第三步,在Master库容器中查看主从同步状态
mysql> show master status;
$ sudo docker exec -it mysql-slave /bin/bash
mysql -uroot -proot
修改语句标准语法:
change master to master_host='宿主机ip', master_user='slave', master_password='123456', master_port=3307, master_log_file='mall-mysql-bin.000001', master_log_pos=617, master_connect_retry=30;
测试语句(Slave库容器):
mysql> change master to master_host='192.168.25.128', master_user='slave', master_password='123456', master_port=3307, master_log_file='mall-mysql-bin.000001', master_log_pos=617, master_connect_retry=30;
# 接着在Slave库容器中查看主从同步状态,\G表示以KV形式打印
mysql> show slave status \G;
观察是否开启主从复制,主要查看Slave_IO_Running和Slave_SQL_Running这两个线程是否在运行,由于我们没有启动,之前只是指定了它的Master库,所以这里显示为NO
第五步,在Slave库容器中开启slave,再查看IO和SQL线程的运行结果:
mysql> start slave;
mysql> show slave status \G;
最后一步,同时开启Master库和Slave库,进行读写分离的测试:
在Master库容器中,创建随机的一个数据库、数据表,插入随机数据
然后在Slave库容器中进行查询。
至此,基于Docker搭建的MySQL主从架构已完毕。
本次使用Docker搭建了两个节点的MySQL主从架构,了解了MySQL中继日志、读写分离的相关概念,主从架构本质上实现了读写分离,比如在Master库写入数据的同时不会影响在Slave库容器读数据,提高可用性,但同时也容易产生数据不一致的问题,这里没有做讨论,至少我们知道了MySQL也支持类似于分布式的架构。
连接MySQL本身就需要通过IP:端口的形式,说明它肯定是支持远程连接的,这意味着它本身就能通过IP:端口去连接另外的MySQL服务器,虽然我们在平时学习当中经常是使用localhost连接的MySQL,但也不能仅仅局限于本地上的MySQL这种思想,如果有公网IP,开放对应的端口和权限后,只要在有网络的情况下,同样是可以继续远程连接的。
最后就是MySQL的主从架构并不一定是最好的选择,它虽然提高了数据的安全性,但同时也带来了数据延时和成本的问题。
[1]MySQL视频资料
[2]Docker视频资料