Linux - MySQL迁移至一主一从

news2024/12/16 3:37:49

Linux - MySQL迁移至一主一从

  • 迁移准备
    • 安装MySQL
  • ibd文件迁移
    • 原服务器操作
    • 目标服务器操作
  • 一主一从
  • 增量同步
  • 异常解决
  • 结尾

首先部分单独安装MySQL,请参考Linux - MySQL安装,迁移数据量比较大约400G左右且网络不通故使用文件迁移,需开启一段时间只读和锁表。

迁移准备

测试机作用
172.17.7.9原MySQL
10.3.69.6目标主库
10.3.69.7目标从库

原服务器与目标服务器不在同一局域网内而且无外网。

思路

先检测原MySQL健康的表进行记录,设置原MySQL为只读以及锁表,防止迁移过程中继续写入,记录时间点用作迁移后增量同步,导出所有表结构和ibd文件,解锁恢复读写,将表结构和ibd文件转至目标主库以及从库,都先进行恢复ibd文件,然后进行主从连接,使用binlog导出原MySQL时间点开始的sql日志,并增量同步至目标主库。

安装MySQL

先在目标2台服务器上面安装MySQL,请参考Linux - MySQL安装,其中my.cnf配置参考以下,其中server_id主库与从库不一致 主库6 从库7,其他配置都一致,具体参数值参考自己MySQL需求大小进行配置。

[mysqld]
basedir=/usr/local/mysql/mysql8
datadir=/home/mysql/data
log-error=/home/mysql/log/mysql.log

server_id=6
gtid_mode=on
enforce_gtid_consistency=on
binlog_format=row
log-slave-updates=on
log-bin=mysqlbin-log
binlog_row_image = minimal



max_connections=2000
lower_case_table_names=1
character-set-server=utf8mb4
default_authentication_plugin=mysql_native_password
max_binlog_size=1G
max_binlog_cache_size=4G
log_timestamps=system

配置好后就初始化MySQL,然后重置密码操作什么的,先不进行主从连接。

ibd文件迁移

原服务器操作

注:其中有些打通ssh免密也进行了记录(假设原服务器和目标服务器可以互通),本次迁移未使用到ssh免密

ssh免密

ssh-keygen -t rsa
ssh-copy-id root@10.3.69.6
ssh-copy-id root@10.3.69.7
ssh root@10.3.69.6   # 测试是否免密登录
ssh root@10.3.69.7

创建一个export.sh脚本

找一个磁盘够大的位置(看数据量),创建一个transfer文件夹,在这个文件夹里面创建脚本
我们要一次一个库的去迁移(数据量有点大没磁盘了)当然也可以一次全部迁移全部的库(自行加一个循环),先查询某个库的所有表名,然后导出这个库所有的表结构,然后把ibd文件复制压缩即可
此处我自己写了一个py每过10s向数据库orders表中新增一条数据,模拟真实写入

#!/bin/bash

# 数据库连接信息 变量 - 需要更改的
DB_USER="root"          # 替换为你的数据库用户名
DB_PASSWORD="123456"    # 替换为你的数据库密码
DB_HOST="172.17.7.9"    # 主机地址
DB_NAME="dw"            # 数据库名称,想迁移整个MySQL所有库可以写个大循环
MYSQLDUMP_PATH="/usr/local/mysql/mysql8/bin/mysqldump"   # mysqldump 路径
MYSQL_DATA_DIR="/home/weekeight/mysql/data/${DB_NAME}"   # MySQL 数据目录路径

# 注:下面的所有值都不需要修改
# 输出文件路径
TABLES_FILE="${DB_NAME}_table_name.txt"
SCHEMA_FILE="${DB_NAME}_schema.sql"
# 创建 dw 文件夹(如果不存在)
DW_DIR="./${DB_NAME}"
mkdir -p "$DW_DIR"
# 查询所有表名并保存到文件,移除标题行
mysql -u "$DB_USER" -p"$DB_PASSWORD" -h "$DB_HOST" -D "$DB_NAME" -e "SHOW TABLES;" | sed '1d' > "$TABLES_FILE"
if [ $? -ne 0 ]; then
    echo "导出表名时发生错误"
    exit 1
