SQLite 在线热备:为什么不能直接 cp 数据库文件

举报
yd_246468676 发表于 2026/11/06 12:44:29 2026/11/06
【摘要】 生产环境里跑着一个小面板,数据库是 SQLite,不到 3MB。每次升级前我都会先备份一份。有一回图省事,直接 cp 了 db 文件,升级出事想回滚,把备份贴回去,启动就报 database disk image is malformed。

生产环境里跑着一个小面板,数据库是 SQLite,不到 3MB。每次升级前我都会先备份一份。有一回图省事,直接 cp 了 db 文件,升级出事想回滚,把备份贴回去,启动就报 database disk image is malformed。数据没全丢,但丢了一整个下午的写入。

那次之后我把备份流程重写了。下面把这件事说清楚:为什么 cp 会坏,以及三种正确做法怎么选。

一、cp 为什么会拿到坏快照

SQLite 在 WAL 模式下工作,一个库对应至少三个文件:主库 .db、预写日志 .db-wal、共享内存索引 .db-shm。

写入不是直接改主库,而是先追加到 WAL,之后某个时刻才 checkpoint 回主库。这意味着两件事:

第一,任何时刻主库文件本身只是"某个历史状态",最新数据还在 WAL 里。只 cp 主库,等于丢掉 checkpoint 之后的所有写入。

第二,checkpoint 是分页搬运的。你在搬运到一半时 cp,主库里就是一半新页、一半旧页的混合体——页校验能过,但语义已经错了,恢复出来是"能打开但数据错乱"。这种情况最坑,因为它不一定当场报错,可能几天后才在对账时暴露。

二、三种做法

做法一:sqlite3 的 .backup 点命令

sqlite3 db ".backup out.db",内部调的就是 backup API,一致性没问题。代价是机器上得有 sqlite3 命令行,容器镜像里经常没有,为了备份再装一个包不值。

做法二:停服后 cp

先停服务,再 cp 三个文件,然后启动。一致性有保证(前提是确实没进程在写),但服务要停,而且容易漏掉 -wal。适合半夜跑批,不适合"升级前顺手备一下"。

做法三:Python 的 backup API(推荐)

标准库自带,零依赖:

import sqlite3, os

def hot_backup(src, dst):

if not os.path.exists(src):

raise FileNotFoundError(src)

s = sqlite3.connect(src)

d = sqlite3.connect(dst)

try:

with d:

s.backup(d) # 在线备份,自动处理 WAL

finally:

s.close()

d.close()

三个细节值得说:

一是 s.backup(d) 会在源库上起一个读事务、页级加锁,不阻塞正常写入(WAL 模式下读不挡写),所以不用停服。

二是目标连接写出的是单文件、不依赖 WAL 的完整库——这一点比 cp 三个文件强得多,拷到别的机器直接能用。

三是备份后要跑一次 PRAGMA integrity_check,返回 ok 才算这份备份可信。

还有个变体:VACUUM INTO 'out.db'(SQLite 3.27+)。一条 SQL 搞定,还顺带压缩空闲页,代价是重建整个库,大库上比 backup API 慢。

三、备份之外别忘的四件事

权限。备份文件里有全量业务数据,落盘就 chmod 600。数据目录里通常还有 JWT 密钥这类单文件,一起备,否则恢复出来的服务谁也登不进去。

保留策略。只留最近 10 份,多的删掉。备份把磁盘写满,是比不备份更常见的故障。

校验而不是"看起来成功"。脚本返回 0 不等于备份可用。至少要 integrity_check 通过、文件大小非零、能 SELECT count(*) 出主表行数。

跨版本。SQLite 向后兼容读旧库,但新版本写的库旧版本可能打不开。升级前留的备份配旧二进制没问题,反过来"用新备份恢复到旧程序"要先确认。

四、现在的升级流程

备份(在线,不停服)→ 改权限并跑完整性检查 → 拉新镜像 → 重建容器 → 健康检查,失败就用备份回滚。

整个流程里,第一步是唯一能在出事之后把你捞回来的东西。它只花两秒,但必须是对的。cp 出来的那一份,往往在最需要它的时候才告诉你 malformed。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。