一、Binlog

Binlog 日志主要作用是数据恢复和主从复制。本身就是二进制格式的日志文件,网络传输无需进行协议转换。MySQL 集群的高可用,负载均衡,读写分离等功能都是基于Binlog 来实现的。关于Binlog的文章

二、MySQL 主从复制主流架构模型

我们基于 Binlog 可以复制出一台 MySQL 服务器,也可以复制出多台,取决于我们想实现什么功能。主流的系统架构有如下几种方式:

  1. 一主一从 / 一主多从

    一主一从和一主多从是最常见的主从架构方式,一般实现主从配置或者读写分离都可以采用这种架构。如果是一主多从的模式,当 Slave 增加到一定数量时,Slave 对 Master 的负载以及网络带宽都会成为一个严重的问题。

  2. 多主一从

    MySQL 5.7 开始支持多主一从的模式,将多个库的数据备份到一个库中存储。

  3. 双主复制
    理论上跟主从一样,但是两个MySQL服务器互做对方的从,任何一方有变更,都会复制对方的数据到自己的数据库。双主适用于写压力比较大的业务场景,或者 DBA 做维护需要主从切换的场景,通过双主架构避免了重复搭建从库的麻烦。(主从相互授权连接,读取对方binlog日志并更新到本地数据库的过程;只要对方数据改变,自己就跟着改变)

  4. 级联复制
    级联模式下因为涉及到的 slave 节点很多,所以如果都连在 master 上对主服务器的压力肯定是不小的。所以部分 slave 节点连接到它上一级的从节点上。这样就缓解了主服务器的压力。级联复制解决了一主多从场景下多个从库复制对主库的压力,带来的弊端就是数据同步延迟比较大。

  5. 企业级架构

    海量用户通过数据库代理(mycat,shardingjdbc)访问数据库,然后数据库读写分离,写由master承担,读由slave承担,同时,不同的业务场景可以指定特定的slave,降低数据库并发量。同时,有两个master(双主复制,进行热备份,需要keepalived等技术的支持),两个互相同步,只要有一个master宕机,就提升另一个master为主master,而不是从slave中选举。但是,这样一个但master也无法突破数据量,那就得进行分库分表了(进而将数据存在硬盘上),分完每一个分库,又做成改图得逻辑架构,从而提升mysql集群的可用性

三、MySQL 主从复制原理

MySQL 主从复制涉及到三个线程:

  • 一个在主节点的线程:log dump thread
  • 从库会生成两个线程:一个 I/O 线程,一个 SQL 线程

如下图所示:

  1. 主库会生成一个 log dump 线程,用来给从库 I/O 线程传 Binlog 数据。
  2. 从库的 I/O 线程会去请求主库的 Binlog,并将得到的 Binlog 写到本地的 relay log (中继日志)文件中。
  3. SQL 线程,会读取 relay log 文件中的日志,并解析成 SQL 语句逐一执行。
  • 主节点 log dump 线程
    从节点连接主节点时,主节点会为其创建一个 log dump 线程,用于发送和读取 Binlog 的内容。在读取 Binlog 中的操作时,log dump 线程会对主节点上的 Binlog 加锁;当读取完成发送给从节点之前,锁会被释放。主节点会为自己的每一个从节点创建一个 log dump 线程。

  • 从节点I/O线程
    从节点上执行start slave命令之后,从节点会创建一个 I/O 线程用来连接主节点,请求主库中更新的Binlog。I/O 线程接收到主节点的 log dump 进程发来的更新之后,保存在本地 relay-log(中继日志)中。

  • relay log
    这里又引申出一个新的日志概念。MySQL 进行主主复制或主从复制的时候会在要复制的服务器下面产生相应的 relay log。relay log 是怎么产生的呢?从服务器 I/O 线程将主服务器的 Binlog 日志读取过来,解析到各类 Events 之后记录到从服务器本地文件,这个文件就被称为 relay log。然后 SQL 线程会读取 relay log 日志的内容并应用到从服务器,从而使从服务器和主服务器的数据保持一致。中继日志充当缓冲区,这样 master 就不必等待 slave 执行完成才发送下一个事件。

四、relay log 相关参数查询

show variables like '%relay%';

  1. max_relay_log_size