fi
echo "表名已成功导出到 $TABLES_FILE"
# 使用 mysqldump 导出表结构到文件
$MYSQLDUMP_PATH -u "$DB_USER" -p"$DB_PASSWORD" -h "$DB_HOST" --no-data --single-transaction --routines --triggers --events "$DB_NAME" > "$SCHEMA_FILE"
if [ $? -ne 0 ]; then
    echo "导出表结构时发生错误"
    exit 1
else
    echo "表结构已成功导出到 $SCHEMA_FILE"
fi
# 复制 IBD 文件到 dw 文件夹
while IFS= read -r table; do
    ibd_file="${MYSQL_DATA_DIR}/${table}.ibd"
    if [ -f "$ibd_file" ]; then
        cp "$ibd_file" "$DW_DIR/"
        echo "复制了 $ibd_file$DW_DIR/"
    else
        echo "警告: $ibd_file 不存在"
    fi
done < "$TABLES_FILE"
# 压缩打包 dw 文件夹
TAR_FILE="${DB_NAME}_ibd_files.tar.gz"
tar -czvf "$TAR_FILE" "$DW_DIR"
if [ $? -eq 0 ]; then
    echo "dw 文件夹已成功压缩打包为 $TAR_FILE"
else
    echo "压缩打包时发生错误"
    exit 1
fi
# 清理临时文件夹
rm -rf "$DW_DIR"

上面的脚本写好记得添加权限

chmod +x export.sh

搞好sh脚本后先不用管他,接下来我们进入MySQL进行设置只读和锁表,然后执行脚本,恢复MySQL

SET GLOBAL read_only = ON;    # 设置全局只读模式
FLUSH TABLES WITH READ LOCK;  # 锁表
SHOW ENGINE INNODB STATUS\G   # 检查当前是否还有事务正在执行
# 记录一下当前时间(16:26:00,order结尾11),用作后续的增量同步,order结尾11验证后面的增量同步order.ibd中只存在11条数据
# 然后去执行上面的./export.sh脚本,脚本执行完毕后继续在MySQL中执行以下命令恢复MySQL
UNLOCK TABLES;                # 解除锁表
SET GLOBAL read_only = OFF;   # 恢复读写模式,恢复后order表记录到38,上面sh脚本保存的ibd文件中不包含12-38

现在的我们已经生成了三个文件了,一个ibd数据文件、一个dw库所有表名文件、一个dw库表结构文件,可以把export.sh文件删除了,已经没用了
在这里插入图片描述
接下来就是把这三个文件移动到目标服务器了,下面使用scp,

scp -r ./transfer/ root@10.3.69.6:/home/weekeight/
scp -r ./transfer/ root@10.3.69.7:/home/weekeight/

目标服务器操作

下面的操作在目标服务器的两台上面同步执行命令

cd /home/weekeight/transfer/   # 进入移动过来的文件夹里面

创建一个import.sh脚本

#!/bin/bash

# 变量 - 需要更改的
DB_USER="root"          # 替换为你的数据库用户名
DB_PASSWORD="123456"    # 替换为你的数据库密码
DB_NAME="dw"            # 迁移数据库名
MYSQL_DATA_DIR="/home/mysql/data/${DB_NAME}"   # MySQL 数据目录路径
TRANSFER_DIR="/home/weekeight/transfer"        # 资源目录,就是从原服务器移动过来的

