Linux 数据库备份策略实战

1次阅读

应明确排除非事务表并禁用锁表:用–single-transaction配合–skip-lock-tables,–ignore-table排除myisam表,避免全局锁;大库导出需分段处理、大表单独导出并控制每条insert行数;必须校验pg_dump退出码和文件头合法性;rsync同步前须确保压缩完成且使用原子重命名。

Linux 数据库备份策略实战

mysqldump 备份时锁表导致业务卡顿怎么办

默认 mysqldump 对 InnoDB 表会加 READ LOCK,哪怕用了 --single-transaction,一旦遇到非事务表(比如 MyISAM)或显式锁表语句,整个 dump 过程仍可能阻塞写入。
真正安全的做法是:只对 InnoDB 表启用一致性快照,明确排除非事务引擎。

  • --single-transaction(必须搭配 --skip-lock-tables,否则无效)
  • --ignore-table=db.myisam_log 排除非事务表,避免它触发全局锁
  • 确认数据库未开启 autocommit=0 或长事务,否则快照可能拉取到过旧数据
  • 如果必须备份 MyISAM 表,改用 mysqlhotcopy(已弃用)或停写 + FLUSH TABLES WITH READ LOCK 手动操作,不能混用

pg_dump 导出大库慢、内存爆掉怎么调

pg_dump 默认单连接、全量加载到内存再写文件,导出 50GB+ 数据时容易 OOM 或超时。关键不是“加参数”,而是拆解导出动作本身。

  • --section=pre-data / --section=data / --section=post-data 分段导出,把 DDL 和数据分离,便于并行或分片处理
  • 对大表单独用 --table=big_table --inserts 配合 --rows-per-insert=1000,避免单条 INSERT 过长触发 WAL 压力
  • 禁用 --compress(客户端压缩),改用管道接 gzip -1,节省内存且不影响传输效率
  • 注意 work_mem 在 dump 连接里不生效,别在 postgresql.conf 里盲目调高它来“优化 dump”

备份脚本里没校验 pg_dump 返回码就发邮件成功通知

很多脚本用 pg_dump ... > backup.sql 2>/dev/NULL 后直接 echo “success”,但 pg_dump 出错时仍可能生成空文件或截断文件,退出码却是 0 —— 因为重定向掩盖了 stderr,而某些错误(如权限不足读取 pg_largeobject)只报在 stderr。

  • 永远用 set -e 或显式检查 $?,且不重定向 stderr 到 /dev/null
  • --no-unlogged-table-data 避免因 unlogged 表不可读导致静默跳过
  • 导出后立刻用 head -c 100 backup.sql | grep -q "PGDMP" 确认文件头合法,再用 wc -l 看是否明显少于预期行数
  • 不要依赖文件大小判断成败,空库和失败导出都可能产生 1KB 左右的文件

rsync 同步备份到远端时覆盖了正在写的 .sql.gz

rsync 默认按修改时间判断更新,但 gzip 压缩过程是先写临时文件再 rename,如果 rsync 正好扫到中间状态,就会同步一个损坏的半成品。这不是 rsync 的 bug,是使用时机错了。

  • 压缩完再同步:用 gzip -c backup.sql > backup.sql.gz && rsync -av backup.sql.gz user@backup:/backups/
  • 或加原子性保护:压缩到 backup.sql.gz.tmp,成功后再 mv backup.sql.gz.tmp backup.sql.gz,rsync 加 --exclude='*.tmp'
  • 别用 --delete,删错一个正在传输的旧备份可能让恢复链断裂
  • 远程目录用 chattr +a(ext4)锁定仅追加,防止误删或覆盖已有备份文件

备份不是“跑通命令就行”,最常失效的环节藏在退出码、文件完整性、并发写入竞争这些细节里。一次没校验的 $?,可能让半年后的恢复变成一场数据考古。

text=ZqhQzanResources