GreatSQL 异步复制及搭建

文摘   科技   2024-09-11 08:00   福建  

* GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。

一、简介

复制就是将一个数据库数据复制到一个或多个数据库上,复制的过程是异步的,其工作原理是通过binlog(二进制日志)记录事务变更然后传送到从库并重放事务,保持数据一致

二、复制过程

1-1 复制过程图

2.1 binlog日志

GreatSQL 复制是基于 binlog 日志来实现复制的

2.1.1 二进制日志输出格式比较

二进制日志格式记录内容主从同步使用场景大小性能
statement基于SQL如果使用了一些不确定性的函数和自定义函数,函数返回的数据在主从库上不一致。比如 now(),last_insert_id()等。较小最好
row基于数据行默认使用基于row较大最差
mixed混合格式默认使用statement。当statement无法正确复制时,采用rows
居中

2.2 复制过程

  1. 主库把数据更新事件写入二进制日志。

  2. 从库的IO线程向主库请求二进制日志事件。

  3. 主库的binlog dump线程向从库IO线程发送二进制日志事件。

  4. 从库的IO线程将二进制日志事件写入中继日志。

  5. 从库的SQL线程应用中继日志中的事件。

2.3 二阶段提交

GreatSQL 包含两种记录数据变更的日志,redolog、binlog为了保证两个日志的对数据变更事件达到一致性,GreatSQL 内部使用XA来实现,其核心是两阶段提交。

2.3.1 事务提交流程

主从复制中,从库是通过binlog日志重放来实现复制。如何保证主从的数据一致性,就需要考虑如下两方面

  1. binlog记录的事务一定不比redolog少。

  2. binlog与redolog记录的事务的顺序性是一致的。

在两阶段协议中一般分为事务管理器(协调者)和若干事务执行器(参与者)两种角色。GreatSQL 内部实现的两阶段提交中,二进制日志充当了协调组角色,由它来通知InnoDB执行准备、提交和回滚。从实现角度分析,事务提交有准备阶段和提交阶段组成。两阶段提交流程如下图:

1-2事务提交流程

1、事务发起commit请求。

2、调用binlog-hton和innobase-hton的prepare方法完成第一阶段。binlog-hton的方法什么也没有做,innodb的prepare持有prepare_commit_mutex锁,将重做日志刷盘,并将事务状态设置为prepared。

3、如果事务涉及的所有存储引擎的prepare都执行成功,则调用TC_LOG_BIN:log_xid将事务写入到二进制日志。

4、最后,调用存储引擎的commit完成事务的提交,向重做日志写入commit标记,释放prepare_commit_mutex,并将事务设置为trx_not_started状态。

2.3.2 InnoDB恢复

数据库在奔溃恢复时,不同状态的事务,会进行不同的处理。

  • trx_commit_in_memory的事务,清除回滚段后,将事务设置为trx_commit_not_started。

  • trx_commit_active的事务,直接回滚。

  • trx_not_started的事务,表示事务已提交过,跳过。

  • trx_commit_prepared的事务,要根据二进制日志来决定事务是否提交,暂时跳过。

在数据库发生奔溃时,数据库根据重做日志进行数据恢复,逐个检查重做日志的每个事务状态。根据1-2的流程,如果已经进行到trx_not_started阶段,也就是存储引擎commit阶段,那么说明重做日志和二进制日志是一致的,正常根据重做日志的内容进行恢复即可。如果事务状态为trx_active,没有写入到二进制日志,就直接回滚。如果事务状态为trx_commit_prepared,要分两种情况:先检查二进制日志是否写入成功,如果没有写入成功,直接回滚,如果写入成功了,那就进行最后一步,调用存储引擎commit,更改事务状态为trx_not_started,也就是真正提交的状态,可以用作数据恢复。

