美文网首页PHP经验分享编什么程
基于Docker的Mysql主从复制搭建,实现读写分离

基于Docker的Mysql主从复制搭建,实现读写分离

作者: 沙蒿同学 | 来源:发表于2020-02-19 15:51 被阅读0次
    此图借用的

    在之前的教程中docker搭建LNMP环境(php-fpm)后,我将自己的项目部署上去,虽然阿里服务器是9.9买的,但还算是能撑得起本人的折腾。今天在准备面试的时候看到一道关于mysql主从复制的题目。

    请问MySQL的复制原理以及流程,三个线程是怎么回事?他们之间怎么关联?

    因为在日常开发过程中,很多关于框架、架构、技术选型等上一层的难点技术点大佬们都之前帮我们确定或部署完毕了,很多同学在这种情况下一般都只剩下CRUD的工作,枯燥无味还没提升空间。
    虽然一年前刚出来工作的时候看过这道题目,也知道大致的答案(可查看最下方参考链接),但还真没自己去部署并实现,今天弄一弄吧。

    简单看了下教程,其实就是配置一下mysql,然后项目代码中配置一下主从数据库的连接信息。所以打算在原阿里服务器docker部署的php-fpm上做下修改,主要看下mysql-master和mysql-slave。

    docker-compose.yml

    version: "3"
    services:
      nginx:
        image: nginx:latest
        container_name: nginx
        ports:
          - "80:80"
        links:
          - php
        volumes:
          - ./code:/code  #创建项目根目录
          - ./nginx/conf.d:/etc/nginx/conf.d
          - ./nginx/nginx.conf:/etc/nginx/nginx.conf
          - ./nginx/logs:/var/log/nginx
      mysql-master:
        image: mysql:5.7
        container_name: mysql-master
        restart: always
        command: --default-authentication-plugin=mysql_native_password
        volumes:
          - /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime
          - ./mysql-master/data:/var/lib/mysql:rw #创建 /data/myql 目录
          - ./mysql-master/logs:/var/lib/mysql-logs:rw  # /logs/mysql 目录
          - ./mysql-master/conf.d:/etc/mysql/conf.d:ro # /mysql/conf.d 目录
          - ./mysql-master/my.cnf:/etc/mysql/my.cnf # /etc/mysql/my.conf 目录
        ports:
          - "33307:3306"
        links:
          - mysql-slave
        environment:
          MYSQL_USER: root
          MYSQL_PASSWORD: sdkhf1231!%$@%  #你的密码,稍微复杂点哦
          MYSQL_ROOT_PASSWORD: sdkhf1231!%$@%  #你的密码,稍微复杂点哦
        hostname: mysql-master
      mysql-slave:
        image: mysql:5.7
        container_name: mysql-slave
        restart: always
        command: --default-authentication-plugin=mysql_native_password
        volumes:
          - /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime
          - ./mysql-slave/data:/var/lib/mysql:rw #创建 /data/myql 目录
          #- ./mysql-slave/logs:/var/lib/mysql-logs:rw  # /logs/mysql 目录
          #- ./mysql-slave/conf.d:/etc/mysql/conf.d:ro # /mysql/conf.d 目录
          - ./mysql-slave/my.cnf:/etc/mysql/my.cnf # /etc/mysql/my.conf 目录
        ports:
          - "33308:3306"
        environment:
          MYSQL_USER: root
          MYSQL_PASSWORD: sdkhf1231!%$@%  #你的密码,稍微复杂点哦
          MYSQL_ROOT_PASSWORD: sdkhf1231!%$@%  #你的密码,稍微复杂点哦
        hostname: mysql-slave
      php:
        build: .
        container_name: fpm7.1
        ports:
          - "9000:9000"
        working_dir: /code
        volumes:
          - /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime
          - ./code:/code
        hostname: php
    

    主数据库mysql-master的/etc/mysql/my.cnf 配置为,详见注释

    [mysqld]
    ## 设置server_id,一般设置为IP,注意要唯一
    server_id=100
    ## 复制过滤:也就是指定哪个数据库不用同步(mysql库一般不同步)
    binlog-ignore-db=mysql
    ## 开启二进制日志功能,可以随便取,最好有含义(关键就是这里了)
    log-bin=replicas-mysql-bin
    ## 为每个session分配的内存,在事务过程中用来存储二进制日志的缓存
    binlog_cache_size=1M
    ## 主从复制的格式(mixed,statement,row,默认格式是statement)
    binlog_format=mixed
    ## 二进制日志自动删除/过期的天数。默认值为0,表示不自动删除。
    expire_logs_days=7
    ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
    ## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
    slave_skip_errors=1062
    
    !includedir /etc/mysql/conf.d/
    !includedir /etc/mysql/mysql.conf.d/
    
    

    从数据库mysql-slave的/etc/mysql/my.cnf 配置为,详见注释

    [mysqld]
    ## 设置server_id,一般设置为IP,注意要唯一
    server_id=101
    ## 复制过滤:也就是指定哪个数据库不用同步(mysql库一般不同步)
    binlog-ignore-db=mysql
    ## 开启二进制日志功能,以备Slave作为其它Slave的Master时使用
    log-bin=replicas-mysql-slave1-bin
    ## 为每个session 分配的内存,在事务过程中用来存储二进制日志的缓存
    binlog_cache_size=1M
    ## 主从复制的格式(mixed,statement,row,默认格式是statement)
    binlog_format=mixed
    ## 二进制日志自动删除/过期的天数。默认值为0,表示不自动删除。
    expire_logs_days=7
    ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
    ## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
    slave_skip_errors=1062
    ## relay_log配置中继日志
    relay_log=replicas-mysql-relay-bin
    ## log_slave_updates表示slave将复制事件写进自己的二进制日志
    log_slave_updates=1
    ## 防止改变数据(除了特殊的线程)
    read_only=1
    
    !includedir /etc/mysql/conf.d/
    !includedir /etc/mysql/mysql.conf.d/
    
    

    执行“docker-compose up -d”,服务正常启动。(如果出现端口、ip等冲突的问题就自己谷歌解决)

    image.png

    进入mysql-master容器,执行“docker exec -it mysql-master /bin/bash”,进入mysql数据库,执行“show master status;”,可以看到主数据库 binary-log 的 文件名称 和 数据同步起始位置。(请记住它,下面会用到)


    image.png

    退出,切换进入到mysql-slave容器从数据库,执行命令

    CHANGE MASTER TO
        MASTER_HOST='mysql-master',
        MASTER_USER='root',
        MASTER_PASSWORD='sdkhf1231!%$@%',
        MASTER_LOG_FILE='replicas-mysql-bin.000021',
        MASTER_LOG_POS=1305;
    

    字段说明:

    MASTER_HOST:Master的地址,这里我们命名为mysql-master
    MASTER_PORT:Master的端口号,指的是容器的端口号
    MASTER_USER:用于数据同步的用户
    MASTER_PASSWORD:用于同步的用户的密码
    MASTER_LOG_FILE:指定 Slave 从哪个日志文件开始复制数据,即上文中提到的 File 字段的值
    MASTER_LOG_POS:从哪个 Position 开始读,即上文中提到的 Position 字段的值
    MASTER_CONNECT_RETRY:如果连接失败,重试的时间间隔,单位是秒,默认是60秒

    然后开启主从复制过程,执行“start slave status\G;”


    image.png

    然后用navicat连接两个端口的mysql,在33307上创建一个test的库并创建一个test的表来测试一下是否配置完成。


    image.png

    项目代码修改

    项目使用的是fastadmin框架来进行二次开发的,现修改database.php配置,当然根据自己的项目情况来确定是否使用主从读写分离,配置也是不一样的。

    <?php
    use think\Env;
    return [
        // 数据库类型
        'type'            => Env::get('database.type', 'mysql'),
        // 服务器地址
        'hostname'        => Env::get('database.hostname', 'xx.xx.xx.xx') . ',' . Env::get('database-slave.hostname', 'xx.xx.xx.xx'),
        // 数据库名
        'database'        => Env::get('database.database', 'xxx') . ',' . Env::get('database-slave.database', 'xxx'),
        // 用户名
        'username'        => Env::get('database.username', 'root') . ',' . Env::get('database-slave.username', 'root'),
        // 密码
        'password'        => Env::get('database.password', 'xxx') . ',' . Env::get('database-slave.password', 'xxx'),
        // 端口
        'hostport'        => Env::get('database.hostport', 'xxx') . ',' . Env::get('database-slave.hostport', 'xxx'),
        // 连接dsn
        'dsn'             => '',
        // 数据库连接参数
        'params'          => [],
        // 数据库编码默认采用utf8
        'charset'         => Env::get('database.charset', 'utf8'),
        // 数据库表前缀
        'prefix'          => Env::get('database.prefix', 'st_'),
        // 数据库调试模式
        'debug'           => Env::get('database.debug', true),
        // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
        'deploy'          => Env::get('database.deploy', 0),
        // 数据库读写是否分离 主从式有效
        'rw_separate'     => Env::get('database.rw_separate', false),
        // 读写分离后 主服务器数量
        'master_num'      => 1,
        // 指定从服务器序号
        'slave_no'        => '',
        // 是否严格检查字段是否存在
        'fields_strict'   => true,
        // 数据集返回类型
        'resultset_type'  => 'array',
        // 自动写入时间戳字段
        'auto_timestamp'  => false,
        // 时间字段取出后的默认时间格式,默认为Y-m-d H:i:s
        'datetime_format' => false,
        // 是否需要进行SQL性能分析
        'sql_explain'     => false,
    ];
    

    参考博主:Mysql的复制原理以及流程Docker Compose搭建MySQL主从复制集群ThinkPHP实现读写分离

    相关文章

      网友评论

        本文标题:基于Docker的Mysql主从复制搭建,实现读写分离

        本文链接:https://www.haomeiwen.com/subject/hreafhtx.html