资讯专栏INFORMATION COLUMN

Mysql主从同步原理

macg0406 / 2901人阅读

摘要:主从同步原理在服务器上执行命令开启主从复制开关,开始进行主从复制。架构的优化当用户完全掌握了如何基于搭建主从集群后,可以自己尝试,专门创建一个节点,作为数据同步节点使用。其他节点从数据同步节点来同步数据。

Mysql主从同步原理

1)在Slave 服务器上执行sart slave命令开启主从复制开关,开始进行主从复制。

2)此时,Slave服务器的IO线程会通过在master上已经授权的复制用户权限请求连接master服务器,并请求从执行binlog日志文件的指定位置(日志文件名和位置就是在配置主从复制服务时执行change master命令指定的)之后开始发送binlog日志内容。

3)Master服务器接收到来自Slave服务器的IO线程的请求后,其上负责复制的IO线程会根据Slave服务器的IO线程请求的信息分批读取指定binlog日志文件指定位置之后的binlog日志信息,然后返回给Slave端的IO线程。返回的信息中除了binlog日志内容外,还有在Master服务器端记录的IO线程。返回的信息中除了binlog中的下一个指定更新位置。

4)当Slave服务器的IO线程获取到Master服务器上IO线程发送的日志内容、日志文件及位置点后,会将binlog日志内容依次写到Slave端自身的Relay Log(即中继日志)文件(Mysql-relay-bin.xxx)的最末端,并将新的binlog文件名和位置记录到master-info文件中,以便下一次读取master端新binlog日志时能告诉Master服务器从新binlog日志的指定文件及位置开始读取新的binlog日志内容。

5)Slave服务器端的SQL线程会实时检测本地Relay Log 中IO线程新增的日志内容,然后及时把Relay LOG 文件中的内容解析成sql语句,并在自身Slave服务器上按解析SQL语句的位置顺序执行应用这样sql语句,并在relay-log.info中记录当前应用中继日志的文件名和位置点。

Mysql主从同步注意事项

master节点和slave节点的uuid不同

master节点和slave节点的server_id不同

slave节点需要自动执行向master节点注册的操作

制作Mysql容器镜像

同一镜像创建不同容器的uuid

用同一mysql镜像创建mysql主从集群时,发现每台mysql服务的uuid都是相同的,是因为在数据初始化时将uuid写在了/var/lib/mysql/auto.cnf文件中,造成每个容器的uuid都是相同的。

为了解决不同容器的uuid不同问题,需要在mysql启动生成配置文件后并在启动前 随机生成一个uuid写入到/var/lib/mysql/auto.cnf,这样就可以确保同一镜像生成的容器的uuid都不相同。

为了达成这一目标,我们修改了mysql镜像自带的启动脚本/usr/local/bin/docker-entrypoint.sh:

