【DB2 数据库】03 模拟故障排查系列:表空间打满后的扩容与恢复
一、这篇文章要解决什么问题
上一篇文章中,我已经通过一个很小的 DMS 表空间 TS2,成功复现了“表空间被打满”的故障现象。
这一篇文章继续沿着同一个实验环境往下做,重点解决下面几个问题:
- 表空间打满之后,如何判断故障还在
- 表空间打满之后,如何通过扩容恢复
- 扩容前后应该重点观察哪些指标
- 为什么扩容后
High water mark不会自动变小 - 为什么扩容后业务可以立刻恢复写入
如果说上一篇重点是“怎么构造故障”,那么这一篇重点就是:
故障发生后,如何通过扩容把库恢复回来。
二、实验环境
- 操作系统:
SUSE Linux Enterprise Server 12 SP5 - DB2 版本:
DB2 v9.7.0.6 Fix Pack 6 - 实例:
db2inst1 - 数据库:
TESTDB - 故障表空间:
TS2 - 原始容器:
/DB2_DATA/TESTDB/ts2/ts2_01.dat - 扩容后新增容器:
/DB2_DATA/TESTDB/ts2/ts2_02.dat
本次实验基于上一篇已经搭建好的环境继续进行:
TS2是一个很小的手工表空间T3是明确落在TS2的测试表
三、为什么这篇要单独写
“表空间打满”和“表空间扩容恢复”虽然是同一个故障链条上的前后两段,但实际写成博客时,最好拆开。
原因很简单:
- 前一篇重点是复现故障
- 这一篇重点是恢复动作和恢复后观察
这样分开后,每一篇都会更清楚,读者也更容易按需查阅。
四、实验前的起点状态
在开始这篇实验前,我先确认了当前 TS2 的状态。
当时表空间信息是:
Tablespace ID = 5
Name = TS2
Type = Database managed space
Contents = All permanent data. Regular table space.
State = 0x0000
Detailed explanation:
Normal
Total pages = 2000
Useable pages = 1952
Used pages = 160
Free pages = 1792
High water mark (pages) = 160
Page size (bytes) = 4096
Extent size (pages) = 32
Prefetch size (pages) = 32
Number of containers = 1当时 T3 已经重新创建回来,并且库里已有一条测试数据。
也就是说,这次实验的起点是:
TS2可写TS2只有一个容器TS2还没有再次被打满
五、先确认扩容前的容器状态
在真正开始恢复实验之前,我先再次确认 TS2 当前只有一个容器。
执行命令:
db2 list tablespace containers for 5 show detail
# 查看表空间 TS2 当前容器实验时真实输出如下:
Tablespace Containers for Tablespace 5
Container ID = 0
Name = /DB2_DATA/TESTDB/ts2/ts2_01.dat
Type = File
Total pages = 2000
Useable pages = 1952
Accessible = Yes这一步很关键,因为后面扩容是否成功,最直观的判断依据之一就是:
- 容器数有没有从
1变成2
六、再次把 TS2 打满
为了验证扩容动作是否真的能恢复业务,我没有直接扩容,而是先让 TS2 再次进入“打满”状态。
持续插入数据:
i=2
while [ $i -le 50000 ]
do
db2 "insert into T3 values ($i, repeat('X',3000))" || break
i=$((i+1))
done这段脚本的目的很直接:
- 不断向
TS2中的T3插入大字段数据 - 直到表空间再次耗尽可分配页
七、打满之后该看什么
这类故障发生后,我最关注的不是先去猜 SQL 报错,而是立刻看表空间状态。
核心命令:
db2 "select count(*) from T3"
# 查看当前已经成功插入了多少条数据
db2 list tablespaces show detail
# 查看 TS2 的详细状态,重点观察 Free pages
db2 list tablespace containers for 5 show detail
# 再确认故障发生时 TS2 仍然只有一个容器在这一步里,最重要的判断点是:
Free pages是否已经变成0
因为只要 Free pages = 0,就说明当前表空间已经没有新的可分配页。
八、恢复前的核心判断
表空间打满后的恢复动作,不应该一上来就盲目执行。
应该先回答两个问题:
1. 是不是表空间真的满了
看:
Used pagesFree pages
2. 现在有没有多余容器
看:
Number of containerslist tablespace containers
这一步的意义在于:
如果当前只有一个容器,而且 Free pages = 0,那么最直接的恢复方式就是:
增加新的容器
九、准备扩容用的新容器路径
这次实验里,我选择的扩容方式不是修改现有容器大小,而是:
ADD 一个新的容器
先确保路径存在,并且实例用户有权限:
mkdir -p /DB2_DATA/TESTDB/ts2
# 确保 TS2 容器目录存在
chown -R db2inst1:db2iadm1 /DB2_DATA/TESTDB/ts2
# 把目录属主设为实例用户
chmod 755 /DB2_DATA/TESTDB/ts2
# 确保目录权限正常虽然这次的新容器仍然放在同一路径下,但它已经是一个新的容器文件:
ts2_02.dat
十、通过 ADD 新容器扩容 TS2
执行扩容命令:
db2 "alter tablespace TS2 add (file '/DB2_DATA/TESTDB/ts2/ts2_02.dat' 2000)"
# 给 TS2 增加第二个容器文件
# 容器大小同样是 2000 页这一步属于:
手工扩容
不是自动扩容,也不是调整自动扩容策略,而是立刻给表空间增加一个新的物理容器。
十一、扩容后立刻验证
扩容完成后,我没有马上插数据,而是先看表空间状态是否真的变化了。
1. 先看容器数
db2 list tablespace containers for 5 show detail
# 再次查看 TS2 的容器详情2. 再看表空间整体信息
db2 list tablespaces show detail
# 查看 TS2 的 Total pages / Free pages / Number of containers这次实验里,扩容后的真实状态是:
Tablespace ID = 5
Name = TS2
Type = Database managed space
Contents = All permanent data. Regular table space.
State = 0x0000
Detailed explanation:
Normal
Total pages = 4000
Useable pages = 3904
Used pages = 1952
Free pages = 1952
High water mark (pages) = 1952
Page size (bytes) = 4096
Extent size (pages) = 32
Prefetch size (pages) = 64
Number of containers = 2这里最关键的变化是:
Total pages:从2000变成了4000Free pages:从0恢复成了1952Number of containers:从1变成了2
这已经足以说明扩容是成功的。
十二、为什么 High water mark 没有变小
这一步很容易让人困惑。
很多人看到扩容后会下意识以为:
- 总空间变大了
- 空闲页也回来了
- 那么
High water mark也应该变小
其实不是。
High water mark 表示的是:
这个表空间历史上曾经使用到过的最高水位。
所以它记录的是“历史峰值”,不是“当前是否已经恢复”。
这次实验中,扩容后它仍然是:
High water mark = 1952
这是完全正常的。
所以要注意:
- 看当前还能不能继续分配页,重点看
Free pages - 看历史上曾经用到多满,重点看
High water mark
十三、扩容后为什么业务可以立刻恢复
扩容成功后,我继续执行了一条插入:
db2 "insert into T3 values (999999, repeat('R',3000))"
# 扩容后再次插入一条大记录,验证能否恢复写入实验结果是:
DB20000I The SQL command completed successfully.这说明:
扩容后的 TS2 已经重新具备可写能力,业务恢复成功。
十四、这次实验说明了什么
通过这次实验,已经可以清楚地得出下面这些结论:
- 当表空间打满时,只要
Free pages = 0,表空间就已经没有新的可分配页 - 如果当前表空间是手工容器,并且只剩一个容器,那么最直接的恢复方式之一就是
ADD新容器 - 扩容成功后,
Total pages、Free pages、Number of containers都会发生变化 High water mark不会因为扩容而自动下降,因为它表示历史峰值- 只要新的空闲页已经出现,业务就可以继续写入
十五、这篇实验和上一篇的衔接关系
上一篇讲的是:
- 表空间是怎么被打满的
- 删除表后为什么页可以复用
- 为什么空间不会自动返还给操作系统
这一篇讲的是:
- 表空间再次打满后
- 如何通过增加新容器完成恢复
- 恢复后哪些字段会变,哪些字段不会变
所以这两篇连起来,刚好构成一个完整闭环:
- 先制造表空间打满
- 再通过扩容恢复业务
十六、为什么这次选择 ADD,而不是直接讲 EXTEND
理论上,表空间扩容可以有多种方式:
ADD:新增容器EXTEND:扩大已有容器AUTORESIZE:让系统按策略自动扩
但这次实验我优先选择 ADD,原因很简单:
- 容器数变化最直观
- 扩容前后差异最好观察
- 后续写“容器路径异常”“不同盘扩容”等主题时也更好衔接
对入门故障模拟来说,ADD 是最适合先讲清楚的一种方式。
十七、这篇文章最值得记住的三句话
把整篇实验压缩成三句话,就是:
表空间打满后,先看 Free pages 是否为 0。通过 ADD 新容器扩容后,Free pages 会恢复,业务可以继续写入。High water mark 记录的是历史峰值,不会因为扩容而自动下降。
十八、下一篇最自然写什么
基于当前环境,下一篇最自然的方向有两个:
- 继续沿表空间路线,讲
EXTEND和AUTORESIZE - 切换到另一类故障,例如日志空间不足或容器权限异常
如果继续顺着当前脉络往下走,那么最适合的下一篇是:
【DB2 数据库】04 模拟故障排查系列:表空间扩容方式对比(ADD、EXTEND、AUTORESIZE)
这样整个系列会非常成体系。