重建mysql从库、表数据迁移

一、背景

1、xtrabackup+ systemd管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
cat /etc/systemd/system/mysql_slave.service
[Unit]
Description=MySQL Slave Container
After=docker.service
Requires=docker.service
 
[Service]
TimeoutStartSec=60
RuntimeDirectory=mysqld
RuntimeDirectoryMode=0777
ExecStartPre=-/usr/bin/docker rm -f mysql_slave
ExecStartPre=-/usr/bin/docker pull "ip:5000/mysql:5.7"
ExecStartPre=/usr/bin/docker volume create mysqls_data
ExecStartPre=/usr/bin/docker volume create mysqls_log
ExecStart=/backup/mysql/mysql_slave.run
ExecStop=-/usr/bin/docker stop mysql_slave
Restart=on-failure
RestartSec=10
 
[Install]
WantedBy=multi-user.target

启动文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cat /backup/mysql/mysql_slave.run
#!/bin/bash
/usr/bin/docker run -i \
    -e MYSQL_ROOT_PASSWORD=xxx \
    -e MYSQL_DATABASE=xxx \
    -e LANG=C.UTF-8 \
    -v /backup/mysql/mysql_slave_my.cnf:/etc/mysql/my.cnf \
    -v /var/run/mysqld:/var/run/mysqld \
    -v mysqls_data:/var/lib/mysql \
    -v mysqls_log:/var/log/mysql \
    --privileged=true \
    --net=host \
    --rm \
    --name=mysql_slave \
    "ip:5000/mysql:5.7"

2、mysql的配置文件

bin log 部分,设置bin log保存时间、格式等

3、bin log三种格式 

MySQL 的二进制日志(binlog)是用于记录更改数据库状态的日志文件,主要用于数据恢复或复制。

MySQL 支持三种不同的 binlog 格式:Statement、Row 和 Mixed

1. Statement-Based Logging (声明式日志)

描述

  • 在这种模式下,MySQL 记录的是执行的 SQL 语句,而不是实际数据更改的行。
  • 每当执行一个更改数据的 SQL 语句(如 INSERTUPDATE 或 DELETE)时,相关的 SQL 语句会以文本形式记录到 binlog 中。

特点

  • 优点

    • 存储空间占用较少,因为只记录 SQL 语句,而非数据的具体变化。
    • 任何能够被 SQL 引擎执行的更改都可以被记录,保持了灵活性。
  • 缺点

    • 在某些情况下,由于当前上下文的差异(如函数的非确定性行为、时间戳等),相同的 SQL 语句在主从服务器上可能导致不一致。
    • 可能会导致某些语句在复制时无法完全重放,由于不同时刻的承诺或环境差异,导致更新数据时可能出现问题。

2. Row-Based Logging (行式日志)

描述

  • 在行式日志中,MySQL 记录的是实际更改的表的行数据,而非整个 SQL 语句。
  • 当对表进行 INSERT、UPDATE 或 DELETE 操作时,具体更改的行信息(包括哪些行发生了什么更改)会被记录。

特点

  • 优点

    • 数据的准确性高,因为每个行的更改都有明确记录。
    • 复制时更可靠,不会受到 SQL 语句上下文的影响。
  • 缺点

    • 相对于声明式日志,行式日志占用的存储空间较大,因为每个更改都记录了具体的行信息。
    • 如果涉及到大批量的数据变更,日志的体积增长可能会很快。

3. Mixed Logging (混合日志)

描述

  • 混合日志模式结合了声明式和行式日志的优点。根据具体 SQL 语句的特性,MySQL 可以选择使用声明式或行式日志。
  • 对于简单的语句,MySQL 可能选择声明式日志,而对于那些可能出现复制不一致的复杂语句,选择行式日志。

特点

  • 优点

    • 在性能与数据一致性之间提供了更好的平衡。
    • 充分利用声明式日志的存储效率,同时在必要时确保数据完整性和准确性。
  • 缺点

    • 在一些情况下,可能会导致理解和管理上的复杂性,因为不同语句使用不同的日志记录方法。
    • 依赖于 MySQL 的内部逻辑决定使用哪种日志模式。

总结

选择使用哪种 binlog 格式要考虑应用程序的需求、数据一致性要求以及性能考虑。通常来说,在主从复制环境中,行式日志因其数据的准确性和一致性,提供了更强的保障,

而声明式日志由于其较小的存储需求和较好的性能,适合不要求极高一致性的场景。混合模式则是一个折衷方案,能灵活调整。

二、实操

在mysql slave节点操作

1、停止mysql服务

1
systemctl stop mysql_slave.service

2、重建mysql从库的数据卷

1
2
3
4
docker volume rm mysqls_data
docker volume rm mysqls_log
docker volume create mysqls_data
docker volume create mysqls_log

