来学习一下mysql的主从复制, 顺便将docker 的知识点也复习一下, 来一个基于docker的mysql 8.0 主从复制.

主从复制的基本介绍

为什么需要主从复制?

1.在业务 复杂的系统中, 有这么一个情景, 有一句sql 语句需要锁表, 导致暂时不能使用读的服务, 那么就很影响运行中的业务.使用主从复制, 让主库负责写, 从库负责读, 这样, 即使主库出现了锁表的情况, 通过读从库也可以保证业务的正常运行.
2.做 数据的 热备.
3.架构的扩展. 业务量越来越大, I/O 访问频率过高,单机无法满足, 此时做多库的存储, 降低磁盘I/O 访问的频率, 提高单个机器的I/O 性能.

什么是mysql 的主从复制

mysql主从复制是指数据可以从一个mysql 数据库服务器主节点复制到一个或者多个从节点. Mysql 默认采用异步复制方式.这样从节点不用一直访问主服务器来更改自己 的数据, 数据 的 更新可以在远程连接上进行, 从节点可以复制主数据库中的所有数据库或者特定的 数据库,或者待定的表.

mysql 复制原理

(1) master 服务器将数据的改变记录二进制 binlog 日志, 当master 上的数据发送 改变时,则将其改变写入二进制日志中;
(2)slave 服务器会在一定时间间隔内对master 二进制日志对其进行探测是否发生 改变, 如果 发生改变,则开始 一个 I/O Thread 请求master 二进制事件;
(3)同时主节点为每个I/O 线程启动一个 dump 线程, 用于向其发送二进制事件, 并保存至从节点本地的中继日志中, 从节点将启动SQL 线程从中继日志中读取二进制日志,在本地存放, 使其数据和主节点的保持一致, 最后 I/O Thread 和sql Thread 将进入睡眠状态,等待下一次被唤醒.
也就是说:
从库会生成 两个线程,一个IO 线程, 一个SQL 线程;
I/O线程会去请求主库的binlog, 并将得到的binlog 写到本地的relay-log(中继日志) 文件中;
主库会 生成一个logdump , 用来给从库 I/O 线程传 binlog ;
从库的SQL 线程,会去读relay log 文件中 的 日志,并解析成 sql 语句逐一执行.

mysql 主从复制原理图

mysql主从复制原理图

