祥积宫 无限进步

【DB2 数据库】06 模拟故障排查系列:表空间容器不可访问(权限异常)实验

一、这篇文章要解决什么问题

前面的几篇实验,我已经把表空间容量这一条线基本讲完整了:

  • 表空间打满
  • ADD 扩容
  • EXTEND 扩容
  • AUTORESIZE 自动扩容

但在真实运维里,表空间出问题并不只有“空间不够”这一种情况。

还有一类非常典型、也非常容易让人一开始看懵的故障:

表空间的底层容器文件还在,但 DB2 突然不让访问了。

这篇文章就专门验证这一类问题。

这次实验的目标有 4 个:

  • 人为构造一个“容器文件权限异常”的故障
  • 观察业务层会报什么错
  • 观察 DB2 会把表空间置成什么状态
  • 验证把权限修好以后,表空间和业务是否能恢复

如果说前几篇讲的是:

空间怎么满,怎么扩

那么这一篇讲的就是:

空间本身没问题,但容器文件访问不了时,DB2 会怎样出故障。

二、实验环境

  • 操作系统:SUSE Linux Enterprise Server 12 SP5
  • DB2 版本:DB2 v9.7.0.6 Fix Pack 6
  • 实例:db2inst1
  • 数据库:TESTDB
  • 实验表空间:TS4
  • 容器文件:/DB2_DATA/TESTDB/ts4/ts4_01.dat
  • 测试表:T5

为了让现象足够干净,这次没有继续复用前面做过容量实验的 TS2TS3,而是单独使用一个新的小表空间 TS4 来做容器访问异常实验。

这样做的好处是:

  • 故障现象不容易被前面历史动作干扰
  • 证据链更清楚
  • 后续写成排障文章时更容易讲明白

三、实验前先打快照

这次实验和前面的“纯插数”不同,因为它会直接修改底层容器文件权限。

所以正式开始前,我先建议打一个快照:

10-准备做TS4容器权限异常实验

原因很简单:

  • 这次会主动制造故障
  • 会让表空间短时间内不可访问
  • 一旦恢复步骤做乱了,快照可以快速回退

这种习惯很重要,因为真实运维里“先留后路”本身就是操作规范的一部分。

四、故障前的基线状态

在真正制造故障前,我先确认了当前环境是否正常。

1. 表空间状态

实验开始前,TS4 的状态如下:

Tablespace ID                        = 8
Name                                 = TS4
Type                                 = Database managed space
Contents                             = All permanent data. Regular table space.
State                                = 0x0000
  Detailed explanation:
    Normal
Total pages                          = 1000
Useable pages                        = 960
Used pages                           = 160
Free pages                           = 800
High water mark (pages)              = 160
Page size (bytes)                    = 4096
Extent size (pages)                  = 32
Prefetch size (pages)                = 32
Number of containers                 = 1

从这里可以确认:

  • TS4 当前处于 Normal
  • 还有可用页
  • 表空间本身没有容量问题

2. 容器状态

继续看容器详情:

Tablespace Containers for Tablespace 8

Container ID                         = 0
Name                                 = /DB2_DATA/TESTDB/ts4/ts4_01.dat
Type                                 = File
Total pages                          = 1000
Useable pages                        = 960
Accessible                           = Yes

这里最关键的是:

  • 容器文件存在
  • Accessible = Yes

3. 业务访问状态

再看测试表 T5

db2 "select count(*) from T5"

1
-----------
          1

  1 record(s) selected.

所以这次实验的起点非常清楚:

  • 业务可访问
  • 表空间正常
  • 容器可访问

五、这次故障是怎么构造的

这次没有删文件,也没有卸载数据盘,而是选择了一个最简单、最可控、最适合教学的办法:

直接把容器文件权限改坏。

故障注入前,容器文件权限是:

-rw------- 1 db2inst1 db2iadm1 4096000 4月 8 10:59 /DB2_DATA/TESTDB/ts4/ts4_01.dat

然后执行:

chmod 000 /DB2_DATA/TESTDB/ts4/ts4_01.dat

改完后,权限变成:

---------- 1 db2inst1 db2iadm1 4096000 4月 8 10:59 /DB2_DATA/TESTDB/ts4/ts4_01.dat

这一步的本质就是:

文件还在,但 DB2 实例用户已经没有任何读写权限。

相比直接删文件,这种做法更适合实验,因为:

  • 故障现象明显
  • 根因清晰
  • 恢复简单可逆

六、故障发生后,业务层先出现了什么现象