# 注:下面的所有值都不需要修改
IBD_TAR_FILE="${TRANSFER_DIR}/${DB_NAME}_ibd_files.tar.gz"
SCHEMA_FILE="${TRANSFER_DIR}/${DB_NAME}_schema.sql"
TABLES_NAME="${TRANSFER_DIR}/${DB_NAME}_table_name.txt"
log_file="all.log"
# 清空日志文件
> "$log_file"
# 检查数据库是否存在
check_db_exists() {
    mysql -u "$DB_USER" -p"$DB_PASSWORD" -e "SHOW DATABASES LIKE '$DB_NAME';" | grep -w "$DB_NAME" > /dev/null
}
# 检查数据库是否存在
if check_db_exists; then
    echo "数据库 $DB_NAME 已存在。" | tee -a "$log_file"
else
    # 创建数据库
    echo "正在创建数据库 $DB_NAME..." | tee -a "$log_file"
    mysql -u "$DB_USER" -p"$DB_PASSWORD" -e "CREATE DATABASE IF NOT EXISTS $DB_NAME;"
    if [ $? -ne 0 ]; then
        echo "创建数据库 $DB_NAME 失败,请检查数据库连接信息和权限。" | tee -a "$log_file"
        exit 1
    else
        echo "数据库 $DB_NAME 创建成功。" | tee -a "$log_file"
    fi
fi
# 导入表结构
echo "正在导入表结构..." | tee -a "$log_file"
mysql -u "$DB_USER" -p"$DB_PASSWORD" "$DB_NAME" < "$SCHEMA_FILE"
if [ $? -eq 0 ]; then
    echo "表结构已成功导入到数据库 $DB_NAME 中。" | tee -a "$log_file"
else
    echo "导入表结构失败,请检查 $SCHEMA_FILE 是否存在且格式正确。" | tee -a "$log_file"
    exit 1
fi
# 解压 IBD 文件压缩包
echo "解压 IBD 文件..." | tee -a "$log_file"
tar -xzvf "$IBD_TAR_FILE" -C "$TRANSFER_DIR"
if [ $? -ne 0 ]; then
    echo "解压失败,请检查 $IBD_TAR_FILE 是否存在且无损坏。" | tee -a "$log_file"
    exit 1
else
    echo "解压成功,文件已放置在 $TRANSFER_DIR 中。" | tee -a "$log_file"
fi
# 循环读取表名
while IFS= read -r table_name; do
    echo "开始处理表 $table_name..." | tee -a "$log_file"
    # 设置源和目标路径
    source_path="${TRANSFER_DIR}/${DB_NAME}/${table_name}.ibd"
    destination_path="${MYSQL_DATA_DIR}/${table_name}.ibd"
    # 清除表空间
    mysql -u "$DB_USER" -p"$DB_PASSWORD" -e "ALTER TABLE $DB_NAME.$table_name DISCARD TABLESPACE;"
    if [ $? -ne 0 ]; then
        echo "表 $table_name: DISCARD TABLESPACE 失败,跳过" | tee -a "$log_file"
        continue
    fi
    # 复制 .ibd 文件
    cp "$source_path" "$destination_path"
    if [ $? -ne 0 ]; then
        echo "表 $table_name: 文件复制失败,跳过" | tee -a "$log_file"
        continue
    fi
    # 修改文件拥有者为 mysql
    chown mysql:mysql "$destination_path"
    if [ $? -ne 0 ]; then
        echo "表 $table_name: 更改文件拥有者失败,跳过" | tee -a "$log_file"
        continue
    fi
    # 导入表空间
    mysql -u "$DB_USER" -p"$DB_PASSWORD" -e "ALTER TABLE $DB_NAME.$table_name IMPORT TABLESPACE;"
    if [ $? -ne 0 ]; then
        echo "表 $table_name: IMPORT TABLESPACE 失败,跳过" | tee -a "$log_file"
        continue
    fi
    echo "表 $table_name 迁移成功" | tee -a "$log_file"
done < "$TABLES_NAME"
echo "所有表处理完成,详情见 $log_file" | tee -a "$log_file"

创建import.sh后执行下面操作

chmod +x import.sh   # 修改权限
./import.sh          # 执行,执行完毕后检查一下打印是否正确,可以查看all.log日志
cd ..
rm -rf ./transfer    # 删除移动过来的文件夹即可,已无用