注意:清理目录后,不要再启动mysql从库服务

3、临时开放防火墙端口

1
firewall-cmd --zone=public --add-port=20000/tcp

4、开启接收服务

1
nc -l 20000|xbstream -x -C /healsci/docker/volumes/mysqls_data/_data/

5、主库操作

1
2
3
xtrabackup --defaults-file=/backup/mysql/mysql_master_my.cnf --backup --user=root --password=xxx
--host=127.0.0.1 --port=3306 --datadir=/healsci/docker/volumes/mysqlm_data/_data/
--parallel=8 --compress --compress-threads=8 --stream=xbstream | nc node3 20000

备份期间,不能执行ddl操作,否则备份会失败。
当执行结束后,最后一行显示有 completed OK!,代表备份操作顺利完成。

6、在mysql从库节点执行以下命令:

1
2
3
4
5
firewall-cmd --zone=public --remove-port=20000/tcp
 
xtrabackup --decompress --remove-original --parallel=8 --target-dir=/heal/docker/volumes/mysqls_data/_data
 
xtrabackup --prepare --use-memory=4G --target-dir=/heal/docker/volumes/mysqls_data/_data

7、启动mysql从库

1
2
3
4
5
systemctl start mysql_slave.service
 
mysql -uroot -pxxx -S /var/run/mysqld/mysqld.sock
 
CHANGE MASTER TO MASTER_HOST='ip',MASTER_USER='repl',MASTER_PASSWORD='repl',MASTER_LOG_FILE='mysql-bin.xxx',MASTER_LOG_POS=xxx;

MASTER_LOG_FILE和MASTER_LOG_POS值获取:

当用主库备份时,查询备份目录(/heal/docker/volumes/mysqls_data/_data/xtrabackup_info)文件中的binlog_pos行,对应filename和position

8、启动mysql主从同步

1
2
3
start slave;
 
show slave status\G;

三、使用脚本重建从库

1、依赖

使用xtrabackup程序采用流的方式备份主库

openeuler-22.03-LTS:

1
percona-xtrabackup-24,percona-toolkit,qpress,nmap,tmux,jq,yq

centos-7:

1
percona-xtrabackup-24,percona-toolkit,qpress,nmap,tmux.nmap-ncat

注:

qpress 是一个高效的文件压缩工具,特别适合用于快速压缩和解压缩文件。qpress 经常与数据库备份工具(如 Percona XtraBackup)一起使用,用于高效地压缩备份文件

percona-toolkit 是一个工具集,大致包含数据一致性检查、查询性能诊断、数据库复制管理、数据归档、索引优化

1
2
3
4
5
6
7
8
9
ls /usr/bin/pt-*
/usr/bin/pt-align                  /usr/bin/pt-fingerprint          /usr/bin/pt-mongodb-index-check   /usr/bin/pt-secure-collect  /usr/bin/pt-table-checksum
/usr/bin/pt-archiver               /usr/bin/pt-fk-error-logger      /usr/bin/pt-mongodb-query-digest  /usr/bin/pt-show-grants     /usr/bin/pt-table-sync
/usr/bin/pt-config-diff            /usr/bin/pt-heartbeat            /usr/bin/pt-mongodb-summary       /usr/bin/pt-sift            /usr/bin/pt-table-usage
/usr/bin/pt-deadlock-logger        /usr/bin/pt-index-usage          /usr/bin/pt-mysql-summary         /usr/bin/pt-slave-delay     /usr/bin/pt-upgrade
/usr/bin/pt-diskstats              /usr/bin/pt-ioprofile            /usr/bin/pt-online-schema-change  /usr/bin/pt-slave-find      /usr/bin/pt-variable-advisor
/usr/bin/pt-duplicate-key-checker  /usr/bin/pt-k8s-debug-collector  /usr/bin/pt-pg-summary            /usr/bin/pt-slave-restart   /usr/bin/pt-visual-explain
/usr/bin/pt-fifo-split             /usr/bin/pt-kill                 /usr/bin/pt-pmp                   /usr/bin/pt-stalk
/usr/bin/pt-find                   /usr/bin/pt-mext                 /usr/bin/pt-query-digest          /usr/bin/pt-summary

2、脚本

3、脚本依赖文件

1
2
3
# cat mysql_slave_init.template <br>
CHANGE MASTER TO MASTER_HOST="master_ip", MASTER_PORT=3306, MASTER_USER='repl',MASTER_PASSWORD='repl',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=1;
start slave;

注意:

从库执行sql文本时候,mysql < /tmp/mysql_slave_init.sql , 这里依赖于socket文件的映射