标记 relay log 允许的最大值,如果该值为 0,则默认值为 max_binlog_size(1G);如果不为 0,则max_relay_log_size 则为最大的 relay_log 文件大小。

  1. relay_log_purge

是否自动清空不再需要中继日志时。默认值为1(启用)。

  1. relay_log_recovery

当 slave 从库宕机后,假如 relay log 损坏了,导致一部分中继日志没有处理,则自动放弃所有未执行的 relay log,并且重新从 master 上获取日志,这样就保证了 relay log 的完整性。默认情况下该功能是关闭的,将 relay_log_recovery 的值设置为 1 时,可在 slave 从库上开启该功能,建议开启。

  1. relay_log_space_limit

防止中继日志写满磁盘,这里设置中继日志最大限额。但此设置存在主库崩溃,从库中继日志不全的情况,不到万不得已,不推荐使用。

  1. sync_relay_log

这个参数和 Binlog 中的 sync_binlog作用相同。当设置为 1 时,slave 的 I/O 线程每次接收到 master 发送过来的 Binlog 日志都要写入系统缓冲区,然后刷入 relay log 中继日志里,这样是最安全的,因为在崩溃的时候,你最多会丢失一个事务,但会造成磁盘的大量 I/O。当设置为 0 时,并不是马上就刷入中继日志里,而是由操作系统决定何时来写入,虽然安全性降低了,但减少了大量的磁盘 I/O 操作。这个值默认是 0,可动态修改,建议采用默认值

  1. sync_relay_log_info

设置为 1 时,slave 的 I/O 线程每次接收到 master 发送过来的 Binlog 日志都要写入系统缓冲区,然后刷入 relay-log.info 里,这样是最安全的,因为在崩溃的时候,你最多会丢失一个事务,但会造成磁盘的大量 I/O。当设置为 0 时,并不是马上就刷入 relay-log.info 里,而是由操作系统决定何时来写入,虽然安全性降低了,但减少了大量的磁盘 I/O 操作。这个值默认是0,可动态修改,建议采用默认值。

五、从节点 SQL 线程

SQL 线程负责读取 relay log 中的内容,解析成具体的操作并执行,最终保证主从数据的一致性。对于每一个主从连接,都需要这三个进程来完成。当主节点有多个从节点时,主节点会为每一个当前连接的从节点建一个 log dump 进程,而每个从节点都有自己的 I/O 进程,SQL 进程。从节点用两个线程将从主库拉取更新和执行分成独立的任务,这样在执行同步数据任务的时候,不会降低读操作的性能。比如,如果从节点没有运行,此时 I/O 进程可以很快从主节点获取更新,尽管 SQL 进程还没有执行。如果在 SQL 进程执行之前从节点服务停止,至少 I/O 进程已经从主节点拉取到了最新的变更并且保存在本地 relay log 中,当服务再次起来之后就可以完成数据的同步。要实施复制,首先必须打开 Master 端的 Binlog 功能,否则无法实现。因为整个复制过程实际上就是 Slave 从 Master 端获取该日志然后再在自己身上完全顺序的执行日志中所记录的各种操作。如下图所示:

六、数据复制的基本过程

  1. 在从节点上执行 sart slave 命令开启主从复制开关,开始进行主从复制。从节点上的 I/O 进程连接主节点,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容。
  2. 主节点接收到来自从节点的 I/O 请求后,通过负责复制的 I/O 进程(log Dump Thread)根据请求信息读取指定日志指定位置之后的日志信息,返回给从节点。返回信息中除了日志所包含的信息之外,还包括本次返回的信息的 Binlog file 以及 Binlog position(Binlog 下一个数据读取位置)。
  3. 从节点的 I/O 进程接收到主节点发送过来的日志内容、日志文件及位置点后,将接收到的日志内容更新到本机的 relay log 文件(Mysql-relay-bin.xxx)的最末端,并将读取到的 Binlog文件名和位置保存到master-info 文件中,以便在下一次读取的时候能够清楚的告诉 Master :“ 我需要从哪个 Binlog 的哪个位置开始往后的日志内容,请发给我”。
  4. Slave 的 SQL 线程检测到relay log 中新增加了内容后,会将 relay log 的内容解析成在能够执行 SQL 语句,然后在本数据库中按照解析出来的顺序执行,并在 relay log.info 中记录当前应用中继日志的文件名和位置点。