if [ ! -d "$DATADIR/mysql" ]; then
        file_env "MYSQL_ROOT_PASSWORD"
        if [ -z "$MYSQL_ROOT_PASSWORD" -a -z "$MYSQL_ALLOW_EMPTY_PASSWORD" -a -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
            echo >&2 "error: database is uninitialized and password option is not specified "
            echo >&2 "  You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD"
            exit 1
        fi

        mkdir -p "$DATADIR"

        echo "Initializing database"
        "$@" --initialize-insecure
        echo "Database initialized"
                # 位于mysql启动脚本90行,新增如下语句
                psd="/proc/sys/kernel/random/uuid"
                str=$(cat $psd)
                uuid="server-uuid="${str}
                echo "[auto]" > /var/lib/mysql/auto.cnf
                echo $uuid >> /var/lib/mysql/auto.cnf


同一服务不同实例的server_id处理

用同一MYSQL镜像创建MYSQL主从集群时,如何确保每个MYSQL服务的server_id不同?

k8s在创建容器时,会为每个容器创建创建一个主机名( 如:gr78648d-0),创建多个容器后面的数字会依次递增,所以可以利用这一特性生成不同的server_id(主机名数字部分 + 指定数字),然后在maser和slave使用不同的数字即可。

从库自动初始化

创建slave数据库时,我们希望salve应用下的每个实例,在扩容后,会自动向主库注册。

这需要salve应用中实例初始化时,自动执行指定的SQL脚本。这要借助于官方MYSQL镜像所提供的特定功能:数据库初始化时,会自动读取/docker-entrypoint-initdb.d/中*.sql 文件并执行。

为了实现上述两个目标,我们在镜像的自定义启动脚本 /run/docker-entrypoint.sh进行指定:

# define server_id and anyother cluster configuration
# 通过环境变量来区分当前镜像创建主库或从库
if [ ${MYSQL_ROLE} == "master" ];then
   # 借助有状态应用主机名特点,截取其中的数字
   server_id=${HOSTNAME#*-}
   # 主库ID设置为1
   MYSQLC_MYSQLD_SERVER_ID=`expr $server_id + 1`
   export MYSQLC_MYSQLD_SERVER_ID
   # 指定生成主库特定的配置
   export MYSQLC_MYSQLD_binlog_ignore_db=mysql
   export MYSQLC_MYSQLD_log_bin=mysql-bin
else 
   # 借助有状态应用主机名特点,截取其中的数字
   server_id=${HOSTNAME#*-}
   # 从库各实例ID,从2开始排序
   MYSQLC_MYSQLD_SERVER_ID=`expr $server_id + 2`
   export MYSQLC_MYSQLD_SERVER_ID
   # 指定生成从库特定配置
   export MYSQLC_MYSQLD_replicate_ignore_db=mysql
   export MYSQLC_MYSQLD_log_bin=mysql-bin
   # 将从库所需要的初始化脚本模版拷贝到指定目录
   cp -a /tmp/init-slave.sql /docker-entrypoint-initdb.d/
   # 根据实例特定的环境变量,对初始化脚本模版进行更改
   sed -i -r -e "s/MYSQL_ROOT_PASSWORD/${MYSQL_ROOT_PASSWORD}/g" 
             -e "s/MYSQL_USER/${MYSQL_USER}/g" /docker-entrypoint-initdb.d/init-slave.sql
fi


关于脚本中通过环境变量生成指定配置,参考项目 env2file

制作镜像的Dockerfile解析

FROM percona:5.7.23-stretch
LABEL creater="barnett"
ENV MYSQL_VERSION=5.7.23
ENV TZ=Asia/Shanghai

RUN sed -i "s/deb.debian.org/mirrors.ustc.edu.cn/g" /etc/apt/sources.list; 
    rm -rf /etc/apt/sources.list.d/percona.list && apt-get update; 
    apt-get install -y --no-install-recommends wget net-tools vim; 
    rm -rf /var/lib/apt/lists/*; 
    wget -O /usr/local/bin/env2file -q https://github.com/barnettZQG/env2file/releases/download/0.1.1/env2file-linux; 
    chmod +x /usr/local/bin/env2file;
# 自定义启动脚本
ADD docker-entrypoint.sh /run/docker-entrypoint.sh
# mysql官方启动脚本
ADD ./run/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
ADD ./run/mysqld.cnf /etc/mysql/percona-server.conf.d/mysqld.cnf
# 拷贝slave初始化脚本模版到镜像中,以备调用
ADD ./sql /tmp/
EXPOSE 3306
VOLUME ["/var/lib/mysql", "/var/log/mysql"]
ENV MYSQL_ROOT_PASSWORD=changeme
ENTRYPOINT [ "/run/docker-entrypoint.sh" ]
CMD [ "mysqld" ]

创建并配置mysql-master服务

创建mysql-master服务组件

代码地址:https://github.com/goodrain-a...

代码分支:cluster

通过Dockerfile创建服务 参考文档 基于Dockerfile源码创建服务

mysql-master服务 相关配置

开启3306端口对内服务,并更改使用别名为MYSQL

配置关键环境变量

环境变量 值 说明
MYSQL_ROOT_PASSWORD changeme(默认)自行指定 root密码
MYSQL_USER 自行指定,如admin mysql工作用户
MYSQL_PASSWORD 自行指定 工作用户密码
MYSQL_DATABASE 自行指定 初始化生成数据库
MYSQL_ROLE master 指定角色

其中 除MYSQL_ROLE外,其他环境变量要在服务创建完成后,转移到连接信息中去。

部署属性中,修改应用类型为 有状态应用

创建Slave服务

创建mysql-slave服务组件

创建方式同mysql-master服务组件一致。

mysql-slave服务 相关配置

区别于mysql-master服务组件,mysql-slave服务组件配置如下:

开启3307端口对内服务,并更改使用别名为 MYSQL_SLAVE

配置环境变量

环境变量 值 说明
MYSQLC_MYSQLD_PORT 3307 mysql-slave监听3307端口

mysql-slave服务依赖于mysql-master服务

mysql-slave服务组件,可以随意扩容,脚本中写好的逻辑会让其自动向mysql-master注册。

至此,一个基本的 MYSQL主从集群就已经搭建完成,如需要发布到应用市场供随时下载使用,请参考应用分享与发布

读写分离

机制

MYSQL主从集群的一个好处就是,可以配置master库负责写入,slave库负责查询,slave自动从master同步数据的读写分离结构。

如果设置得当,这样的结构可以大幅度提高数据库性能的同时,降低主库的压力。

使用方法

如果用户的业务程序已经支持读写分离,那么只需要设置:

数据库写入地址为mysql-master服务地址,如果使用Rainbond服务依赖,则可以用 ${MYSQL_HOST}:${MYSQL_PORT}的方式指定连接地址。

数据库查询地址为mysql-slave服务地址,如果使用Rainbond服务依赖,则可以用${MYSQL_SLAVE_HOST}:${MYSQL_SLAVE_PORT}的方式指定连接地址。

如果用户的业务程序不支持读写分离,那么就要靠支持读写分离的中间件实现。

Atlas中间件

Atlas是由奇虎360开源的数据库中间件,基于mysql官方提供的mysql-proxy改良而来。通过将mysql-proxy的LUA脚本,用C语言重新实现,Atlas提供了比mysql-proxy更强大的性能。经由中间件的代理,用户只需要配置数据库连接地址为 Atlas 服务地址,对于数据库的写入和查询,则由 Atlas 来管理。

详细了解Atlas

我们提供的docker化的Atlas组件,用户可以直接基于Dockerfile源码构建这个项目:

Atlas-docker项目地址

Rainbond已经发布的 Mysql主从集群 应用,已经集成了该中间件。

高阶实现

当前架构缺点

目前搭建的 MYSQL主从集群,是一个master节点,对接多个slave节点。这样的架构在小规模集群下没有问题。但是如果集群规模很大、slave节点过多的时候,由master向所有slave节点同步数据这一过程将变成性能的瓶颈。

架构的优化

当用户完全掌握了如何基于Rainbond搭建MYSQL主从集群后,可以自己尝试,专门创建一个slave节点,作为数据同步节点使用。

该节点向上对接 master节点,来同步数据;向下对接slave集群,分发由master节点同步来的数据。

这样做的好处是,master节点只需要对接一个数据同步节点来同步数据,可以更加专注于数据的写入。其他slave节点从数据同步节点来同步数据。

如果有用户实现了这种优化,欢迎将其分享到应用市场中,供更多的人来使用。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/110665.html

相关文章

  • Mysql主从同步原理

    摘要:主从同步有什么好处水平扩展数据库的负载能力。主从同步的原理是什么首先我们来了解的体系结构。如此,就实现了主从同步了下面我们来详细的了解。在机器上的操作当主从同步开启的时候,上会创建个线程。 关于实战,请参考我的另一篇文章:Mysql主从同步实战 1、什么是mysql主从同步? 当master(主)库的数据发生变化的时候,变化会实时的同步到slave(从)库。 2、主从同步有什么好处...

    Achilles 评论0 收藏0
  • MySQL主从数据库同步延迟问题解决

    摘要:数据库主从同步延迟解决方案。数据库主从同步延迟解决方案答最简单的减少同步延时的方案就是在架构上做优化,尽量让主库的快速执行。原理和丁奇的类似,丁奇的是以表做多线程,使用的是以数据库为单位做多线程,不同的库可以使用不同的复制线程。 MySQL的主从同步是一个很成熟的架构,优点为:①在从服务器可以执行查询工作(即我们常说的读功能),降低主服务器压力;②在从主服务器进行备份,避免备份期间影响...

    mingde 评论0 收藏0
  • 面试官:咱们来聊一聊mysql主从延迟

    摘要:编辑器编辑器背景编辑器前段时间遇到一个线上问题,后来排查好久发现是因为主从同步延迟导致的,所以今天写一篇文章总结一下这个问题希望对你有用。编辑器几句唠叨编辑器大家好,我是小饭,一枚后端工程师。背景前段时间遇到一个线上问题,后来排查好久发现是因为主从同步延迟导致的,所以今天写一篇文章总结一下这个问题希望对你有用。如果觉得还不错,记得加个关注点个赞哦思维导图思维导图常见的主从架构随着日益增长的访...

    EasonTyler 评论0 收藏0
  • mysql 主从分离原理及mycat配置

    摘要:在事件写入二进制日志完成后,通知存储引擎提交事务。从线程处理该过程的最后一步。线程从中继日志读取事件,并重放其中的事件而更新的数据,使其与中的数据一致。参数说明选项有四个可用值,分别为,,,。 1.1 mysql支持的复制类型:   基于语句的复制:在主服务器上执行的SQL语句,在从服务器上执行同样的语句。MySQL默认采用基于语句的复制,效率比较高。一旦发现没法精确复制时,会自动选...

    fengxiuping 评论0 收藏0
  • XtraBackup不停机不锁表搭建MySQL主从同步实践

    摘要:当然我们在实际运维过程中都应针对不同的业务需求分析和选择合适的备份恢复方案,这篇文章就是针对多实例且一个实例对应多个的情况,实现在线不停机不锁表的主从同步,日后再继续更新分享基于的其它实用技能。 showImg(//i.v2ex.co/02ftb7pa.jpeg); 前言 Percona XtraBackup可以说是一个相对完美的免费开源数据备份工具,支持在线无锁表同步复制和可并行...

    dreamtecher 评论0 收藏0

发表评论

0条评论

macg0406

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<