1
2
3
4
5
6
7
mysql> SHOW VARIABLES LIKE 'socket';
+---------------+-----------------------------+
| Variable_name | Value                       |
+---------------+-----------------------------+
| socket        | /var/run/mysqld/mysqld.sock |
+---------------+-----------------------------+
1 row in set (0.00 sec)

获取bin_log、log_positon

1
2
3
4
local mysql_bin_file=$(egrep "binlog_pos" /tmp/xtrabackup_info|awk -v FS="'" '{print $2}')
local mysql_position=$(egrep "binlog_pos" /tmp/xtrabackup_info|awk -v FS="'" '{print $4}')
 
sed -i -e s/master_ip/192.168.1.231/g -e s/mysql-bin.000001/mysql-bin.000014/g -e s/MASTER_LOG_POS=1/MASTER_LOG_POS=484569852/g /tmp/mysql_slave_init.sql

四、mysql 表数据迁移

1、MySQL中的.cfg.ibd.frm文件是与InnoDB存储引擎相关的文件。它们存储了有关数据库表的不同类型的信息:

.frm 文件

.frm文件是MySQL数据库中的表定义文件。对于每个表,MySQL都会在表所在的数据库目录下创建一个与表同名的.frm文件。此文件包含了表结构的元数据,包括列的定义(如数据类型、大小),索引信息,以及其他表属性。无论使用哪种存储引擎,都需要.frm文件来描述表的结构。从MySQL 5.7.31开始,.frm文件逐渐被废除,表结构元数据被保存在数据字典中。

.ibd 文件

  • .ibd 文件是 InnoDB 存储引擎的表空间文件,代表单个表的存储。在 MySQL 中,如果你使用了 InnoDB 的独立表空间模式(通过设置 innodb_file_per_table=ON),那么每个表的数据和索引都会存储在一个独自的 .ibd 文件中。

主要特点

  • 表结构与数据每个 .ibd 文件包含表的结构信息和数据行的实际存储。这意味着表的所有行以及相关的索引信息都存储在这个文件中。
  • 文件命名:文件名通常是表名加上 .ibd 后缀。例如,如果表名为 my_table,则文件名为 my_table.ibd
  • 独立性:每个 .ibd 文件是独立的,允许在管理数据库时更方便地备份、迁移或删除表。
  • 元数据.ibd 文件还包含该表的元数据,如索引信息、数据行的格式等。

ibdata1 文件

  • ibdata1 是 InnoDB 的共享表空间文件(和其他共享文件,例如 undo 日志、元数据等)。在默认情况下(即没有启用 innodb_file_per_table),所有的 InnoDB 表的数据和索引都被存储在这个文件中。

主要特点

  • 全局表空间ibdata1 是一个全局的表空间,所有 InnoDB 表的元数据、数据、索引等都存储在其中。该文件是共享的,包含了所有表的空间信息。
  • 增量增长:随着数据的插入或更新,ibdata1 文件会根据需要不断增长。它不会自动收缩。
  • 回滚日志:除了存储表数据,ibdata1 还存储 InnoDB 的撤消日志(undo log),这些用于处理事务回滚等操作。
  • 表元数据:它存储了 InnoDB 表的结构信息和元数据,也包括 InnoDB 的内部控制信息。

总结

  • .ibd 文件用于存储每个 InnoDB 表的具体数据和索引,支持独立管理和操作,适用于需要单表管理的场景。
  • ibdata1 文件是全局的共享表空间,包含所有 InnoDB 表的元数据和信息,同时承担了事务处理等功能,适用于不使用独立表空间的设置。

.cfg 文件

对于运行在MySQL 5.6和更高版本上的InnoDB表,.cfg文件用于保存表的压缩信息。当你使用mysqldump工具的—innodb-optimize-keys选项导出表结构为SQL时(或者其他表传输操作,比如Transportable Tablespaces功能),此文件会被创建。.cfg文件中存储了有关如何压缩表的信息,如行格式、键块大小等。这个文件不是用于常规操作,仅在表导出和导入之间传输压缩信息时才会用到。

请注意,从MySQL 8.0 版本开始,MySQL引入了Data Dictionary的概念替代.frm文件,数据字典是一个包含所有服务器对象元数据的事务性数据结构。在MySQL 8.0及以后的版本中,.frm文件和一些相关文件已经不再使用。

2、迁移脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#!/bin/bash
src_db_host='node1'
dest_db_host='node3'
dest_file_host='node2'
 
src_volume_name='mysqlm_data'
dest_volume_name='mysqlm_data'
 
dest_file_path_root='/dasda/database_backup/'
 
mysql_user='root'
mysql_password='xxxx'
 
date=$(date +%Y%m%d)
 
databases_tables1=(
'pbm_app.a_predict_flowing'
'pbm_app.patient_service_record'
'pbm_app.wait_beds_event'
)
 