七、MySQL 基于 Binlog 主从复制的模式介绍

MySQL 主从复制默认是异步的模式。MySQL增删改操作会全部记录在 Binlog 中,当 slave 节点连接 master 时,会主动从 master 处获取最新的 Binlog 文件。并把 Binlog 存储到本地的 relay log 中,然后去执行 relay log 的更新内容。

  • 异步模式 (async-mode)

异步模式如下图所示:

这种模式下,主节点不会主动推送数据到从节点,主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理,这样就会有一个问题,主节点如果崩溃掉了,此时主节点上已经提交的事务可能并没有传到从节点上,如果此时,强行将从提升为主,可能导致新主节点上的数据不完整。

  • 半同步模式(semi-sync)

介于异步复制和全同步复制之间,主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收到并写到 relay log 中才返回成功信息给客户端(只能保证主库的 Binlog 至少传输到了一个从节点上),否则需要等待直到超时时间然后切换成异步模式再提交。

相对于异步复制,半同步复制提高了数据的安全性,一定程度的保证了数据能成功备份到从库,同时它也造成了一定程度的延迟,但是比全同步模式延迟要低,这个延迟最少是一个 TCP/IP 往返的时间。所以,半同步复制最好在低延时的网络中使用。半同步模式不是 MySQL 内置的,从 MySQL 5.5 开始集成,需要 master 和 slave 安装插件开启半同步模式。

  • 全同步模式

指当主库执行完一个事务,然后所有的从库都复制了该事务并成功执行完才返回成功信息给客户端。因为需要等待所有从库执行完该事务才能返回成功信息,所以全同步复制的性能必然会收到严重的影响。

八、基于docker搭建Mysql主从复制例子

  1. 下载mysql8.0版本
docker pull mysql:8.0
  1. 创建如下目录用于挂载
  • mydata/mysql/master
    master下编写my.conf
  • mydata/mysql/slave-1
    slave-1下编写my-slave-1.cnf
  • mydata/mysql/slave-2
    slave-2下编写my-slave-2.cnf

my.conf内容如下

[mysqld]
user=mysql
character-set-server=utf8
default_authentication_plugin=mysql_native_password
secure_file_priv=/var/lib/mysql
expire_logs_days=7
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
max_connections=1000[client]
default-character-set=utf8[mysql]
default-character-set=utf8

参考文章

  1. 执行容器命令如下
docker run \
--restart=always \
--privileged=true \
-p 13306:3306 --name mysql-master \
-v /mydata/mysql/master/log:/var/log/mysql \
-v /mydata/mysql/master/data:/var/lib/mysql \
-v /mydata/mysql/master/my.cnf:/etc/mysql/my.cnf \
-v /mydata/mysql/master/conf.d:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:8.0-------------------------------------------------------------
docker run \
--restart=always \
--privileged=true \
-p 23306:3306 --name mysql-slave-1 \
-v /mydata/mysql/slave-1/log:/var/log/mysql \
-v /mydata/mysql/slave-1/data:/var/lib/mysql \
-v /mydata/mysql/slave-1/my-slave-1.cnf:/etc/mysql/my.cnf \
-v /mydata/mysql/slave-1/conf.d:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:8.0--------------------------------------------
docker run \
--restart=always \
--privileged=true \
-p 33306:3306 --name mysql-slave-2 \
-v /mydata/mysql/slave-2/log:/var/log/mysql \
-v /mydata/mysql/slave-2/data:/var/lib/mysql \
-v /mydata/mysql/slave-2/my-slave-2.cnf:/etc/mysql/my.cnf \
-v /mydata/mysql/slave-2/conf.d:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:8.0

  1. master主从复制配置

在my.cnf中添加以下配置,注意添加到[mysqld]下面

#服务器id 留心各自的server-id一定要彼此独立,不能重复,否则,会出现如下错误:
#Slave: received end packet FROM server, apparent master shutdown
server_id=1#bing二进制日志文件
log-bin=mysql-bin#是否只读
read-only=0#要同步的数据库
binlog-do-db=test#不同步的数据库
binlog-ignore-db=ignore#以下是每个数据库都会自带的数据库,不需要复制
replicate-ignore-db=mysql
replicate-ignore-db=sys
replicate-ignore-db=information_schema
replicate-ignore-db=performance_schema

