|
复制就是将一个数据库数据复制到一个或多个数据库上,复制的过程是异步的,其工作原理是通过binlog(二进制日志)记录事务变更然后传送到从库并重放事务,保持数据一致
1-1 复制过程图
GreatSQL 复制是基于 binlog 日志来实现复制的
二进制日志格式 | 记录内容 | 主从同步使用场景 | 大小 | 性能 |
---|---|---|---|---|
statement | 基于SQL | 如果使用了一些不确定性的函数和自定义函数,函数返回的数据在主从库上不一致。 比如 now(),last_insert_id()等。 | 较小 | 最好 |
row | 基于数据行 | 默认使用基于row | 较大 | 最差 |
mixed | 混合格式 | 默认使用statement。 当statement无法正确复制时,采用rows | 居中 |
GreatSQL 包含两种记录数据变更的日志,redolog、binlog为了保证两个日志的对数据变更事件达到一致性,GreatSQL 内部使用XA来实现,其核心是两阶段提交。
主从复制中,从库是通过binlog日志重放来实现复制。如何保证主从的数据一致性,就需要考虑如下两方面
在两阶段协议中一般分为事务管理器(协调者)和若干事务执行器(参与者)两种角色。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状态。
数据库在奔溃恢复时,不同状态的事务,会进行不同的处理。
在数据库发生奔溃时,数据库根据重做日志进行数据恢复,逐个检查重做日志的每个事务状态。根据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事务两阶段提交的支持。
两阶段提交只是从流程上保证了日志的一致性,如果日志在写盘期间,数据库发生了崩溃或者服务器宕机,存在日志数据丢失的风险。为了规避此类风险,我们需要配置正确的日志刷盘频率。
重做日志的刷盘频率由innodb_flush_log_at_commit_trx参数控制。二进制日志的刷盘频率由sync_binlog参数控制。
参数名 | 参数值 | 参数级别 | 作用 |
---|---|---|---|
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指定的参数值。 |
使用两台服务器来部署一主一从的异步复制。
Master:192.168.135.183
Slave:192.168.135.142
安装GreatSQL数据库,见GreatSQL官方文档 https://greatsql.cn/docs/8.0.32-25/4-install-guide/3-install-with-tarball.html
初始安装的数据库没有任何应用数据。可以直接配置就能使用。
如果源数据库上存在应用数据,允许在一个接收的脱机时间窗口进行复制,那么我们可以直接把源库的数据文件复制到从库,再启动从库进行主从配置。
大多数情况下,复制被要求在不影响线上业务的情况下联机创建,而且还要求对线上源库影响越小越好。在联机情况下,我们通常采用mysqldump和xtrabackup工具复制源库到从库,配置主从同步。
mysqldump联机复制过程
greatsql> create user repl@'%' identified with mysql_native_password by '!QAZ2wsx';
greatsql> grant replication client,replication slave on *.* to repl@'%';
greatsql> flush privileges;
greatsql> change master to master_host='192.168.135.183',master_port=3305,master_user='repl',master_password='!QAZ2wsx';
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
重要参数说明:
xtrabackup联机复制过程
--prepare
参数准备备份数据进行恢复。数据文件在准备之前是不一致的,因为它们是在备份程序运行的不同时间复制的,并且在这个时间段,有些数据已经发生变更。其原理是使用redolog进行后滚,使用undolog进行前滚。
我们在从库执行show slave status来观察主从同步的状态。
主从异步复制中,存在数据库丢失的可能性,导致主从数据不一致。如果数据量比较少的情况下,我们在从库执行相关的操作补齐数据后,对改事务进行跳过。
可以使用GreatSQL社区的gt-checksum工具对主从数据进行一致性校验,或者使用官方工具checksum进行数据校验。checksum工具对数据库校验时,会给表上读锁,这一点在使用时需要注意。
gt-checksum工具详见:https://gitee.com/GreatSQL/gt-checksum
合作电话:010-64087828
社区邮箱:greatsql@greatdb.com