权限改坏后,我没有先去看管理命令,而是先从业务访问层去观察。

1. 查询失败

执行:

db2 "select count(*) from T5"

真实返回:

1
-----------
SQL0290N  Table space access is not allowed.  SQLSTATE=55039

2. 写入也失败

执行:

db2 "insert into T5 values (2, repeat('P',3000))"

真实返回:

DB21034E  The command was processed as an SQL statement because it was not a
valid Command Line Processor command.  During SQL processing it returned:
SQL0290N  Table space access is not allowed.  SQLSTATE=55039

这一步很重要,因为它说明:

并不是只有写入失败,连查询也已经失败了。

而且两条 SQL 都指向同一个核心报错:

SQL0290N Table space access is not allowed

这已经可以初步判断:

问题不是表 T5 自己坏了,而是 T5 所在的表空间 TS4 已经不允许访问。

七、再看管理视角:表空间和容器状态发生了什么变化

接下来我再回到管理视角,继续看表空间和容器状态。

1. 表空间状态变成 Offline

执行 db2 list tablespaces show detail 后,TS4 变成了:

Tablespace ID                        = 8
Name                                 = TS4
Type                                 = Database managed space
Contents                             = All permanent data. Regular table space.
State                                = 0x4000
  Detailed explanation:
    Offline

这一步非常关键,因为它说明:

DB2 已经把 TS4 从正常状态打成了 Offline。

2. 容器状态变成不可访问

继续执行:

db2 list tablespace containers for 8 show detail

真实输出如下:

Tablespace Containers for Tablespace 8

Container ID                         = 0
Name                                 = /DB2_DATA/TESTDB/ts4/ts4_01.dat
Type                                 = File
Total pages                          = 1000
Useable pages                        = 960
Accessible                           = No

这里最关键的一行就是:

Accessible = No

到这里,业务层和管理层的现象已经可以完全对上:

  • 业务层:SQL0290N
  • 表空间层:Offline
  • 容器层:Accessible = No

也就是说,这不是单纯的 SQL 报错,而是:

底层容器文件不可访问 -> 表空间下线 -> 业务无法访问

八、诊断日志里 DB2 是怎么写这个故障的

这一步是整个实验里最有价值的排障证据。

查看 db2diag.log 后,可以看到非常明确的系统级报错:

FUNCTION: DB2 Common, OSSe, ossErrorIOAnalysis, probe:100
CALLED  : OS, -, open                             OSERR: EACCES (13)

Target file = /DB2_DATA/TESTDB/ts4/ts4_01.dat

这表示:

  • DB2 在尝试 open 这个文件时
  • 操作系统返回了 EACCES (13)
  • 也就是典型的权限拒绝

后面日志里还继续给出了权限分析:

Information of each subdirectory leading up to the first inaccessible one is shown in the format below :
   <UID>:<GID>:<permissions> (subdirectories)

   101:901:755 (DB2_DATA)
   101:901:755 (TESTDB)
   101:901:755 (ts4)
   101:901:0 (ts4_01.dat)

这一段其实已经把问题说透了:

  • 上层目录都没问题
  • 真正出问题的是 ts4_01.dat
  • 它的权限已经被改成了 0

这时再往下看 DB2 自己的内部错误码,又能看到:

SQLO_ACCD "Access Denied"
SQLB_CONTAINER_NOT_ACCESSIBLE
ADM6081W  The table space "TS4" (ID "8") is in the OFFLINE state

这就把整个故障链彻底闭环了:

  1. OS 层拒绝访问文件
  2. DB2 无法打开容器
  3. 容器被判定为 not accessible
  4. 表空间进入 Offline
  5. 业务访问报 SQL0290N

九、恢复动作其实很简单

既然根因就是权限被改坏,那恢复动作也应该非常直接:

chmod 600 /DB2_DATA/TESTDB/ts4/ts4_01.dat

恢复后再看文件权限:

-rw------- 1 db2inst1 db2iadm1 4096000 4月 8 10:59 /DB2_DATA/TESTDB/ts4/ts4_01.dat

这一步恢复的是:

让 db2inst1 重新具备正常读写这个容器文件的权限。

十、恢复权限后,表空间会不会自动回来

这一步很有学习价值,因为很多人会下意识以为:

是不是还要执行额外的表空间恢复命令?

在这次实验环境里,结果是:

不需要。

权限恢复后,再回到 db2inst1 下检查,发现 TS4 已经自动恢复正常。

1. 表空间恢复为 Normal