也分别在my-slave-1.cnf、my-slave-2.cnf配置以上信息(注意修改server_id),并重启docker

  1. 让master授权某一用户,让其他slave可以来同步master的数据

注意这里,8.0版本的mysql已经将用户的创建和授权分开了。

- CREATE USER 'backup'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
- GRANT REPLICATION SLAVE ON *.* TO 'backup'@'%';
  1. 让两台slave追寻主master
CHANGE MASTER TO MASTER_HOST='172.17.0.6',MASTER_USER='backup',MASTER_PASSWORD='123456',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=0,MASTER_PORT=3306;

这里一定要注意:由于我3个mysql都是基于docker的虚拟网络的,所以这里的MASTER_PORT不是暴露给外网的13306,而是基于docker局域网内的3306,如果遇到Slave_IO_Running:Connecting ; Slave_SQL_Running:Yes的问题,参考这两篇文章一定能解决,文章1,文章2。
注意这里的host不是简单的localhost,而是docker分配的

  • 启动同步:
start slave

  • 关闭同步
stop slave

至此,mysql主从同步搭建完成


可以看到master中的test同步到了slave中,而ignore则没有

九、主从复制可能会出现的问题

  1. Slave 同步延迟

因为 Slave 端是通过 I/O thread 单线程来实现数据解析入库;而 Master 端写 Binlog 由于是顺序写效率很高,当主库的 TPS 很高的时候,必然 Master 端的写效率要高过 Slave 端的读效率,这时候就有同步延迟的问题。I/O Thread 的同步是基于库的,即同步几个库就会开启几个 I/O Thread。可以通过 show slave status 命令查看 Seconds_Behind_Master 的值来看是否出现同步延迟,这个值代表主从同步延迟的时间,值越大说明延迟越严重。值为 0 为正常情况,正值表示已经出现延迟,数字越大从库落后主库越多。基于 Binlog 的复制方式肯定有这种问题,MySQL 官方也意识到,单线程不如多线程强,所以在 MySQL 5.7 版本引入了基于组提交的并行复制(官方称为Enhanced Multi-threaded Slaves,即MTS),设置参数:slave_parallel_workers>0 即可,并且 global.slave_parallel_type=‘LOGICAL_CLOCK’,即可支持一个 schema(库) 下,slave_parallel_workers个 worker 线程并发执行 relay log 中主库提交的事务。

  1. 其核心思想:

一个组提交的事务都是可以并行回放(配合binary log group commit);slave 机器的 relay log 中 last_committed 相同的事务(sequence_num不同)可以并发执行。其中,变量 slave-parallel-type 可以有两个值:

  • DATABASE 默认值,基于库的并行复制方式
  • LOGICAL_CLOCK,基于组提交的并行复制方式

MySQL 5.7 开启 MTS 很简单,只需要在 Slave 从数据库的 my.cnf 文件中如下配置即可:

# slaveslave-parallel-type=LOGICAL_CLOCKslave-parallel-workers=8        #一般建议设置4-8,太多的线程会增加线程之间的同步开销master_info_repository=TABLErelay_log_info_repository=TABLErelay_log_recovery=ON

当然多线程带来的并行复制方案也有很多实现难点,比如事务都是有序执行的,如果并行回放会不会存在执行数据错乱的问题。这些问题就不在本节解释,大家有兴趣可以继续深究。

参考文章

