GreatSQL 异步复制及搭建

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_db schema 配置文件修改 二进制日志只记录该参数指定的库名产生的更新事件
binlog_ignore_db schema 配置文件修改 二进制日志不记录该参数指定的库名产出的更新事件。
log_slave_update ON/OFF 系统级别 复制库应用中继日志中的事件是否写入二进制日志。用于复制级联,建议主库和从库都开启该参数。
replicate_do_db schema 配置文件修改 只重放中继日志中该参数指定的库名的事件。
replicate_ignore_db schema 配置文件修改 不重放中继日志中该参数指定的库名的事件。
replicate_wild_do_table schema.% 配置文件修改 只重放中继日志中该参数指定的库名的事件。 建议使用这种方式进行复制过滤。
replicate_wild_ignore_table schema.% 配置文件修改 不重放中继日志中该参数指定的库名的事件。 建议使用这种方式进行复制过滤。
skip_slave_start ON/OFF 只读参数 复制库启动时,是否启动复制线程。 建议不开启该参数。
sql_log_bin ON/OFF 会话级别 会话端执行的更新事件是否写入二进制日志。
slave_parallel_workers 0-N 全局级别 是否开启多线程复制, 并指定对少个线程并发应用复制事务。 参数值为0时,表示不开启。
slave_parallel_type logical_lock database 全局级别 在源库二进制日志事件是以组的方式进行提交。 为了保证在从库并发的执行事务,有两种方式进行控制。 基于logical_lock的方式: 通过跟踪某一个时间点内的事务与事务之间的关系, 来决定尽可能的并发执行事务。 基于database的方式: 在不同数据库之间值的事务可以并发执行。
slave_preserve_commit_order ON/OFF 全局级别 在多线程复制库上, 事务的执行和提交顺序与中继日志中记录的顺序一致。
slave_pending_job_size_max integer 全局级别 在多线程复制库上, 应用队列用于保留暂未应用的事务的最大可用内存。 该参数的值不能小于源库上max_allowed_packet参数指定的值, 不然在执行大事务事会报错。
slave_max_allowed_packet integer 全局级别 指定复制库上的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 😃

关于 GreatSQL

GreatSQL是适用于金融级应用的国内自主开源数据库,具备高性能、高可靠、高易用性、高安全等多个核心特性,可以作为MySQL或Percona Server的可选替换,用于线上生产环境,且完全免费并兼容MySQL或Percona Server。

相关链接: GreatSQL社区 Gitee GitHub Bilibili

GreatSQL社区:

社区博客有奖征稿详情:https://greatsql.cn/thread-100-1-1.html

技术交流群:

微信:扫码添加GreatSQL社区助手微信好友,发送验证信息加群