|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?用户注册
×
上周五晚上六点,开发同事在测试库上跑错了一个 UPDATE,where 条件少写了半截,二十多万行订单状态被刷成同一个值。DBA 组的第一反应是恢复,结果翻配置一看:这个库每周日只做一次 dump database,事务日志按 last-chance threshold 自动 dump 之后就被截断了。也就是说,最多要丢六天的数据,谁也兜不住这个责任。最后是靠开发从应用日志里人工拼出被改的行,加班到凌晨两点才补回来。这篇文章就把 Sybase ASE 的备份恢复体系从头捋一遍,重点讲清楚 dump/load 怎么搭、时间点恢复怎么做,以及为什么"每周一个全量"在出事那天救不了你。
一、具体的问题
很多 ASE 环境的备份策略常年停留在两个状态:要么只有一个周日全量 dump database,中间的日志全被 truncate 掉了;要么知道要 dump transaction,但从来没实际演练过 load,真出事的时候才发现日志备份链断了、设备不全、load 不上去。具体表现有三类:
- 全量备份之间的事务全部丢失。dump database 拿到的只是一个静态的物理快照,周日备份、周五出事,周一到周四的数据没有第二份。
- 日志 dump 链不连续。中间某次手工执行了 truncate_only 或者 no_log(救 1105 的时候),链子就断了,后面的日志备份全部作废,但从断点之后到出事那一刻的数据也全丢。
- load 的顺序和选项搞错。load database 之后忘了 load transaction,或者不知道 until "time" 这个用法,恢复出来的库要么停在很早的时点,要么干脆 online 不起来。
二、核心原理
ASE 的备份恢复是物理级的,理解三条主线就够:
第一,dump database 是整库数据页的物理拷贝,由 Backup Server(sybmultbuf)完成,不占 Adaptive Server 的主引擎资源。它记录的是备份那一刻的落库状态,恢复时 load database 会把库置于 offline 状态等待日志续放。
第二,dump transaction 是事务日志的增量备份。只要日志截断点(truncate point)在 dump 时被推进,两条相邻日志备份之间就是无缝的。时间点恢复的本质是:load 全量,然后按顺序 load 每一份事务日志,最后一份可以指定 until "time" 精确到秒。这条链子的前提是中间没有被 truncate 打断——这正是上一篇讲 1105 应急时强调"no_log 之后必须立刻 dump database"的原因:它是重新起链。
第三,last-chance threshold 自动 dump tran 是日志段的保险丝,但它是"保日志段不爆"的机制,不是备份策略本身。阈值 dump 出来的日志确实进了备份链,但如果没人核对 dump 设备和保留期,链子照样有洞。备份策略要用 cron/作业调度按固定周期主动 dump transaction,阈值 dump 只做兜底。
三、实例参考(动手步骤)
以下场景假设:订单库 orderdb,数据 80GB,日志 20GB,目标是出事后能恢复到出事前一分钟。
步骤 0:确认现状基线
- -- 确认日志没有按检查点自动截断(截断了就做不了时间点恢复)
- sp_helpdb orderdb
- -- 看 status 列,绝不能有 "truncate log on chkpt"
- -- 确认 Backup Server 在跑
- sp_who -- 应能看到 BACKUP SERVER 相关进程
- -- 或者直接在 shell 看 backupserver 进程
- -- 看现有 dump 设备
- sp_helpdevice
复制代码
步骤 1:规划 dump 设备与周期
dump 到文件系统比裸设备好管理,建议每库两个条带并行提速:
- -- 全量:每周日 01:00,两路条带 + 压缩
- dump database orderdb
- to "/backup/orderdb/full_1.dat"
- stripe on "/backup/orderdb/full_2.dat"
- with compression = 2, init
- go
- -- 日志:每 15 分钟一次,工作日高峰可加密到 5 分钟
- dump transaction orderdb
- to "/backup/orderdb/tran_20261015_1200.dat"
- with compression = 2, init
- go
复制代码
用 crontab 或者 ASE 的 job scheduler 驱动,文件名必须带时间戳,脚本里先判断空间再 dump。
步骤 2:验证备份可恢复(备份没验证过等于没备份)
- -- 检查 dump 文件内容与日志链
- load database orderdb
- from "/backup/orderdb/full_1.dat"
- with listonly, header
- go
复制代码
listonly 能列出这份全量对应的日志链起点,tran 备份的 header 能看出它续在哪一份之后。每周抽一份全量 + 当天日志,load 到一台备用机或临时 dataserver 上,跑一遍 dbcc checkalloc / checkdb,确认数据可读。
步骤 3:时间点恢复演练(重点)
假设 12:47 发生误 UPDATE,12:45 有最后一份正常日志备份:
- -- 1. load 全量(周日那份),库进入 offline loading 状态
- load database orderdb
- from "/backup/orderdb/full_1.dat"
- with compression = 2
- go
- -- 2. 按时间顺序依次 load 所有日志备份,普通份不带 until
- load transaction orderdb
- from "/backup/orderdb/tran_20261015_1030.dat"
- with compression = 2
- go
- -- 3. 最后一份用 until 停在误操作前一分钟
- load transaction orderdb
- from "/backup/orderdb/tran_20261015_1230.dat"
- with compression = 2,
- until "Oct 15 2026 12:46:00:000PM"
- go
- -- 4. 联机
- online database orderdb
- go
复制代码
load transaction 是可重入的:如果 until 的时间设早了想再往后放,直接重新执行 load transaction 即可,不需要从全量重来。恢复完成后第一件事是立刻再做一次 dump database,重新起链。
步骤 4:改错恢复的止损路径
如果只是单表被误改且表不大,更快的路子是"并行恢复出副本库、再单表搬回":把 orderdb 的 dump load 到一个临时库名(load database 支持 with file = 指定逻辑页设备时可换库名的场景,更通用的做法是建一个空库名 orderdb_rec,直接 load 进去),online 之后用 bcp / insert-select 把误改表导回主库,全程主库不停服。
四、实操检查清单
- sp_helpdb 确认目标库 status 不含 truncate log on chkpt,含了立即关掉
- Backup Server 进程存活,dump 前先确认而不是事后发现
- 全量每周至少一次,事务日志 15~30 分钟一份,文件名带时间戳且脚本判断磁盘空间
- 日志链完整性:每周核对最近一次 dump transaction 的 header,确认它续在上一次之后
- 每周一次"全量 + 日志"真机恢复演练,dbcc checkalloc 通过才算数
- master 库也要备份(dump database master),并保留 disk init 记录,防止 master 损坏时设备信息无处可查
- dump 目录与数据库数据目录不同盘、不同主机(有条件走 NFS 到备份机)
- 保留期与空间清理脚本绑定,防止 /backup 写满导致当晚 dump 全部失败
- 恢复预案成文:谁执行、load 顺序、until 语法、online 命令,写清到可以直接照抄
几个容易踩的坑
- with truncate_only / no_log 之后再做的时间点恢复,只能恢复到 no_log 那一刻,之后的日志全丢——救急之后立刻 dump database 重起链子,这篇和 1105 那篇是同一枚硬币的两面。
- dump transaction with no_truncate 是数据设备坏了但日志设备还活着时的救命选项,它绕过截断点把日志整个备走,别和普通 dump tran 混用。
- load database 之后如果忘了后续 load transaction 就直接 online,未恢复的日志区间直接作废,库就停在 load 全量的那一刻。
- until 时间用错了时区或格式(ASE 用服务器本地时间,格式要写成 "Oct 15 2026 12:46:00:000PM" 这种),宁可按日志文件的时间戳倒推,也别手敲猜。
- 压缩的 dump(with compression)load 时同样要带 compression 参数,两边设备字符集(-J)也要一致,否则 load 报格式错误。
- 备份脚本成功不等于备份有效:磁盘写满写了一半、NFS 掉线后 dump 报错但 cron 邮件没人看,这类"假成功"只有真恢复演练能兜住。
治理前后对比
orderdb 按 80GB 数据 + 15 分钟日志周期改造后,同一次误 UPDATE 场景的恢复效果:
| 指标 | 改造前(仅周日全量) | 改造后(全量+15min日志) | | 最大数据丢失窗口 | 6 天 | ≤15 分钟 | | 恢复到指定时点能力 | 无 | 精确到秒(until) | | 全量恢复耗时(80GB) | 约 55 分钟 | 约 40 分钟(双条带) | | 日志追加恢复(15 份) | 不可用 | 约 8 分钟 | | 每周恢复演练 | 0 次 | 1 次,dbcc 通过 | | 误改止损路径 | 人工拼日志 | 副本库单表搬回,主库不停服 |
备份体系的价值不在备份那天,而在出事那天。ASE 这套 dump/load 机制本身很皮实,坑都在流程里:链子断没断、备份验证没验证、until 语法练没练过。把清单跑一遍,比出事后再翻文档强得多。 |
|