Mysql主从复制(docker例子)相关推荐

  1. 史上最详细Docker部署Mysql主从复制,带每一步骤图!!!

    没有夸大标题哈,能够成功的,实测后发文 本文主要讲怎么用Docker部署Mysql的主从复制,看起来很长,实际非常简单的,看一遍,立马就能懂的. 直接CV也能搭建起来,莫慌. 我们一起加油!!! 地点 ...

  2. 【MySQL】基于Docker的Mysql主从复制搭建

    基于Docker的Mysql主从复制搭建 为什么基于Docker搭建? 资源有限 虚拟机搭建对机器配置有要求,并且安装mysql步骤繁琐 一台机器上可以运行多个Docker容器 Docker容器之间相 ...

  3. 使用docker部署mysql主从复制集群

    一.环境搭建 虚拟机环境:centos7 IP:192.168.37.134 用户名:root 密码:123 启动3个容器,一个是master,端口是3307,另外两个是slaver,端口是3308和 ...

  4. docker mysql日志_面试官问:了解Mysql主从复制原理么?我呵呵一笑

    搭建Mysql主从同步之前,我们先来说他们之间同步的过程与原理: 同步复制过程 献上一张图,这张图诠释了整个同步过程 主从复制过程: slave节点与主节点进行连接,建立主从关系,并把从哪开始同步,及 ...

  5. 基于Docker的Mysql主从复制搭建_mysql5.7.x

    文章目录 为什么基于Docker搭建? 一.拉取镜像创建容器 1. 拉取mysql:5.7镜像 2. 创建master容器 3. 创建slave容器 4. 查看正在运行的容器 5. 此时可以使用Nav ...

  6. 借力 Docker ,三分钟搞定 MySQL 主从复制!

    hello 各位小伙伴大家好,今年 5 月份的时候,松哥和大家聊过如何搭建 MySQL 主从复制: 提高性能,MySQL 读写分离环境搭建(一) 提高性能,MySQL 读写分离环境搭建(二) 不过很多 ...

  7. win10 mysql 主从复制_win10 使用Docker配置mysql主从复制

    拉取镜像,我这里拉取5.6镜像 docker pull mysql:5.6.43 2.找一个目录编写主从库配置文件,这里我直接在上博客找的: (1)主库master.cnf文件: [mysqld] p ...

  8. Linux下基于 Docker 搭建 MySQL 主从复制(1 Master+2 Slave)

    1.准备环境 CentOS   7.2 64位 (CentOS-7-x86_64-DVD-1511.iso) MySQL   10.244.87.144/library/mysql5.7/centos ...

  9. 自动化部署mysql主从复制集群_使用docker部署mysql主从复制集群

    一.环境搭建 虚拟机环境:centos7 IP:192.168.37.134 用户名:root 密码:123 启动3个容器,一个是master,端口是3307,另外两个是slaver,端口是3308和 ...

最新文章

  1. IDEA热部署基于maven的web项目
  2. UVA122 树的层次遍历 Trees on the level(两种方法详解)
  3. Node.js建立服务、路径处理与响应
  4. Windows的cmd ping不通vmware的linux系统ip
  5. 关于什么事情能做到和不能做到的思考
  6. [云炬创业学笔记]第二章决定成为创业者测试2
  7. 开发板、Windows、Ubuntu三者互联——韦东山嵌入式Linux学习笔记08
  8. SAP Fiori + Vue = ? 1
  9. springboot---成员初始化顺序
  10. mysql table alter_MySQL-ALTER TABLE命令学习[20180503]
  11. VS2012无法安装cocos2d-x-2.1.4 解决方法及VS2012新建coco2d-x项目(一)
  12. Android开发笔记(九十七)图片的特效处理
  13. 推荐8款Windows装机必备下载神器【建议收藏】
  14. visio画图复制粘贴到word_Visio 2010怎么复制图片 Visio粘贴图形到其它office程序
  15. 解决input获取焦点后,旁边文字抖动问题
  16. Python强化知识之获取网络资源 Urllib(一)
  17. 通达信精确逃顶主图指标
  18. “漏洞百出”的智能音箱,为何能“发大财”?
  19. unity3d新手笔记
  20. qt QtUdpSocket

热门文章

  1. SQL Server事务回滚对自增键的影响
  2. WPF中的Bitmap与byte
  3. hibernate主配置文件的配置
  4. 特征工程中的IV和WOE详解
  5. linux下,MySQL默认的数据文档存储目录为/var/lib/mysql。
  6. 给自己的Unity添加声音文件
  7. 优先队列的数组实现(有序)
  8. Git学习笔记:远程仓库
  9. 操作系统安装与优化:chapter8 虚拟机
  10. html传递json中文乱码,解决后台传数据到前台中文乱码问题,使用@ResponseBody返回json 中文乱码...