一主一从

下面是在目标服务器的MySQL上的操作,是进行一主一从的连接

首先在主库上面查看gtid值

mysql> SHOW VARIABLES LIKE 'gtid_executed';
+---------------+-------------------------------------------+
| Variable_name | Value                                     |
+---------------+-------------------------------------------+
| gtid_executed | 36513eed-b6bd-11ef-843c-6c92bfcb11f0:1-76 |
+---------------+-------------------------------------------+
1 row in set (0.01 sec)

然后在从库上面进行绑定连接

SET @@GLOBAL.GTID_PURGED='36513eed-b6bd-11ef-843c-6c92bfcb11f0:1-76';   # 把主库的gtid添加到这里
change master to master_host='10.3.69.6',master_port=3306,master_user='root',master_password='123456',master_auto_position=1 for channel 'master1';   # 连接主库创建管道名为msater1
start slave for channel 'master1';   # 单独启动master1进行复制,可使用start slave;
show slave status\G   # 查看从库的状态,状态中Slave_IO_Running与Slave_SQL_Running同为yes时正常,不然就是异常

下面的几个命令不需要执行,如果主从连接出现了问题,那么我们就要停止连接,清除配置,重新连接时使用的

stop slave;        # 停止主从
reset master;      # 重置主库配置
reset slave all;   # 重置从库配置

下面就是去主库上面进行创建一个数据库,或者写入数据,查看从库是否变化了

增量同步

上方已经记录了时间以及order参数(16:26:00),目标数据库的参数为11,原数据库的参数是38

先在原mysql上面进行查看binlog的file,然后导出binlog信息

mysql> SHOW MASTER STATUS;
+---------------+----------+--------------+------------------+-------------------+
| File          | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+-------------------+
| binlog.000014 | 33034659 |              |                  |                   |
+---------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
  • –skip-gtids:跳过GTID事件,必填项,不加的话导出的数据用不了,GTID冲突
  • –database:指定数据库
  • –start-datetime:指定开始时间,此时间即锁表后的时间,上面已经记录了
  • –stop-datetime:指定结束时间,最好指定此时间,导出的数据包头不包尾,这样的话如果有需要,下次的增量同步这个就是开始时间
  • binlog的文件在MySQL数据目录中,上面已经有文件名称了
/usr/local/mysql/mysql8/bin/mysqlbinlog --skip-gtids --database=dw --start-datetime="2024-12-12 16:26:00" --stop-datetime="2024-12-13 10:00:00" /home/weekeight/mysql/data/binlog.000014 > ./dw20241213100000.sql

把dw20241213100000.sql文件发送到目标服务器主库上面,从库不需要。

scp -r ./dw20241213100000.sql root@10.3.69.6:/usr/local/

下面在主库上导入sql

mysql -u root -p dw < dw20241213100000.sql

然后查看主库以及从库orders参数是否增加。

异常解决

@@SESSION.GTID_NEXT cannot be set to ANONYMOUS when @@GLOBAL.GTID_MODE = ON.

主库执行增量的sql文件时报错
binlog导出sql信息时使用–skip-gtids跳过GTID事件

Multiple channels exist on the slave. Please provide channel name as an argument

需要将从机的master清空(本机连接的有master的也要清空)
stop slave; reset slave all; reset master;

@@GLOBAL.GTID_PURGED cannot be changed: the added gtid set must not overlap with @@GLOBAL.GTID_EXECUTED

reset master;

@@GLOBAL.GTID_PURGED cannot be changed: the new value must be a superset of the old value

之前已经存在gtid了想再需要配置一个多个的
SET @@GLOBAL.GTID_PURGED=‘以前的gtid…,新的gtid’;

结尾

至此MySQL迁移至一主一从已经全部搞定,如果有问题或者有其他好的方案望提议,共同学习。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2260277.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

opencv-python的简单练习

