Linux MySQL数据导出与备份:从mysqldump到物理快照的选型与验证
发布时间:2026/11/3 12:57:29 锦皓数字建站

1. 先把导出这件事拆开看你要的到底是哪一类文件在 Linux 上导出 MySQL 数据很多人的第一反应就是敲一条mysqldump把结果丢进一个.sql文件然后心里就踏实了。但我这些年接手过的烂摊子一大半都出在导出这一步没想清楚有人要的是能把整库拉起来的一份完整快照结果导了个只含数据的 CSV有人只要一张大表里某个时间段的几十万行做分析却对着几百 G 的全库 dump 干等了三小时。所以正式开始讲命令之前我先把导出这个动作按目的分成两类这个分类决定了后面所有工具选型和参数细节。1.1 逻辑导出与物理导出的分水岭逻辑导出的本质是把数据行重新组织成 SQL 语句或者带分隔符的文本落盘成人类可读的文件。mysqldump、mysqlpump、SELECT ... INTO OUTFILE、mysqldump --tab都属于这一路。它的好处非常明显跨版本、跨平台、跨架构都吃得开5.7 导出的文件丢进 8.0 基本能跑x86 机器上导出的文件搬到 ARM 机器上也没问题文件是纯文本出了问题能直接head、grep、sed看一眼实在不行手动改两行再导。代价是慢——引擎要把每一行从页里读出来、做字符集转换、拼成字符串、写进文件这一整套 CPU 开销躲不掉而且中间还要经过 SQL 解析器再解析一遍才能导回去。物理导出是直接把数据文件、redo 日志、undo 文件按字节拷走。文件系统快照、冷备拷贝 datadir、第三方物理备份工具都属于这一类。它的速度快到不讲道理几百 G 的库几分钟就能复制完恢复也快因为是文件级别的还原不需要重建索引。但它对环境的挑剔程度也高版本号必须对得上页大小必须一致操作系统和文件系统最好别换恢复的时候还得处理 redo 日志的前滚。我一般只在两种情况下走物理路线——整机迁移或者数据库大到逻辑导出已经不可能在维护窗口内完成。选哪条路本质上是可移植性和速度之间的权衡没有标准答案。我的判断标准很朴素如果这份数据将来还要被别的系统读、被别的版本加载、被人手工检查就走逻辑如果只是把同一套东西原样搬到另一台机器上继续跑就走物理。这条线划清楚了后面选工具就不会纠结。1.2 五种常见方案的能力边界对照我把日常真正会用到的几种方式列成一张表你先对着自己的场景扫一眼再往下看具体命令。这张表里的适用规模是按单机、常规硬件、有维护窗口的前提估的不是绝对值但相对关系是准的。方式输出形态一致性保证并行能力适用规模典型场景mysqldumpSQL 文本--single-transaction快照无单线程几十 G 以内整库备份、小版本迁移、开发环境取样mysqlpumpSQL 文本快照 分库分表并行表级/库级并行百 G 级多库并行导出、需要压缩输出mysqlsh的 dump 工具分片目录 元数据快照 分片一致多线程分片百 G 至 TB 级大规模迁移、云上云下搬运SELECT ... INTO OUTFILE分隔符文本语句级快照无单表千万行级单表数据交付、喂给分析系统文件级拷贝 / 快照二进制数据文件停机或快照点文件系统级任意规模整机迁移、容灾冷备看这张表的时候有两个地方容易被忽略。第一并行能力那一列决定了你的导出时间能不能压缩mysqldump是单线程的你把 CPU 加到 64 核它也只用一个核指望它变快是徒劳的。第二一致性保证那一列决定了这份文件能不能直接拿去恢复用INTO OUTFILE导出多张表的时候每张表是各自独立的快照表与表之间的关联状态不一定对得上这点后面会细说。1.3 一个常被跳过的前置判断动手之前还有个判断必须先做源库现在忙不忙能不能承受这次导出的压力。逻辑导出是纯读操作但它读得凶——全表扫描会把 buffer pool 里的热页挤出去导致线上查询的命中率骤降如果表上还有 MyISAM 引擎--single-transaction对它无效只能靠--lock-tables加读锁那基本等于停写。我的做法是先看一眼实例状态再决定从哪个节点导出SHOW GLOBAL STATUS LIKE Threads_running; SHOW ENGINE INNODB STATUS\G SHOW VARIABLES LIKE read_only;read_only为ON且复制延迟不大的从库是我最优先的导出源。主库留给业务导出这种重活交给从库这个习惯让我躲过了好几次半夜的告警电话。没有从库的话至少把导出时间挪到低峰期并且用nice和ionice把导出进程的优先级压下去nice -n 19 ionice -c2 -n7 mysqldump ... /data/backup/dump.sql这两条命令加起来不到二十个字符但能让磁盘 IO 队列里的导出请求让路给在线业务实测在对延迟敏感的场景下区别非常明显。2. 工具选型为什么 mysqldump 至今还是默认答案2.1 它慢但它把边界情况都替你处理了mysqldump被吐槽最多的就是慢和单线程。这话没错但它的价值不在速度在于它对各种边界情况的覆盖。它默认会导出建表语句、索引定义、字符集和排序规则、自增起始值、存储引擎选项加上--routines --triggers --events之后存储过程、触发器、定时事件也一并带走--single-transaction帮你拿到一个 InnoDB 的一致性快照不用锁表--source-data顺手把 binlog 位点记在文件头部后面做增量恢复有据可依。这些能力组合起来意味着你拿到的是一个自包含的、能独立把库重建起来的文件。这一点在故障恢复场景下价值极高——你不需要再去翻当时的表结构文档不需要回忆那个字段是不是后来手工加的索引文件里全都写着。它真正的短板只有两个单线程以及把行数据序列化成 SQL 文本的开销。前者靠分库分表分批导绕开后者是逻辑导出的固有成本绕不开。所以我的判断是单实例数据量在几十 G 以内mysqldump依然是最省心的选择超过这个量级再考虑并行方案。2.2 并行导出工具解决的是时间窗口不够这个问题mysqlpump的思路是把库和表拆成任务队列用多线程同时导。它的命令形态和mysqldump很像迁移成本低几个关键参数值得记mysqlpump --default-parallelism8 \ --single-transaction \ --compress-outputzstd \ --users \ --databases shop_db order_db /data/backup/all_$(date %F).sql.zst--default-parallelism是每个库内的表级并行度不是全局线程数这一点很容易搞错——如果你有 10 个库、并行度设 8实际可能起 80 个线程把源库打满。我的经验值是总线程数控制在 CPU 核数的 1/2 到 2/3留出余量给在线业务。mysqlsh提供的那套 dump 工具则是另一个量级的方案它把数据切成多个分片文件配上 JSON 元数据支持多线程、块级压缩、断点续传还能直接在目标端做延迟创建索引先导数据最后统一建索引比边导边维护索引快得多。代价是输出不再是单个.sql文件而是一个目录你得用配套的 load 工具才能导回去。这套东西适合几百 G 到 TB 级、需要跨机房搬运、窗口只有几个小时的场景小库用它属于拿高射炮打蚊子。2.3 INTO OUTFILE 的定位是数据交付而不是备份很多资料把SELECT ... INTO OUTFILE和mysqldump并列讲我觉得这个归类容易误导人。它不是备份工具它是数据交付工具把查询结果以最紧凑的格式吐成一个文本文件交给下游的 Excel、分析引擎、数据仓库去消费。它快的核心原因是跳过了 SQL 语法层的拼装——不生成INSERT INTO xxx VALUES (...)这样的前缀后缀纯数据加分隔符序列化成本大幅下降。实测同一张两千万行的表mysqldump导 SQL 格式要七分钟INTO OUTFILE导 TSV 只要两分半文件体积还小三分之一。但它有三个硬伤必须提前知道文件写在服务端主机上不是客户端路径受secure_file_priv限制不包含任何建表语句下游得自己知道字段类型和顺序多表导出时各自独立没有跨表一致性。这三点决定了它只能做数据搬运做不了备份恢复。3. 五套可以直接抄的命令与参数说明3.1 mysqldump 单库导出一条命令里的每个参数都有理由先给一条我认为最稳的模板然后逐项解释为什么这么写mysqldump \ --defaults-extra-file/etc/my_dump.cnf \ --single-transaction \ --source-data2 \ --set-gtid-purgedOFF \ --routines --triggers --events \ --default-character-setutf8mb4 \ --hex-blob \ --databases shop_db \ /data/backup/shop_db_$(date %F_%H%M).sql--defaults-extra-file是我强烈建议的写法把账号密码写进一个权限 600 的配置文件而不是用-p密码明晃晃地挂在命令行上。命令行参数在ps aux里对所有登录用户可见也会被记进~/.bash_history这是最廉价的泄露路径。配置文件内容长这样[client] userdump_user password改成你自己的密码 host127.0.0.1 port3306--single-transaction是 InnoDB 一致性导出的开关它内部做的事是先SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ再START TRANSACTION WITH CONSISTENT SNAPSHOT之后的读取全部基于这个快照。所以你在导出过程中业务写入的数据不会出现在文件里文件里的各张表也处于同一时间点。注意它只对事务引擎有效库里混着 MyISAM 表的话那些表依然会被锁。--source-data2老版本叫--master-data2会把当时的 binlog 文件名和位点以注释形式写进文件头部做增量恢复时这是起点。写成2是注释形式写成1是会实际执行CHANGE MASTER语句除非你确实要一步到位搭复制否则用2。--set-gtid-purgedOFF是踩坑率最高的一个参数。源库开了 GTID 的话默认行为会在文件里写入SET GLOBAL.GTID_PURGED...这份文件导进一个没开 GTID 或者已经有数据的实例会直接报错。除非你就是要把 GTID 位点一起带过去搭主从否则一律关掉。--hex-blob处理二进制字段把 blob 里的字节转成十六进制字面量。不加这个遇到含特殊字节的 blob 字段导出的 SQL 文件在导入时可能因为字符集解析出错而报语法错误。--default-character-setutf8mb4要导出和导入两端保持一致这点后面单独讲。--databases复数和直接写库名的区别是前者会在文件里生成CREATE DATABASE IF NOT EXISTS和USE语句后者不会。3.2 只导结构、只导数据、只导部分表三种变体实际工作里用得最多的反而不是整库导出而是各种裁剪版本。只要表结构不要数据给新环境建空库用mysqldump --defaults-extra-file/etc/my_dump.cnf \ --no-data --routines --triggers --events \ --databases shop_db /data/backup/shop_db_schema.sql--no-data只输出CREATE TABLE几秒钟跑完。反过来只要数据不要结构把--no-data换成--no-create-info。注意这两个开关都不能单独解决导入时索引拖慢速度的问题真要快就得导结构时不带索引导完数据再补建。只导几张表把库名和表名分开写不要用--databasesmysqldump --defaults-extra-file/etc/my_dump.cnf \ --single-transaction --set-gtid-purgedOFF \ shop_db orders order_items /data/backup/orders_part.sql按条件导一部分行这是mysqldump的隐藏能力很多人不知道mysqldump --defaults-extra-file/etc/my_dump.cnf \ --single-transaction --no-create-info \ --wherecreated_at 2025-01-01 AND created_at 2025-02-01 \ shop_db orders /data/backup/orders_202501.sql--where对每张被导出的表都生效所以只导单表时用它最安全多表一起用容易因为字段名不存在而报错。3.3 INTO OUTFILE把大表快速吐成文本导出单表数据到 TSV走服务端文件SELECT id, order_no, user_id, amount, created_at FROM orders WHERE created_at 2025-01-01 INTO OUTFILE /data/export/orders_2025.tsv FIELDS TERMINATED BY \t OPTIONALLY ENCLOSED BY ESCAPED BY \\ LINES TERMINATED BY \n;跑之前先确认两件事SHOW VARIABLES LIKE secure_file_priv; -- 假设返回 /data/export/ -- 那么路径必须在这个目录下否则报 The MySQL server is running with the --secure-file-priv option以及账号得有FILE权限。目标文件必须不存在同名文件已存在会直接报错所以脚本里要养成先删再导的习惯。格式上的几个细节ESCAPED BY \\让制表符、换行符在字段内部被转义避免把一行数据拆成两行OPTIONALLY ENCLOSED BY 处理含分隔符的文本字段NULL 值默认输出成\N这个跟空字符串是有区别的下游解析时要认这个约定。导完立刻做一次行数比对别等下游发现数据少了才回头查SELECT COUNT(*) FROM orders WHERE created_at 2025-01-01;wc -l /data/export/orders_2025.tsv两个数字应该完全一致。差一行多半是最后一行没换行符差很多就是路径或权限出问题了。3.4 mysqldump 的 --tab 模式介于两者之间的折中mysqldump --tab是个被严重低估的选项。它对每张表生成两个文件表名.sql放建表语句表名.txt放制表符分隔的数据数据部分的导出速度和INTO OUTFILE一个量级但省掉了你自己写SELECT的麻烦mysqldump --defaults-extra-file/etc/my_dump.cnf \ --tab/data/export/shop_db \ --fields-terminated-by\t \ --fields-enclosed-by \ --fields-escaped-by\\ \ --lines-terminated-by\n \ shop_db注意它同样受secure_file_priv约束目录必须已经存在且有FILE权限。它没有--single-transaction的一致性保证这个模式下每张表是独立读的所以只适合数据不需要跨表对齐的场景。3.5 文件级导出什么时候该放弃 SQL 文本数据量到了几百 G逻辑导出基本就退出选项了。这时候要么停机冷备要么用文件系统快照。冷备最直接停库、拷目录、起库systemctl stop mysqld rsync -a --delete /var/lib/mysql/ /data/backup/mysql_cold_$(date %F)/ systemctl start mysqld快照方式不用停库但要求数据目录在 LVM 上mysql -e FLUSH TABLES WITH READ LOCK; SYSTEM sleep 3; UNLOCK TABLES; sleep 1 lvcreate -L 50G -s -n mysql_snap /dev/vg_data/lv_mysql mount -o ro /dev/vg_data/mysql_snap /mnt/snap中间那个SYSTEM sleep 3是给lvcreate留的时间窗——FLUSH TABLES WITH READ LOCK只是把脏页刷盘并短暂阻写真正创建快照的瞬间必须在锁持有期内。这个时间窗口宁长勿短锁三秒对业务的影响远小于拿到一个不一致的快照。拿到的快照目录挂到/mnt/snap之后可以用一台临时实例指过去验证能不能起来验证完再打包压缩别把没验过的快照当宝贝存半年。4. 参数背后要算的账几个必须想清楚的数字关系4.1 net_buffer_length 与 max_allowed_packet 的联动这是最容易出问题、也最少有人算清楚的一组参数。mysqldump在生成INSERT语句时会用--net-buffer-length控制单条语句的长度默认 1MB。也就是说它会把尽可能多的行塞进一条INSERT直到接近 1MB 就切下一条。假设一张订单表 5000 万行、平均每行序列化后 200 字节每条语句容纳的行数 ≈ 1048576 ÷ 200 ≈5200 行总语句条数 ≈ 50000000 ÷ 5200 ≈9600 条如果把--net-buffer-length调到 16MB每条语句 ≈ 83000 行总语句条数降到约 600 条这个变化对导入端影响很大。每一条INSERT都意味着一次 SQL 解析、一次事务提交语句数从近万降到六百导入时间通常能省 15% 到 30%。但代价是单条语句变大导入时必须保证max_allowed_packet足够[mysqld] max_allowed_packet 64M [client] max_allowed_packet 64M为什么要 64M 而不是 16M因为 16MB 是净数据量加上语法开销、转义字符膨胀某些字段内容里的引号会被转义成两个字符实际可能到 20MB 出头留一倍余量最稳。客户端和服务端两边都要设只设一边依然会报ERROR 2006 (HY000): MySQL server has gone away。4.2 磁盘空间和耗时的预估方法我习惯在导出前先算三个数算完再动手能避免导到 90% 磁盘满了这种事故。源数据大小SELECT table_name, ROUND(data_length/1024/1024, 2) AS data_mb, ROUND(index_length/1024/1024, 2) AS index_mb FROM information_schema.tables WHERE table_schema shop_db ORDER BY data_length DESC;SQL 文本体积≈ 数据大小 ×1.3 到 1.8。系数取决于字段类型的构成整型多、字段短的表偏 1.3含大量 varchar、text 的表偏 1.8因为每行都要重复写字段名以外的语法结构。压缩后体积纯文本字段的 gzip 压缩比通常在5 到 8 倍也就是 10GB 的 SQL 压完剩 1.5GB 左右。但如果表里有大量已经压缩过的二进制图片、日志块、序列化后的 blob压缩比会掉到 2 倍甚至更低甚至可能因为压缩头开销而变大。这种情况我一般跳过压缩直接传。磁盘预留我按文本体积 × 2预留空间。多出来的那一倍是给压缩过程中的临时文件、以及万一半路失败要重导时留的余地。耗时估算mysqldump的单线程吞吐大致在 20MB/s 到 60MB/s 之间按输出文件算取决于磁盘、CPU 单核性能和字段转义量。10GB 的数据量对应 12 到 15GB 的 SQL 文件大概需要 4 到 8 分钟。如果同时开 gzip 压缩压缩本身是单线程的通常再叠加 30% 到 50% 的时间。4.3 压缩工具的选择gzip、pigz 与 zstd| gzip -c file.sql.gz是最常见的写法但 gzip 只用一个核。机器有 16 个核而你只用一个压缩剩下的 15 个在睡觉这就不太合适了。pigz是多线程版 gzip产出的文件格式完全兼容解压端用普通gunzip就行mysqldump ... | pigz -p $(nproc) -6 /data/backup/dump.sql.gzzstd在同等压缩比下速度比 gzip 快两到三倍压缩比还略好一点代价是解压端也得装 zstdmysqldump ... | zstd -T0 -19 --long27 /data/backup/dump.sql.zst-T0表示用满所有核-19是高压缩等级。不过等级越高越吃 CPU 和内存我一般用-T8 -12这个组合在速度和体积之间比较平衡。注意管道压缩的一个隐患是管道失败不报错。mysqldump中途崩了pigz会正常结束并写出一个看起来完整的.gz文件等你恢复的时候才发现数据是残的。解决办法是加set -o pipefail或者在命令后检查mysqldump的退出码别只看压缩进程的结果。5. 导出之后验证、恢复与常见坑位排查5.1 一份文件能不能用先做这三项检查导出的文件不验证等于没导。我每次都做三步加起来不到十秒第一步看尾部标记。mysqldump正常结束会在文件最后写一行-- Dump completed on 2025-01-01 3:20:15。没有这一行说明中途被打断了。tail -3 /data/backup/shop_db.sql gzip -dc /data/backup/shop_db.sql.gz | tail -3第二步校验压缩包完整性。gzip -t /data/backup/shop_db.sql.gz echo OK zstd -t /data/backup/dump.sql.zst第三步抽查行数。挑一两张核心表比对源库行数和导出文件里的行数。SQL 格式的文件没法直接数行但可以用grep -c数INSERT语句数再乘以平均每语句行数做粗估——这只能发现数量级的偏差精确比对还得靠实际导入到一个临时库。真正的验证只有一个标准把文件导进一个干净的实例跑一遍业务的关键查询结果对得上才算数。这一步没有捷径但可以只验核心库、核心表不必全量。5.2 常见问题速查表下面这些是我这些年真实遇到过的、排查起来最费时间的几类问题按报错关键词整理遇到直接对照。报错或现象根本原因处理方式ERROR 2006 (HY000): MySQL server has gone away单条语句超过max_allowed_packet客户端和服务端都调到 64M同时调小--net-buffer-lengthERROR 2020: Got packet bigger than max_allowed_packet单行数据本身就超过限制大 blob提高到能容纳最大单行或把该表单独用--hex-blob导出Unknown table COLUMN_STATISTICS in information_schema8.0 客户端连 5.x 服务端加--column-statistics0Access denied; you need the PROCESS privilege非 root 账号做一致性导出补授PROCESS、RELOAD、TRIGGER、SHOW VIEW权限导入到一半报Table already exists文件里没有DROP TABLE检查是否误用了--skip-add-drop-table导入后主键冲突目标库已有数据先清空目标表或导出时加--no-create-info后手工控制中文乱码导出导入字符集不一致两端都指定--default-character-setutf8mb4TIMESTAMP 差 8 小时会话时区不同导出加--tz-utc导入前SET time_zone00:00CREATE DEFINER报错目标实例没有对应账号用sed批量替换DEFINER部分或先建账号导出到一半 SSH 断开进程被杀前台运行nohup或tmux里跑输出重定向到日志文件恢复到 90% 磁盘满未预留足够空间按文本体积 2 倍预留或直接用管道流式导入表里最后两条值得多说两句。关于nohup我现在的固定写法是这样nohup sh -c mysqldump ... | pigz -p 8 /data/backup/dump.sql.gz \ /data/backup/dump.log 21 echo $! /data/backup/dump.pid把 PID 记下来后面要监控进度或者中途要停都有抓手。关于磁盘有个省事的做法不完全依赖本地磁盘直接管道推到另一台机器的磁盘上mysqldump ... | gzip -1 | ssh backup_host cat /data/backup/dump.sql.gz压缩等级调到-1是因为网络带宽通常比 CPU 更早成为瓶颈压太快没意义。5.3 字符集、时区和 DEFINER 这三个隐性雷区字符集的问题通常不是表是 utf8mb4 但导出成了 latin1这么明显而是更隐蔽的一层连接层的character_set_client和表定义的字符集不一致时某些特殊字符比如生僻字、四字节 emoji会在导出时被替换成问号而且不报错。等你在新环境查出来一堆问号原始数据可能已经被覆盖了。所以导出前后各查一次SHOW VARIABLES LIKE character_set%;导出命令里显式写--default-character-setutf8mb4导入命令里也写一遍两端都锁死。时区的问题集中在TIMESTAMP类型上。DATETIME是字面量存取不受时区影响TIMESTAMP在写入时按会话时区转成 UTC 存读出时再转回会话时区。如果导出会话和导入会话的时区不一样同一个TIMESTAMP值读出来能差好几个小时。mysqldump有个--tz-utc参数默认开启会在文件头加SET TIME_ZONE00:00把整个导出过程锁在 UTC。这个默认值是好的但如果有人为了看着方便把它关了坑就埋下了。DEFINER的问题只在存储过程、视图、触发器上出现。文件里写着CREATE DEFINERapp_user10.0.0.% PROCEDURE ...导到新环境如果没有这个账号和这个网段的主机匹配规则直接报The user specified as a definer does not exist。处理办法有两个一是导出时加--skip-definer部分版本支持二是导出后用sed批量处理sed -i s/DEFINER[^]*[^]*//g /data/backup/shop_db.sql改完一定要grep DEFINER再确认一遍sed的正则写错会把整行搞坏而CREATE语句坏一行就是一整张表导不进去。6. 我在实际项目里固化下来的几条习惯第一条命名带时间戳且精确到分钟。shop_db_2025-01-01_0320.sql.gz这种命名方式在出故障时能救命——你能一眼看出哪个文件是变更前、哪个是变更后不需要靠ls -l的时间去推。我见过太多人用backup.sql、backup_new.sql、backup_final.sql这种命名最后谁也说不清哪个是哪个。第二条导出脚本一定要有退出码检查。一条mysqldump ... file.sql在 shell 里失败了也会返回非零但如果后面接了管道退出码就变成最后一个命令的了。所以脚本里要么开set -o pipefail要么分成两步写先导后压。这个细节没处理好会出现备份任务每天成功、恢复时全是空文件的事故而且往往几个月都发现不了。第三条定期真恢复一次。我给自己定的节奏是每月挑一个非核心库把最新的导出文件完整导进一个临时实例跑一遍关键业务查询比对结果。这个动作花不了半小时但它能发现所有文件看起来正常、实际导不进去的问题——比如权限变了、sql_mode变了、磁盘配额变了。第四条关于导出账号的权限我的原则是给到刚好够用不多给一个。一套够用的最小权限集合大概是这样GRANT SELECT, SHOW VIEW, TRIGGER, LOCK TABLES, PROCESS, RELOAD, REPLICATION CLIENT ON *.* TO dump_user127.0.0.1;REPLICATION CLIENT是为了读 binlog 位点PROCESS在 8.0 上做一致性导出时需要RELOAD在部分场景下执行FLUSH TABLES需要。不要图省事直接给ALL PRIVILEGES一个只读导出账号一旦泄露损失范围完全可控这个差别在事故复盘时非常关键。最后分享一个我自己常用的小组合把体积、速度、可验证性都兼顾到set -o pipefail mysqldump --defaults-extra-file/etc/my_dump.cnf \ --single-transaction --source-data2 --set-gtid-purgedOFF \ --routines --triggers --events --hex-blob \ --default-character-setutf8mb4 \ --databases shop_db \ | zstd -T8 -12 \ /data/backup/shop_db_$(date %F_%H%M).sql.zst \ tail -c 200 /data/backup/shop_db_*.sql.zst /dev/null \ echo export okset -o pipefail保证mysqldump失败时整条命令失败链保证只有导出成功才会打印export ok。脚本末尾看到这行字我才能安心去睡觉。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。