由此可以,GreatSQL是以二进制日志的写入与否作为事务提交成功与否的标志。通过这种方式让InnoDB重做日志和GreatSQL服务器的二进制日志中的事务状态保持一致。两阶段提交很好的保持了数据的一致性和顺序性。

GreatSQL通过innodb_support_xa系统变量来控制innodb是否支持XA事务的两阶段提交,默认是支持。在GreatSQL8中已移除该变量,表示数据库内部一直启用innodb对XA事务两阶段提交的支持。

2.3.3 日志刷盘频率

两阶段提交只是从流程上保证了日志的一致性,如果日志在写盘期间,数据库发生了崩溃或者服务器宕机,存在日志数据丢失的风险。为了规避此类风险,我们需要配置正确的日志刷盘频率。

重做日志的刷盘频率由innodb_flush_log_at_commit_trx参数控制。二进制日志的刷盘频率由sync_binlog参数控制。

  • 重做日志刷盘方式

  1. innodb_flush_log_at_trx_commit参数为1时,表示只要事务提交,立即将重做日志刷盘。

  2. innodb_flush_log_at_trx_commit参数为2时,表示每秒将重做日志缓冲区的内容写入到操作系统页面缓冲,至于什么时候刷盘,由操作系统控制。

  3. innodb_flush_log_at_trx_commit参数为0时,表示每秒将重做日志刷盘。

  • 二进制日志刷盘方式

    1. sync_binlog参数为1时,表示只要事务提交,立即将二进制日志刷盘。
    2. sync_binlog参数为N(N>1)时,表示N个二进制日志组提交后,将二进制日志刷盘。
    3. sync_binlog参数为0时,表示二进制日志的刷盘由操作系统控制。

    三、异步复制参数

    3.1 源库和复制库常用参数说明

    参数名参数值参数级别作用
    binlog_do_dbschema配置文件修改二进制日志只记录该参数指定的库名产生的更新事件
    binlog_ignore_dbschema配置文件修改二进制日志不记录该参数指定的库名产出的更新事件。
    log_slave_updateON/OFF系统级别复制库应用中继日志中的事件是否写入二进制日志。用于复制级联,建议主库和从库都开启该参数。
    replicate_do_dbschema配置文件修改只重放中继日志中该参数指定的库名的事件。
    replicate_ignore_dbschema配置文件修改不重放中继日志中该参数指定的库名的事件。
    replicate_wild_do_tableschema.%配置文件修改只重放中继日志中该参数指定的库名的事件。建议使用这种方式进行复制过滤。
    replicate_wild_ignore_tableschema.%配置文件修改不重放中继日志中该参数指定的库名的事件。建议使用这种方式进行复制过滤。
    skip_slave_startON/OFF只读参数复制库启动时,是否启动复制线程。建议不开启该参数。
    sql_log_binON/OFF会话级别会话端执行的更新事件是否写入二进制日志。
    slave_parallel_workers0-N全局级别是否开启多线程复制, 并指定对少个线程并发应用复制事务。参数值为0时,表示不开启。
    slave_parallel_typelogical_lock database全局级别在源库二进制日志事件是以组的方式进行提交。为了保证在从库并发的执行事务,有两种方式进行控制。基于logical_lock的方式:通过跟踪某一个时间点内的事务与事务之间的关系, 来决定尽可能的并发执行事务。基于database的方式:在不同数据库之间值的事务可以并发执行。
    slave_preserve_commit_orderON/OFF全局级别在多线程复制库上, 事务的执行和提交顺序与中继日志中记录的顺序一致。
    slave_pending_job_size_maxinteger全局级别在多线程复制库上, 应用队列用于保留暂未应用的事务的最大可用内存。该参数的值不能小于源库上max_allowed_packet参数指定的值, 不然在执行大事务事会报错。
    slave_max_allowed_packetinteger全局级别指定复制库上的sql线程和io线程能够处理的最大数据包, 该参数不能小于源库上max_allowed_packet指定的参数值。

    四、异步复制部署

    4.1 环境准备

    使用两台服务器来部署一主一从的异步复制。

    Master:192.168.135.183

    Slave:192.168.135.142

    4.2 部署数据库

    安装GreatSQL数据库,见GreatSQL官方文档 https://greatsql.cn/docs/8.0.32-25/4-install-guide/3-install-with-tarball.html

    4.3 配置复制

    4.3.1 空库

    初始安装的数据库没有任何应用数据。可以直接配置就能使用。

    • Master上的操作:

      greatsql> reset master;
    • Slave上的操作:

      greatsql> reset master;
      greatsql> reset slave all;

      greatsql> change master to master_host="192.168.135.183",master_port=3305,master_user='repl',ma ster_password='!QAZ2wsx',master_auto_position=1;

      greatsql> start slave;
      greatsql> show slave status\G

    4.3.2 脱机

    如果源数据库上存在应用数据,允许在一个接收的脱机时间窗口进行复制,那么我们可以直接把源库的数据文件复制到从库,再启动从库进行主从配置。

    • Master上的操作

    1. 创建用于复制的账户,并授予相应的权限。

    2. 停止源数据库服务。

    3. 复制源数据库上的数据文件到从库。

    4. 启动源数据库服务。

  • Slave上的操作

    1. 删除从库数据目录中的auto.cnf,从库在启动时会自动生成唯一的server_uuid。检查数据库配置文件确保server_id是唯一的。

    2. 启动从数据库服务。

    3. 配置主从同步关系,并启动主从同步线程。

    4.3.3 联机

    大多数情况下,复制被要求在不影响线上业务的情况下联机创建,而且还要求对线上源库影响越小越好。在联机情况下,我们通常采用mysqldump和xtrabackup工具复制源库到从库,配置主从同步。

    mysqldump联机复制过程

    • Master上的操作

    1.创建用于复制的账户

    greatsql> create user repl@'%' identified with mysql_native_password by '!QAZ2wsx';
    greatsql> grant replication client,replication slave on *.* to repl@'%';
    greatsql> flush privileges;
    • Slave上的操作
    1. 创建源库信息
    greatsql> change master to master_host='192.168.135.183',master_port=3305,master_user='repl',master_password='!QAZ2wsx';
    1. 使用mysqldump导入数据到从库,建立复制
    greatsql> mysqldump --single-transaction --all-databases --master-data=1 --host=192.168.135.183 --port=3306 --user=root --password=!QAZ2wsx --default-character-set=utf8mb4 --apply-slave-statements|mysql -uroot -p!QAZ2wsx -h192.168.135.142 -P3305

    重要参数说明:

    • --single-transaction参数对innodb表执行非锁定导出。此选项将事务隔离模式设置为repeatable read,并在转储数据之前向服务器发送start transaction sql语句。它仅适用于innodb等事务表,因为它会在发出start transaction时转储数据库一致状态,而不会阻塞任何应用程序。

    • --master-data参数为1时会导致转储输出包含类型change master to master_log_file='binlog.000004',master_log_pos=1230;的sql语句,该语句指示主库的二进制日志坐标(文件和偏移量)。如果选项值为2,则chang master to语句将被注释,仅提供信息,不会执行。如果未指定选项值,则默认值为1。

    • --apply-slave-statements参数会在change master to之前添加stop slave语句,被宰输出的结尾处添加start slave语句,用于开启复制。

    • --deafult-character-set参数指定默认字符集,GreatSQL的默认字符集为utf8mb4。

    xtrabackup联机复制过程

    Master上的操作

    1. 在源库上创建全量备份
    $ xtrabackup --defaults-file=/mysql/conf/node13306.cnf --host='192.168.135.183' --port=3306 --user='root' --password='!QAZ2wsx' --backup --target-dir=/mysql/backup 2>backup.log
    1. 准备数据信息备份
    $ xtrabackup --prepare --target-dir=/mysql/backup 2>restore.log

    --prepare参数准备备份数据进行恢复。数据文件在准备之前是不一致的,因为它们是在备份程序运行的不同时间复制的,并且在这个时间段,有些数据已经发生变更。其原理是使用redolog进行后滚,使用undolog进行前滚。

    Slave上的操作

    1. 关闭从库,在从库上删除数据库初始化生成的数据库文件。
    $ rm -rf /mysql/dbdata/data/*;rm -rf /mysql/dbdata/log/*
    1. 从源库上拉取备份恢复后的数据文件。
    $ scp  -r [root@192.168.135.183:/mysql/backup/*](mailto:root@192.168.1.111:/mysql/backup/*) /mysql/dbdata/data

    $ mv binlog.* ib_logfile* undo_00* ../log/

    $ chown -R mysql:mysql /mysql/dbdata
    1. 启动从数据库服务,并配置主从同步。
    greatsql> service mysql start

    greatsql> change master to master_host="192.168.135.183",master_port=3305,master_user='repl',ma ster_password='!QAZ2wsx',master_auto_position=1;

    五、异步复制常见问题说明

    5.1 show slave 重点指标说明

    我们在从库执行show slave status来观察主从同步的状态。

    • master_log_file:I/O线程正在读取的master binlog。

    • read_master_log_pos:I/O线程已经读取到master binlog的位置。

    • relay_log_file:SQL线程正在读取和执行的relay log。

    • relay_log_pos:SQL线程已经读取和执行relay log的位置。

    • relay_master_log_file:SQL线程最近执行的操作对应的是哪个master binlog。

    • relay_master_log_pos:SQL线程最新执行的操作对应的是master binlog的位置。

    • retrieved_gtid_set:接收到的gtid集合。

    • executed_gtid_set:已执行的gtid集合。

    • seconds_behind_master:SQL线程比IO线程慢多少。在网络正常的情况下,可以表示从库比源库慢多少。

    5.2 常见错误

    主从异步复制中,存在数据库丢失的可能性,导致主从数据不一致。如果数据量比较少的情况下,我们在从库执行相关的操作补齐数据后,对改事务进行跳过。

    • 源库删除一行记录,而slave上找不到改行数据进行删除操作。错误代码为1032。

    • 源库插入一行数据,而slave上表示改行数据早已存在,导致重复冲突。错误代码为1062。

    • 源库上更新一行数据,而slave上表示找不到改行数据执行更新操作,错误代码为1032。

    5.3 主从数据校验

    可以使用GreatSQL社区的gt-checksum工具对主从数据进行一致性校验,或者使用checksum进行数据校验。checksum工具对数据库校验时,会给表上读锁,这一点在使用时需要注意。

    gt-checksum工具详见:https://gitee.com/GreatSQL/gt-checksum


    Enjoy GreatSQL :)

    <往 期 推 荐>
    Percona Toolkit 神器全攻略(复制类)
    GreatSQL执行Update失败案例分析
    GreatSQL社区月报 | 2024.08
    Percona Toolkit 神器全攻略(开发类)
    独家揭秘丨GreatSQL 的MDL锁策略升级对执行的影响

    《GreatSQL运维实战》视频课程

    <关于 GreatSQL>

    GreatSQL数据库是一款开源免费数据库,可在普通硬件上满足金融级应用场景,具有高可用、高性能、高兼容、高安全等特性,可作为MySQL或Percona Server for MySQL的理想可选替换。

    💻社区官网: https://greatsql.cn/ 
    Gitee  https://gitee.com/GreatSQL/GreatSQL
    GitHub  https://github.com/GreatSQL/

    🆙BiliBili  : https://space.bilibili.com/1363850082

    (对文章有疑问或见解可去社区官网提出哦~)

    加入微信交流群
    加入QQ交流群

    想看更多技术好文,点个"在看"吧!

    GreatSQL社区
    专注GreatSQL数据库及相关产品
     最新文章