题目1.读取一张彩色图像并将其转换为灰度图。 import cv2 # 读取图片文件 img cv2.imread(./1.png)# 将原图灰度化 img_gray cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)# 输出图片 cv2.imshow(img,img) cv2.imshow(img_g,img_gray) # 进行阻塞 cv2.waitKey(0) 题目2&#xff1a;…

go-zero(十三)使用MapReduce并发

go zero 使用MapReduce并发 一、MapReduce 介绍 MapReduce 是一种用于并行计算的编程模型&#xff0c;特别适合在大规模数据处理场景中简化逻辑代码。 官方文档&#xff1a; https://go-zero.dev/docs/components/mr 1. MapReduce 的核心概念 在 MapReduce 中&#xff0c;主…

探索React与Microi吾码的完美结合:快速搭建项目,低代码便捷开发教程

一、摘要 在当今的数字化时代&#xff0c;软件开发就像是一场探险&#xff0c;每个开发者都是探险家&#xff0c;探索着代码的奥秘。React作为前端开发的领军框架&#xff0c;其组件化和高效的渲染机制为开发者提供了强大的工具。而Microi吾码低代码平台的出现&#xff0c;则为…

SAP FICO物料分类账实操

物料分类账所涉及到的差异从采购入库的时候就可能已经产生&#xff0c;接下来从创建物料主数据开始对可能产生差异地方进行分析。其中有些操作步骤在标准价格估算这一篇博文中已经有过演示&#xff0c;可以先做了解。 其中的某些创建在有直接可用的情况下是非必须的&#xff0…

WordPress酱茄主题 开源版 博客资讯自媒体网站模板

一款免费开源的WordPress主题&#xff0c;主题专为WordPress博客、资讯、自媒体网站而设计 运行环境 支持WordPress版本&#xff1a;5.6 兼容Chrome、Firefox、Safari等主流浏览器 支持设备&#xff1a;响应式布局&#xff0c;不同设备不同展示效果 服务器环境建议&#x…

【HF设计模式】03-装饰者模式

声明&#xff1a;仅为个人学习总结&#xff0c;还请批判性查看&#xff0c;如有不同观点&#xff0c;欢迎交流。 摘要 《Head First设计模式》第3章笔记&#xff1a;结合示例应用和代码&#xff0c;介绍装饰者模式&#xff0c;包括遇到的问题、遵循的 OO 原则、达到的效果。 …

Linux查看是否有www-data用户,如果没有添加一个

在 Linux 系统中&#xff0c;www-data 用户通常是用来运行 Web 服务&#xff08;如 Nginx 或 Apache&#xff09;的。如果你想检查系统中是否已经存在 www-data 用户&#xff0c;并在没有的情况下添加一个&#xff0c;可以按照以下步骤操作&#xff1a; ### 1. 检查 www-data …

23.模块和包

模块 模块Module,是一个python文件&#xff0c;以.py结尾。 模块能定义函数、类和变量。 模块导入 模块在使用前需要先导入 [from 模块名] import [模块 | 类 | 变量 | 函数 | *] [as 别名] import 模块 import time print("start...") time.sleep(5) print(&…

IDEA报错:无效的源发行版、无效的目标发行版

1. 无效的源发行版 创建项目的时候&#xff0c;会遇见这个报错&#xff0c;原因就是编译的JDK版本与发布版本不一致。 解决方法&#xff1a; 1.1. 找到问题所在地 英文&#xff1a;File -> Project Structure ->Project Settings 中文&#xff1a;文件->项目结构 …

2025年,客服知识库与人工智能的结合

随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;传统客服模式正在经历前所未有的变革。特别是在2025年&#xff0c;客服知识库与AI的深度融合&#xff0c;不仅极大地提升了客服处理的效率与准确性&#xff0c;还为用户带来了更加个性化、高效的服务体验。 …

JVM 双亲委派模型以及垃圾回收机制

