可行,但必须先将mysqldump输出落地为本地文件再上传;需压缩(推荐gzip -3)、校验MD5、命名含时间戳,并用ossutil/s3cmd/rclone等支持断点续传的CLI工具上传,禁用curl直接管道传输。

用 ossutil / s3cmd / rclone 上传,别用 curl
直接用 curl 传 mysqldump 输出流到对象存储几乎必然失败。OSS、COS、S3 都不接受裸 SQL 流,报 411 Length Required 或静默截断是常态。
真正可靠的做法是:先落地为本地文件 → 压缩 → 计算校验和 → 调用云厂商 CLI 工具上传。
-
ossutil cp、s3cmd put、rclone copy都支持分块上传、自动重试、内置 MD5 校验,且能处理大文件(>2GB) - 别写
curl -X PUT --data-binary @- https://...,它没断点续传,也没进度反馈,上传中断就丢数据 - AWS S3 的
aws s3 cp还会自动设Content-MD5头(需提前配置),OSS 的ossutil上传后返回的x-oss-hash-crc64ecma可用于比对完整性
上传前必须做三件事:压缩、校验、命名带时间戳
不压缩直接传 10GB 的 .sql 文件,上传窗口拉得太长,勒索软件可能趁机加密临时文件;不校验,上传损坏了也不知道;不带时间戳,恢复时根本分不清哪份是最新。
- 压缩用
gzip -3,别用-9—— CPU 占用高、耗时翻倍,压缩率只多 5% 左右 - 校验必须在上传前算:
md5sum backup.sql.gz > backup.sql.gz.md5,上传后再取远端 ETag 或 Content-MD5 比对 - 文件名里塞
$(date +\%Y\%m\%d_\%H\%M\%S),注意 crontab 里%要转义成\%,否则整个备份静默失效
crontab 定时执行失败的常见原因
脚本手动运行 OK,但加进 crontab 就报 command not found 或连不上数据库,基本都是环境问题。
-
crontab默认 PATH 很窄(/usr/bin:/bin),找不到mysqldump或ossutil—— 一律用绝对路径,如/usr/bin/mysqldump、/usr/local/bin/ossutil - 密码明文写在命令里(
-p123456)会被ps aux看见,改用~/.my.cnf,权限必须是600 - 别依赖
~/.bashrc,cron 不读它;开头加export PATH="/usr/local/bin:/usr/bin:/bin"更稳 - 并发风险:同一时间跑两个备份会覆盖或冲突,用
flock -n /tmp/mysql-backup.lock -c "..."加锁
上传成功 ≠ 备份可用
很多脚本只检查 ossutil cp 返回码是 0 就认为成功,但 OSS 的分片上传可能部分失败、ETag 却返回了,文件实际不完整。
- 必须验证远端文件大小和本地一致:
[ $(stat -c "%s" backup.sql.gz) -eq $(ossutil head oss://bucket/backup.sql.gz | grep 'Content-Length' | awk '{print $2}') ] - OSS 的 ETag = MD5(单文件上传时),COS 的 ETag 不是 MD5,得查
Content-MD5响应头;AWS S3 分段上传时 ETag 是 multipart hash,必须显式传--content-md5 - 上传后不做校验,等于没备份 —— 你只是把一份可能损坏的文件搬到了另一个地方
真正的难点不在上传动作本身,而在如何让“上传完成”这件事可验证、可回溯、可审计。校验逻辑漏掉任意一环,云备份就只剩心理安慰。


















