概要描述
TDH 容器化集群中的 TxSQL(PhxSQL 三节点架构,承载 Inceptor/Quark 元数据库 metastore_* 等)没有现成的定期备份工具,而且宿主机上通常没有 mysql、mysqldump 客户端,无法直接导出。
本文介绍通用备份脚本 txsql_backup.sh 的获取和使用方法。脚本可以把 TxSQL 逻辑备份到服务器本地磁盘,放到其他集群上不用修改配置即可使用:
- 自动发现集群中所有
txsql-server-*Pod,跨命名空间查找,支持一个集群有多个 TxSQL 服务。 - 自动从 Pod 中读取连接地址、端口和密码,不需要手动配置,密码也不会出现在宿主机命令行中。
- 使用 Pod 内自带的 mysqldump 导出,在宿主机压缩落盘,并校验完整性。
- 支持按天数保留、防止重复运行,可以直接配置成定时任务。
本文内容已在 TOS 2.1.0、TxSQL 5.6.48(Percona)三节点集群上实测,包括备份,以及在隔离实例中恢复后逐表比对行数。
详细说明
脚本获取
工作原理
- 通过 kubectl 找到所有
txsql-server-*Pod,每个服务选一个 Running 的 Pod:- 默认模式:优先选本机上的 Pod,经读写 Proxy(默认端口 3316)连接,实际由 Master 提供数据。
--via-local模式:优先选 Slave(read_only=1)Pod,通过 socket 直连 Pod 内的 mysqld,避免给 Master 增加压力。
- 在 Pod 内读取
$CONF_DIR/txsql-env.sh、phxsqlproxy.conf获取 Proxy 地址和端口,密码取 Pod 环境变量TXSQL_DB_PASSWORD。 - 在 Pod 内用自带的 mysqldump 逐库导出(
--single-transaction,不锁表),输出经kubectl exec流回宿主机,由宿主机 gzip 压缩写盘。 - 校验每个文件的 gzip 完整性,以及 mysqldump 的结束标记
-- Dump completed,然后生成 SHA256 校验值和元数据文件。 - 全部成功后,把临时目录(
.inprogress)改为正式目录,再清理过期备份。
前提条件
- 在 TDH 集群任意节点上以 root 执行,该节点上的 kubectl 能访问 apiserver。脚本会依次尝试
kubectl -s http://127.0.0.1:8080、--kubeconfig=/srv/kubernetes/kubeconfig、--kubeconfig=/root/.kube/config、kubectl;都不通时,用--kubectl参数指定。 - 宿主机有
bash、gzip、flock、sha256sum(CentOS 7 默认都有)。 - 备份盘的可用空间大于待备份库的数据量。脚本执行前会检查,空间不足时直接报错退出。
部署
把下载的脚本上传到节点,例如 /opt/scripts/,然后加上执行权限:
chmod +x /opt/scripts/txsql_backup.sh
如果脚本是在 Windows 上编辑后再上传的,先执行 sed -i 's/\r$//' /opt/scripts/txsql_backup.sh 去掉回车符。
查看实例(不备份)
先用 --list 确认脚本能识别 TxSQL 服务:
/opt/scripts/txsql_backup.sh --list
输出示例:
== 服务: txsql1 namespace: default pod: txsql-server-txsql1-<哈希>-<后缀>
连接: -h<节点IP> -P3316
版本: 5.6.48-88.0-log 实际节点: <主机名> read_only=0
库: metastore_inceptor1 表数=133 4MB
...
执行备份
# 备份所有 TxSQL 服务的所有业务库,保留 7 天
/opt/scripts/txsql_backup.sh -d /mnt/disk2/txsql_backup -k 7
# 只备份 txsql1 服务的指定库
/opt/scripts/txsql_backup.sh -d /mnt/disk2/txsql_backup -s txsql1 -D "metastore_inceptor1"
# 从 Slave 导出,避免给 Master 增加压力
/opt/scripts/txsql_backup.sh -d /mnt/disk2/txsql_backup --via-local
成功时的输出示例:
[txsql1] 连接: -h<节点IP> -P3316 | 实际落到: <主机名> read_only=0 version=5.6.48-88.0-log
[txsql1] 待备份库: metastore_inceptor1 metastore_inceptor2 test
[txsql1] 数据量约 4 MB,备份盘可用 157507 MB
[txsql1] OK metastore_inceptor1 56K 2s
[txsql1] OK create_databases.sql
[txsql1] OK grants
[txsql1] 备份完成: /mnt/disk2/txsql_backup/txsql1/20261111_115525 (84K)
全部备份成功
参数说明
| 参数 | 说明 | 默认值 |
|---|---|---|
-d, --backup-dir |
备份根目录 | 依次尝试 /data、/mnt/disk2、/mnt/disk1,用第一个存在的目录下的 txsql_backup |
-k, --keep-days |
保留天数,0 表示不清理 | 7 |
-s, --service |
只备份指定服务(如 txsql1、guardian),可重复指定 |
全部服务 |
-D, --databases |
只备份指定库,多个库用空格分隔并加引号 | 全部业务库 |
--include-mysql |
同时导出 mysql 系统库 |
不导出 |
--no-grants |
不导出账号授权 | 导出 |
--via-local |
优先选 Slave Pod,通过 socket 直连 mysqld | 走 Proxy |
--kubectl "命令" |
自定义 kubectl 命令 | 自动探测 |
--namespace |
只在指定命名空间查找 | 全部命名空间 |
-l, --list |
只列出实例和库,不备份 | – |
-h, --help |
查看完整帮助 | – |
非容器部署,或宿主机已有 mysqldump 时,可以用直连模式:
TXSQL_PASSWORD='<密码>' /opt/scripts/txsql_backup.sh --direct -H <代理地址> -P 3316 \
--mysqldump <客户端mysqldump路径> -d /mnt/disk2/txsql_backup
直连模式也可以用 --password-file <密码文件> 传入密码(文件只写一行密码,权限设为 600)。
备份产物
<备份根目录>/
├── .txsql_backup.lock 防止重复运行的锁文件
└── <服务名>/
├── backup.log 历次备份日志
├── 20261111_023000/ 一次成功的备份
│ ├── <库名>.sql.gz 每个库一个文件,不含 CREATE DATABASE/USE
│ ├── create_databases.sql 各库建库语句(含字符集)
│ ├── grants.sql.gz 账号和授权
│ ├── meta.txt 版本、提供数据的节点、GTID、库表数量等
│ └── SHA256SUMS
└── 20261110_023000.FAILED/ 失败的备份,保留现场便于排查
<库名>.sql.gz 导出时带存储过程、触发器和事件,用 --set-gtid-purged=OFF,所以可以直接导入开启 GTID 的实例。
判断备份是否成功
-
退出码:
退出码 含义 0 全部成功 1 参数或环境错误,例如找不到 kubectl、指定的服务不存在 2 部分或全部备份失败,例如连接失败、校验失败、指定的库不存在 3 已有备份进程在运行 -
目录名:成功的备份是
YYYYmmdd_HHMMSS,失败的带.FAILED后缀。 -
meta.txt最后一行是status : SUCCESS或status : FAILED。 -
校验文件完整性:
cd <备份目录> && sha256sum -c SHA256SUMS
配置定时任务
crontab -e 中加一行,每天 02:30 执行:
30 2 * * * /opt/scripts/txsql_backup.sh -d /mnt/disk2/txsql_backup -k 7 >/dev/null 2>&1
日志写在 <备份根目录>/<服务名>/backup.log。建议只在一个节点上配置,避免多个节点重复备份。
清理规则
- 只清理名称符合
YYYYmmdd_HHMMSS(含.FAILED、.inprogress后缀)格式、且超过保留天数的目录,不会动其他文件。 - 无论多旧,始终保留最新一份成功的备份。
- 只在本次备份成功后才清理。
恢复
恢复元数据库前,先停掉 Inceptor/Quark 等使用方,并先在测试库上验证。
按以下顺序导入:
-
create_databases.sql:建库。 -
grants.sql.gz:账号和授权。如果 DEFINER 用户(如inceptoruser)在目标实例上已经存在,可以跳过。不导入且用户不存在时,导入视图会报错:ERROR 1449 (HY000): The user specified as a definer ('inceptoruser'@'%') does not exist -
各库的
<库名>.sql.gz。
宿主机没有 mysql 客户端时,经 Pod 导入:
K="kubectl -s http://127.0.0.1:8080 -n <命名空间>"
P=<所选Pod名>
# 1. 建库
cat create_databases.sql | $K exec -i $P -- \
sh -c 'MYSQL_PWD="$TXSQL_DB_PASSWORD" mysql -uroot -h<代理地址> -P3316'
# 2. 授权:过滤掉 root、replica 内部账号,避免覆盖目标实例的密码
gunzip -c grants.sql.gz | grep -vE "TO '(root|replica)'@" | $K exec -i $P -- \
sh -c 'MYSQL_PWD="$TXSQL_DB_PASSWORD" mysql -uroot -h<代理地址> -P3316'
# 3. 导入单个库
gunzip -c metastore_inceptor1.sql.gz | $K exec -i $P -- \
sh -c 'MYSQL_PWD="$TXSQL_DB_PASSWORD" mysql -uroot -h<代理地址> -P3316 metastore_inceptor1'
<库名>.sql.gz 里没有库名,所以也可以导入到另一个库名下,例如先恢复到临时库,核对无误后再切换。
其他信息
注意事项
-
备份目录:不指定
-d时,TDH 节点上通常没有/data,会落到/mnt/disk2或/mnt/disk1。这些一般是 HDFS、KunDB 的业务数据盘。建议用-d明确指定备份目录,并留意磁盘水位。 -
恢复前确认 TxSQL 写入正常:在测试环境中出现过 TxSQL 一写入就导致 Master mysqld 重启的情况,mysqld 日志关键字为
repl_phx_report_binlog_to_binlogsvr ... send binlog buffer failed ... ret 503和fatal error。备份只做读取,不受影响;恢复需要写入,执行前请先确认写入正常。