注意事项

  1. Master 将操作语句记录到binlog 日志中, 然后 授予salve远程连接的权限(master 一定要开启binlog 二进制日志功能; 通常为了数据安全考虑, salve 也开启binlog 功能);
  2. salve 开启两个 线程; io 线程和sql 线程. 其中 io 线程负责 读取master 的binlog 内容到中继日志 relay log 里; sql 线程负责将relay log 日志里读出binlog内容,并更新 到slave 的数据库里, 这样就能保证slave 数据和master 数据一致了.
  3. mysql 复制至少需要两个mysql的服务, 当然mysql 的服务可以分布在不同的服务器上, 也可以 在一台服务器上 启动多个服务.
  4. Mysql 复制最好确保master 和salve 服务器上的mysql 版本相同.( 如果不能满足版本一致, 那么要确保master 主节点的版本低于slave 从节点的版本.)
    master 和salve 两节点 时间需同步.

    基于docker 的mysql8.0 容器的主从复制

    前置步骤: 用docker 下载mysql 的镜像, 并启动两个mysql 容器实例(要用到数据卷).
    启动mysql容器的命令, 可做参考,配置 文件一定要做成数据卷共享, 其他的随你.
    1
    2
    3
    docker run -p 12345:3306 --name mysql -v /你指定的目录/mysql/conf:/etc/mysql/conf.d -v /你指定的目录/mysql/logs:/logs -v /你指定的目录/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=money -d mysql:5.6
    这里你指定的目录, 如果已经存在就会引用, 不存在就会新建. 这里是把mysql容器内的配置文件,日志文件和数据存储文件做成数据卷,和宿主机进行共享.
    docker run -p 6666:3306 --name mysql -v /你指定的目录/mysql2/conf:/etc/mysql/conf.d -v /你指定的目录/mysql2/logs:/logs -v /你指定的目录/mysql2/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=money -d mysql:5.6
    需求: 把其中一个mysql 容器作为mysql 的主服务器, 另一个容器作为mysql 的从服务器容器.

    步骤一:

    用docker 查看容器 ip ;
    然后我就获取到了 两个mysql 容器的ip, 主机的是172.18.0.3, 从机的 是172.18.0.4(你的可能不一样,自己记录下来即可)

    步骤二:

    在mysql 主容器里, mysql -h ip -uroot -p密码 去试试能不能 连接从服务器的mysql.
    mysql -h 172.18.0.4 -uroot -pmoney 这个-p 和密码不能 断开,不然会被要求填写密码并密码连接成功后显示没有这个断开的密码同名的仓库名.
    所以-p 后面要么不写密码, 要么就不要断开.
    能连接上之后,就去从服务器上, mysql -h ip -uroot -p密码 来连接主服务器的mysql .
    这两个服务器之间能够 互通之后, 就可以进行下一步了.

    步骤三:

    在mysql 容器 的这个文件里, 是没有配置文件的,需要我们自己手动创建一个自定义的配置文件.
    我们在那个自己指定 的目录下的 mysql/conf/ 这里(主服务器), 自己创建一个自定义的配置文件, 创建了一个mysql.cnf 文件并填写如下.
    1
    2
    3
    4
    [mysqld]
    server-id=1
    log-bin=mysql-bin

    id=1是主线程的意思. msyqld是服务端的配置的意思.
    然后我们去从服务器的配置文件下创建自定义配置文件并配置 它.(去到 自己指定的目录下的mysql2/conf/) 我这里也是创建一个mysql.cnf
    1
    2
    [mysqld]
    server-id=2
    要记住此时配置的服务id , 不能和主服务器的一样, 一般比主服务器大就可以.
    这个时候, 就需要重启这两个mysql 容器, docker restart 容器ID .

    步骤四:

    去到mysql 主服务器的容器里, docker exec -it mysql 主服务器的容器ID /bin/bash
    然后执行 show master status\G; (如果你是用navicat直接连接mysql 的话, 就不需要用 \G, 不然会报错的).
    记录下查询结果里的两个字段值, file 和 position .

    步骤五:

    去到mysql 从服务器的容器里, docker exec -it mysql 从服务器的容器ID /bin/bash (或者直接用navicat 连接就不用进去容器里)
    在从 服务器的mysql 里, 执行 如下的命令
    1
    2
    change master to master_host = '你个人的mysql主服务器ip' , master_user='root', master_password='money', 
    master_log_file = '你查出来的主服务器的file 字段的值', master_log_pos = 你查出来的主服务器的postion 值;
    然后就是 start slave; 和 show slave status ;
    但是发现 有个小问题, 只看到了一个yes ,没有看到两个yes .(如果你不是mysql8.0 的话,此时应该能看到两个yes),出现问题的原因mysql 8.0 的安全连接校验.

    步骤六:

    解决mysql8.0 的安全校验, 将其改回旧版本的安全校验方式.
    解决方式:
    只要主从服务器都是use mysql 之后, 使用这个alter table 的语句,然后用 flush privileges; 即可(就是主服务器, 从服务器都要做一次).
    1
    2
    use mysql;
    alter user 'root'@'%' IDENTIFIED with mysql_native_password BY 'money';
    现在就需要重启两个mysql容器.

    步骤七:

    然后去到从服务器上, 使用show slave status ; 来查看, 已经看到两个yes 了.
    为了保险, 还有个验证.
    1
    show  VARIABLES like 'server_id';  通过 它来看server_id , 主服务器是 1 , 从 服务器是2(我自己指定的是2)

    步骤八:

    此时就可以在主服务器上, 新建 数据库,表, 插入 数据了. 然后就去从服务器上去查询.