目录 1. JVM 内存区域划分 2. JVM 中类加载的过程 1) 类加载的基本流程 2) 双亲委派模型 3. JVM 中垃圾回收机制 1) 找到垃圾 a) 引用计数 b) 可达性分析 2) 释放垃圾 1. JVM 内存区域划分 一个运行起来的 Java 进程&#xff0c;其实就是一个 JVM 虚拟机。 而进程是…

微信小程序跳转其他小程序以及跳转网站

一、跳转其他小程序 1.1 知道appid和页面路径 wx.navigateToMiniProgram({appId: appid, // 替换为目标小程序 AppIDpath: pathWithParams, // 小程序路径envVersion: release, // 开发版、体验版或正式版success(res) {console.log("跳转到其他小程序成功&#xff01;&q…

学习笔记:从ncsi/nc-si协议和代码了解网络协议的设计范式

学习笔记&#xff1a;从ncsi/nc-si协议和代码了解网络协议的设计范式 参考文档&#xff1a; https://www.dmtf.org/standards/published_documents https://www.dmtf.org/dsp/DSP0222 https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.2.0.pdf参考代…

深度学习训练参数之学习率介绍

学习率 1. 什么是学习率 学习率是训练神经网络的重要超参数之一&#xff0c;它代表在每一次迭代中梯度向损失函数最优解移动的步长&#xff0c;通常用 η \eta η 表示。它的大小决定网络学习速度的快慢。在网络训练过程中&#xff0c;模型通过样本数据给出预测值&#xff0…

【数据结构——线性表】单链表的基本运算(头歌实践教学平台习题)【合集】

目录&#x1f60b; 任务描述 相关知识 测试说明 我的通关代码: 测试结果&#xff1a; 任务描述 本关任务&#xff1a;编写一个程序实现单链表的基本运算。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;初始化线性表、销毁线性表、判定是否为空表、求线性…

利用ROS的Camera Calibration工具进行D435相机标定

一、安装ROS Camera Calibration sudo apt-get install ros-melodic-camera-calibration 二、安装realsense-ros 安装ROS Wrapper for Intel RealSense&#xff08;realsense-ros&#xff09; 三、启动数据读取节点 ctrlaltt打开终端 cd catkin_ws_ur source devel/setu…

让文案生成更具灵活性/chatGPT新功能canvas画布编辑

​ ​ OpenAI最近在2024年12月发布了canvas画布编辑功能&#xff0c;这是一项用途广泛的创新工具&#xff0c;专为需要高效创作文案的用户设计。 无论是职场人士、学生还是创作者&#xff0c;这项功能都能帮助快速生成、优化和编辑文案&#xff0c;提升效率的同时提高内容质量…

C# 网络编程--关于UDP 通信(二)

UDP (User Datagram Protocol) 是一种无连接的传输层协议&#xff0c;主要用于支持数据报文的传输。它的主要特点包括简单、高效、不保证可靠性和顺序。 1.UDP协议基本概念 1.udp基于IP的简单的协议&#xff0c;不可靠的协议 2.优点&#xff1a;简单、 轻量化、 传输速度高、…

Spring Boot 集成 MyBatis 全面讲解

Spring Boot 集成 MyBatis 全面讲解 MyBatis 是一款优秀的持久层框架&#xff0c;与 Spring Boot 集成后可以大大简化开发流程。本文将全面讲解如何在 Spring Boot 中集成 MyBatis&#xff0c;包括环境配置、基础操作、高级功能和最佳实践。 一、MyBatis 简介 1. SqlSession …

解决Jmeter HTTP Cookie管理器cookie不生效

解决Jmeter HTTP Cookie管理器cookie不生效问题 解决Jmeter HTTP Cookie管理器cookie不生效问题1、设置Jmeter HTTP Cookie管理器cookie后&#xff0c;发起的请求显示[no cookies]jmeter问题复现&#xff1a;这里同样使用postman进行重试&#xff0c;发现是可以正常获取数据的&…