Tablespace ID                        = 8
Name                                 = TS4
Type                                 = Database managed space
Contents                             = All permanent data. Regular table space.
State                                = 0x0000
  Detailed explanation:
    Normal
Total pages                          = 1000
Useable pages                        = 960
Used pages                           = 160
Free pages                           = 800
High water mark (pages)              = 160
Page size (bytes)                    = 4096
Extent size (pages)                  = 32
Prefetch size (pages)                = 32
Number of containers                 = 1

2. 容器恢复为可访问

Tablespace Containers for Tablespace 8

Container ID                         = 0
Name                                 = /DB2_DATA/TESTDB/ts4/ts4_01.dat
Type                                 = File
Total pages                          = 1000
Useable pages                        = 960
Accessible                           = Yes

3. 查询恢复正常

db2 "select count(*) from T5"

1
-----------
          1

  1 record(s) selected.

这说明在当前这套环境里:

只要底层权限修复正确,TS4 会自动从 Offline 回到 Normal。

十一、最后再验证一次写入恢复

为了确保不是“只能查,不能写”,我又继续做了一次写入验证。

执行:

db2 "insert into T5 values (2, repeat('R',3000))"
db2 "select count(*) from T5"

真实结果:

DB20000I  The SQL command completed successfully.

然后再查:

1
-----------
          2

  1 record(s) selected.

这说明恢复已经彻底闭环:

  • 查询恢复
  • 写入恢复
  • 表空间恢复
  • 容器恢复

十二、这次实验到底证明了什么

到这里,这次实验实际上已经跑出了一个非常标准的运维故障模型:

1. 容器文件权限异常,会直接影响表空间可用性

即使文件还在,只要 DB2 无法访问它,表空间照样会出问题。

2. 业务报错不一定是 SQL 本身有问题

这次 selectinsert 都报了:

SQL0290N Table space access is not allowed

真正的根因并不在 SQL 语句本身,而是在底层容器不可访问。

3. list tablespace containers 是非常关键的排障命令

因为它能直接告诉你:

  • 容器文件是谁
  • 容器现在能不能访问

这比一上来盲猜问题快得多。

4. db2diag.log 能把根因打到文件权限级别

这次日志里明确给出了:

  • EACCES (13)
  • Access Denied
  • SQLB_CONTAINER_NOT_ACCESSIBLE
  • 文件权限链分析

这就是非常标准的“证据型排障”。

5. 在这套环境里,修复权限后表空间会自动恢复

这次不需要额外执行复杂恢复命令,权限修好以后,TS4 自动从 Offline 回到了 Normal

这一点也很值得记下来,因为它能帮助你判断:

哪些场景只要修底层资源就够,哪些场景还需要进一步的 DB2 恢复动作。

十三、实验结束后的收尾

这次实验结束后,最简单的收尾动作是:

db2 "drop table T5"
db2 terminate

如果想把环境彻底清理干净,也可以进一步执行:

db2 connect to TESTDB
db2 "drop tablespace TS4"
db2 terminate

但如果后面还想继续做“容器路径异常”实验,保留 TS4 会更方便。

十四、把这篇文章压缩成三句话

最后把这次实验压缩成三句话:

  1. 容器文件权限异常,会直接导致表空间 Offline
  2. 业务层常见表现是 SQL0290N,管理层常见表现是 Accessible = No
  3. 修复容器文件权限后,表空间和业务都可以恢复。

十五、到这里,表空间这条线已经从“容量”走到了“可访问性”

前几篇主要讲的是:

  • 空间会不会满
  • 满了怎么扩

而这篇开始进入另外一条非常实战的线:

  • 空间本身没问题
  • 但容器文件不可访问

这类问题在生产里并不少见,尤其是:

  • 权限被误改
  • 挂载异常
  • 存储切换后属主不对
  • 运维脚本误操作

所以这篇实验的价值很高,因为它让你真正看到:

“表空间不可访问” 这件事到底是怎么从底层文件一直传导到业务 SQL 报错的。

十六、下一篇最自然写什么

如果沿着这条线继续往下走,下一篇最自然的方向就是:

【DB2 数据库】07 模拟故障排查系列:表空间容器不可访问(路径异常)实验

因为当前我们已经验证了:

  • 权限异常会让容器不可访问

那下一步最值得继续验证的,就是:

  • 文件路径本身失效
  • 文件被挪走
  • 路径存在但容器不在

这样“容器不可访问”这一类故障,就会从权限问题扩展到路径问题,整个排障知识链也会更完整。

Linux 存储