start_time=$(date +'%Y-%m-%d %H:%M:%S')
start_timestamp=$(date +%s)
 
# 导出表结构并创建表
for d_t in "${databases_tables1[@]}"
do
    IFS="." read -ra database2table <<< "${d_t}"
    db="${database2table[0]}"
    tb="${database2table[1]}"
 
    # 建库
    mysql -h"${dest_db_host}" -u"${mysql_user}" -p"${mysql_password}" -e "CREATE DATABASE IF NOT EXISTS \`${db}\`;" 2> /dev/null
 
    # 建表
    sql=$(mysqldump --column-statistics=0 -u"${mysql_user}" -p"${mysql_password}" -h"${src_db_host}" "${db}" "${tb}" --no-data 2>&1 | tail -n +2)   
    mysql -h "${dest_db_host}" -u"${mysql_user}" -p"${mysql_password}" -e "USE ${db}; ${sql}" 2> /dev/null
     
    # 目标实例上删除.ibd文件
    mysql -h "${dest_db_host}" -u"${mysql_user}" -p"${mysql_password}" -e "USE "${db}"; ALTER TABLE "${tb}" DISCARD TABLESPACE;" 2> /dev/null
     
    # 原实例上导出.ibd 和 .cfg
    mysql -u"${mysql_user}" -h"${src_db_host}" -p"${mysql_password}"  -e "FLUSH TABLES "${db}"."${tb}" FOR EXPORT; SELECT SLEEP(7200);" 2> /dev/null
    export_pid=$!
 
    # 在后台开始同步.ibd 和 .cfg 文件到目标实例
    ssh root@"${src_db_host}" "rsync -aP /healsci/docker/volumes/"${src_volume_name}"/_data/"${db}"/"${tb}".{ibd,cfg} root@"${dest_db_host}":/healsci/docker/volumes/"${dest_volume_name}"/_data/"${db}"/" &
    rsync_pid=$!
 
    # 确认文件同步完毕并验证stat值
    while true; do
        local_stat_ibd=$(stat -c%s "/healsci/docker/volumes/${dest_volume_name}/_data/${db}/${tb}.ibd" 2> /dev/null)
        remote_stat_ibd=$(ssh  root@"${src_db_host}" "stat -c%s /healsci/docker/volumes/${src_volume_name}/_data/${db}/${tb}.ibd" 2> /dev/null)
        local_stat_cfg=$(stat  -c%s "/healsci/docker/volumes/${dest_volume_name}/_data/${db}/${tb}.cfg" 2> /dev/null)
        remote_stat_cfg=$(ssh root@"${src_db_host}" "stat -c%s /healsci/docker/volumes/${src_volume_name}/_data/${db}/${tb}.cfg" 2> /dev/null)
 
        if [[ -n "$local_stat_ibd" && -n "$remote_stat_ibd" && "$local_stat_ibd" == "$remote_stat_ibd" && -n "$local_stat_cfg" && -n "$remote_stat_cfg" && "$local_stat_cfg" == "$remote_stat_cfg" ]]; then
            break
        fi
        sleep 5
    done
 
    # .cfg和.ibd文件一致,可结束MySQL会话
    kill "${export_pid}"
     
    # 确保rsync进程已经完成
    wait "${rsync_pid}" 2> /dev/null
     
    # 解锁原表
    mysql -h"${src_db_host}" -u"${mysql_user}" -p"${mysql_password}" -e 'UNLOCK TABLES;' 2> /dev/null
 
    # 同步文件到备份节点
    ssh root@"${dest_file_host}" "mkdir -p "${dest_file_path_root}""${date}"/"${db}"/"
    scp /healsci/docker/volumes/"${dest_volume_name}"/_data/"${db}"/"${tb}".*  root@"${dest_file_host}":"${dest_file_path_root}""${date}"/"${db}"/
 
    # 新实例刷新
    mysql -h"${dest_db_host}" -u"${mysql_user}" -p"${mysql_password}" -e "USE "${db}"; ALTER TABLE "${tb}" IMPORT TABLESPACE;" 2> /dev/null
done
 
end_time=$(date +'%Y-%m-%d %H:%M:%S')
end_timestamp=$(date +%s)
elapsed_seconds=$((end_timestamp - start_timestamp))
hours=$((elapsed_seconds / 3600))
minutes=$(( (elapsed_seconds / 60) % 60))
seconds=$((elapsed_seconds % 60))
  
echo "Total time taken: $hours hours $minutes minutes $seconds seconds."

关键点:

mysql会话一旦关闭cfg、ibd文件就会自动删除,当文件比较大的时候,就需要考虑保持会话的存在直至数据传输完成

 

posted @   凡人半睁眼  阅读(105)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探
历史上的今天:
2020-01-09 镜像的导入和导出

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示