大家好,这里是公众号 DBA学习之路,分享一些学习国产数据库路上的知识和经验。
目录
前言
最近,在学习 KingbaseES 数据库时,遇到两道 KCP 考题,分别为:
【单选题】当 KES 实例正在运行时,控制文件丢失,此时执行 checkpoint 操作,会有怎样的结果?
- checkpoint 执行正常
- 实例崩溃
- checkpoint 执行失败,但是实例继续运行
- 不能确定
【单选题】使用什么工具可以重建控制文件?
- sys_resetwal
- sys_controlbuild
- sys_resetcontrol
- sys_rebuild_control
对于上面两道题的详细解析,大家感兴趣可以查看:
这两道题考验了对 KingbaseES 数据库控制文件维护和恢复的知识,经过研究和梳理之后,我写了一篇关于控制文件的维护和恢复文章,详细梳理了 KingbaseES 数据库控制文件的知识,这里分享给大家一起学习。
控制文件介绍
KingbaseES 数据库的控制文件是记录数据库内部信息的重要文件,一但控制文件损坏,数据库将会宕机,且无法启动。
控制文件默认存放在数据文件目录下的 global 目录下:
[kingbase@kes:/home/kingbase]$ cd /data/global/
[kingbase@kes:/data/global]$ ll sys_control
-rw------- 1 kingbase kingbase 8192 10月 8 16:00 sys_control
通过 sys_controldata 命令可以查看控制文件的内容:
[kingbase@kes:/home/kingbase]$ export KINGBASE_DATE=/data
[kingbase@kes:/home/kingbase]$ sys_controldata
sys_control 版本: 1201
Catalog 版本: 202211151
数据库系统标识符: 7418197114018412488
数据库簇状态: 在运行中
sys_control 最后修改: 2024年10月08日 星期二 16时00分11秒
最新检查点位置: 0/1CF23F0
最新检查点的 REDO 位置: 0/1CF23C0
最新检查点的重做日志文件: 000000010000000000000001
最新检查点的 TimeLineID: 1
最新检查点的PrevTimeLineID: 1
最新检查点的full_page_writes: 开启
最新检查点的NextXID: 0:1064
最新检查点的 NextOID: 24576
最新检查点的NextMultiXactId: 1
最新检查点的NextMultiOffsetD: 0
最新检查点的oldestXID: 1032
最新检查点的oldestXID所在的数据库:1
最新检查点的oldestActiveXID: 1064
最新检查点的oldestMultiXid: 1
最新检查点的oldestMulti所在的数据库:1
最新检查点的oldestCommitTsXid:0
最新检查点的newestCommitTsXid:0
最新检查点的时间: 2024年10月08日 星期二 16时00分07秒
不带日志的关系: 0/3E8使用虚假的LSN计数器
最小恢复结束位置: 0/0
最小恢复结束位置时间表: 0
开始进行备份的点位置: 0/0
备份的最终位置: 0/0
需要终止备份的记录: 否
wal_level设置: replica
wal_log_hints设置: 关闭
max_connections设置: 100
max_worker_processes设置: 8
max_wal_senders设置: 10
max_prepared_xacts设置: 0
max_locks_per_xact设置: 64
track_commit_timestamp设置: 关闭
最大数据校准: 8
数据库块大小: 8192
大关系的每段块数: 131072
WAL的块大小: 8192
每一个 WAL 段字节数: 16777216
标识符的最大长度: 64
在索引中可允许使用最大的列数: 32
TOAST区块的最大长度: 1988
大对象区块的大小: 2048
日期/时间 类型存储: 64位整数
正在传递Flloat4类型的参数: 由值
正在传递Flloat8类型的参数: 由值
数据页校验和版本: 0
当前身份验证: c4e1fd6b06f9a8aed87af6ecd6fe351980a0c2d5377215695d959f1af2a2b0a5
数据库模式: 1
身份验证方法模式: 0
控制文件中记录内容如下:
- 建库时生成的静态信息:初始化数据库时产生,固定不变,无需手动维护。
- kingbase.conf 中的配置信息:conf 中的相关参数被修改,会自动更新控制文件,无需手动维护。
- wal 以及 checkpoint 的动态信息:当发生检查点、日志切换等操作,则会自动更新控制文件,无需手动维护。
注意:KES 中的控制文件路径不能改变。
控制文件冗余
控制文件无法手动修改,无法单独备份,只能在使用 sys_rman、sys_basebackup 备份数据库时一起备份控制文件。
启动、关闭和恢复数据库时需要读取控制文件中的相关信息。
通过参数 control_file_copy 可以实现控制文件冗余(多路复用):
-- 参数 control_file_copy 默认不启用
test=# show control_file_copy;
control_file_copy
-------------------
(1 行记录)
启用 control_file_copy:
## 使用 root 用户创建目录 /cf_copy 并设置目录权限
[root@kes ~]# mkdir -p /cf_copy
[root@kes ~]# chown kingbase:kingbase /cf_copy
[root@kes ~]# chmod 700 /cf_copy
[root@kes ~]# su - kingbase
## 查看配置参数示例
[kingbase@kes:/data]$ cat kingbase.conf | grep control_file_copy
# control_file_copy = '' #example: control_file_copy = 'filepath/filename'
#control_file_copy = 'filepath1/filename1;filepath2/filename2'
## 配置 kingbase.conf 文件,这里复制 2 份
[kingbase@kes:/data]$ cat<<-EOF>>/data/kingbase.conf
control_file_copy='/cf_copy/sys_control_1;/cf_copy/sys_control_2'
EOF
## 查看配置后的参数值
[kingbase@kes:/data]$ grep -v "^\s*\(#\|$\)" /data/kingbase.conf | grep control_file_copy
control_file_copy='/cf_copy/sys_control_1;/cf_copy/sys_control_2'
## 重启数据库
[kingbase@kes:/data]$ sys_ctl restart
等待服务器进程关闭 .... 完成
服务器进程已经关闭
等待服务器进程启动 ....2024-10-08 17:10:40.808 CST [9023] 日志: sepapower extension initialized
2024-10-08 17:10:40.812 CST [9023] 日志: 正在启动 KingbaseES V008R006C007B0024 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-28), 64-bit
2024-10-08 17:10:40.812 CST [9023] 日志: 正在监听IPv4地址"0.0.0.0",端口 54321
2024-10-08 17:10:40.812 CST [9023] 日志: 正在监听IPv6地址"::",端口 54321
2024-10-08 17:10:40.813 CST [9023] 日志: 在Unix套接字 "/tmp/.s.KINGBASE.54321"上侦听
2024-10-08 17:10:40.914 CST [9023] 日志: 日志输出重定向到日志收集进程
2024-10-08 17:10:40.914 CST [9023] 提示: 后续的日志输出将出现在目录 "sys_log"中.
完成
服务器进程已经启动
验证参数生效:
test=# show control_file_copy;
control_file_copy
-----------------------------------------------
/cf_copy/sys_control_1;/cf_copy/sys_control_2
(1 行记录)
查看控制文件:
[kingbase@kes:/home/kingbase]$ ll /cf_copy/* -rw------- 1 kingbase kingbase 8192 10月 8 17:10 /cf_copy/sys_control_1 -rw------- 1 kingbase kingbase 8192 10月 8 17:10 /cf_copy/sys_control_2
可以看到数据库配置已经生效,现在有 3 份控制文件。
控制文件恢复
模拟破坏控制文件
登录数据库,对一张测试表 test 插入数据:
test=# \c test system
您现在已经连接到数据库 "test",用户 "system".
test=# \d test
数据表 "public.test"
栏位 | 类型 | 校对规则 | 可空的 | 预设
------+---------+----------+--------+------
id | integer | | |
索引:
"idx_test_id" btree (id)
-- 插入一条数据
test=# insert into test values (1);
INSERT 0 1
-- 人为删除控制文件 /data/global/sys_control
test=# \! rm /data/global/sys_control
-- 插入第二条数据,可以成功插入
test=# insert into test values (2);
INSERT 0 1
-- 可以成功查询,说明删除之后不影响正常的 DML 操作,必须要触发检查点才会报错
test=# select * from test;
id
----
1
2
(2 行记录)
-- 但是手动触发检查点之后,数据库宕机了
test=# checkpoint;
警告: 中断联接, 因为其它服务器进程崩溃
描述: The kingbase has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
提示: 一会儿你将可以重联接数据库并且重复你的命令.
服务器意外地关闭了联接
这种现象通常意味着服务器在处理请求之前
或者正在处理请求的时候意外中止
此时尝试启动数据库,会提示无法找到控制文件,启动失败:
[kingbase@kes:/home/kingbase]$ sys_ctl start
sys_ctl: 其他服务器进程可能正在运行; 尝试启动服务器进程
等待服务器进程启动 ....kingbase: 无法找到数据库系统
预期在目录 "/data" 找到,
但是无法打开文件 "/data/global/sys_control": 没有那个文件或目录
已停止等待
sys_ctl: 无法启动服务器进程
检查日志输出.
当控制文件被破坏后,手动触发检查点,实例会直接崩溃。
control_file_copy 方式(简单推荐)
这时,如果我们配置了控制文件冗余,也就是 control_file_copy 参数,那就很简单了,直接拷贝 /cf_copy 目录下的控制文件到 /data/global 目录下,并且重命名为 sys_control 即可:
[kingbase@kes:/home/kingbase]$ cp /cf_copy/sys_control_1 /data/global/sys_control
再次启动数据库:
[kingbase@kes:/home/kingbase]$ sys_ctl start
sys_ctl: 其他服务器进程可能正在运行; 尝试启动服务器进程
等待服务器进程启动 ....2024-10-08 17:21:02.689 CST [9321] 日志: sepapower extension initialized
2024-10-08 17:21:02.693 CST [9321] 日志: 正在启动 KingbaseES V008R006C007B0024 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-28), 64-bit
2024-10-08 17:21:02.694 CST [9321] 日志: 正在监听IPv4地址"0.0.0.0",端口 54321
2024-10-08 17:21:02.694 CST [9321] 日志: 正在监听IPv6地址"::",端口 54321
2024-10-08 17:21:02.695 CST [9321] 日志: 在Unix套接字 "/tmp/.s.KINGBASE.54321"上侦听
2024-10-08 17:21:02.797 CST [9321] 日志: 日志输出重定向到日志收集进程
2024-10-08 17:21:02.797 CST [9321] 提示: 后续的日志输出将出现在目录 "sys_log"中.
完成
服务器进程已经启动
suprise,数据库成功启动,此时查看 test 表数据库:
test=# \c test system
您现在已经连接到数据库 "test",用户 "system".
test=# select * from test;
id
----
1
2
(2 行记录)
数据也没有丢失。
sys_resetwal 方式
这种方式是基于没有使用控制文件冗余的情况,需要使用 sys_resetwal 来重建控制文件,相对比较复杂一些。
sys_resetwal 会重置一个 KingbaseES 数据库集簇的预写式日志和控制信息。出于安全原因,使用时必须在命令行中指定数据目录,sys_resetwal 不会使用环境变量 $KINGBASE_DATA。
查看 sys_resetwal 的帮助命令:
[kingbase@kes:/home/kingbase]$ sys_resetwal --help
sys_resetwal 重置一个Kingbase数据库集簇的预写式日志.
用法:
sys_resetwal [选项]... 数据目录
选项:
-c, --commit-timestamp-ids=XID,XID
设置提交时间可以检索到的最老的和最新的事务ID
(0意味着没有变化)
[-D, --kingbase-data=]DATADIR data directory
-e, --epoch=XIDEPOCH 设置下一个事务ID的epoch
-f, --force 强制更新完成
-g, --dbmode 设置数据库模式
-l, --next-wal-file=WALFILE 设置新的WAL最小起始位置
-m, --multixact-ids=MXID,MXID 设置下一个和最旧的多事务ID
-n, --dry-run 不更新,只显示将要执行的操作
-o, --next-oid=OID 设置下一个OID
-O, --multixact-offset=OFFSET 设置下一个多事务偏移量
-V, --version 输出版本信息,然后退出
-x, --next-transaction-id=XID 设置下一个事务ID
--wal-segsize=SIZE WAL段的大小(兆字节)
-?, --help 显示本帮助,然后退出
Report bugs to <kingbase-bugs@kingbase.com.cn>.
首先,我们需要取消 control_file_copy 参数的配置:
## 从 kingbase.conf 文件中注释 control_file_copy 参数配置,vi 修改即可
[kingbase@kes:/data]$ cat kingbase.conf | grep control_file_copy
# control_file_copy = '' #example: control_file_copy = 'filepath/filename'
#control_file_copy = 'filepath1/filename1;filepath2/filename2'
#control_file_copy='/cf_copy/sys_control_1;/cf_copy/sys_control_2'
## 重启数据库生效
[kingbase@kes:/data]$ sys_ctl restart
等待服务器进程关闭 .... 完成
服务器进程已经关闭
等待服务器进程启动 ....2024-10-08 17:25:49.495 CST [9475] 日志: sepapower extension initialized
2024-10-08 17:25:49.499 CST [9475] 日志: 正在启动 KingbaseES V008R006C007B0024 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-28), 64-bit
2024-10-08 17:25:49.499 CST [9475] 日志: 正在监听IPv4地址"0.0.0.0",端口 54321
2024-10-08 17:25:49.499 CST [9475] 日志: 正在监听IPv6地址"::",端口 54321
2024-10-08 17:25:49.500 CST [9475] 日志: 在Unix套接字 "/tmp/.s.KINGBASE.54321"上侦听
2024-10-08 17:25:49.596 CST [9475] 日志: 日志输出重定向到日志收集进程
2024-10-08 17:25:49.596 CST [9475] 提示: 后续的日志输出将出现在目录 "sys_log"中.
完成
服务器进程已经启动
## 删除 /cf_copy 目录下的冗余文件
[kingbase@kes:/data]$ rm -rf /cf_copy/sys_control_*
使用以上同样方式模拟控制文件损坏后,数据库无法成功启动:
[kingbase@kes:/data]$ sys_ctl start
sys_ctl: 其他服务器进程可能正在运行; 尝试启动服务器进程
等待服务器进程启动 ....kingbase: 无法找到数据库系统
预期在目录 "/data" 找到,
但是无法打开文件 "/data/global/sys_control": 没有那个文件或目录
已停止等待
sys_ctl: 无法启动服务器进程
检查日志输出.
此时没有冗余控制文件,只能使用 sys_resetwal 来重建控制文件,这个过程比较复杂,下面进行详细演示。
一般恢复控制文件只需要以下几个参数即可:
| 参数 | 简介 |
|---|---|
| -l | 设置新的 WAL 最小起始位置 |
| -x | 设置下一个事务 ID (NextXID) |
| -m | 设置下一个多事务 ID (NextMultiXactId) 和最旧的多事务 ID (oldestMultiXid) |
| -O | 设置下一个多事务偏移量 (NextMultiOffset) |
| -f | 强制更新完成 |
| -D | 指定数据库主数据目录 |
| -g | 设置数据库模式 |
下面节开始演示 sys_resetwal 如何重建控制文件。
首先需要讲解每一个参数的值是如何获取。
参数 -l
wal 命名格式文件名称为 16 进制的 24 个字符组成,每 8 个字符一组,每组的意义如下:
- 时间线:英文为timeline,是以1开始的递增数字,如1,2,3…
- LogId:32bit长的一个数字,是以0开始递增的数字,如0,1,2,3…
- LogSeg:32bit长的一个数字,是以0开始递增的数字,如0,1,2,3…
| 时间线 | LogId | LogSeg |
|---|---|---|
| 00000001 | 00000000 | 00000002 |
参数 -l 的值是设置新的 WAL 最小起始位置,需要查找 $KINGBASE_DATA/sys_wal 目录下最大的日志文件编号,然后加 1,就可以得到 -l 参数的值:
## 最大文件编号为 000000010000000000000002
[kingbase@kes:/home/kingbase]$ ll /data/sys_wal/*
-rw------- 1 kingbase kingbase 16777216 10月 8 17:28 /data/sys_wal/000000010000000000000001
-rw------- 1 kingbase kingbase 16777216 9月 24 21:13 /data/sys_wal/000000010000000000000002
## 加 1 也就是 000000010000000000000003
000000010000000000000002 + 1 = 000000010000000000000003
这个结果是如何计算的?通过获取的最大文件编号 wal 的十六进制数:000000010000000000000002,进行加 1 的计算过程如下:
- 识别最右边的位:最右边的位是 2,它小于 15(F),所以可以直接加 1。
- 执行加法:将最右边的位 2 加 1 得到 3。
- 更新数值:所有其他位保持不变。
因此,计算过程是:,这是因为在十六进制中,每个位的值是 16 的幂,最右边的位是 ,即 1。当我们将 2 加 1 时,我们得到 3,这在十六进制中是有效的,不需要进位到下一个位。
这里也可以使用 python 计算,比较方便:
import os
import glob
import re
# 获取 WAL 目录路径
wal_directory = os.path.join(os.getenv("KINGBASE_DATA"), "sys_wal")
# 正则表达式匹配十六进制字符串
hex_pattern = re.compile(r'^[0-9A-Fa-f]+$')
# 查找所有符合十六进制格式的文件名并获取最大编号
max_number = max(
(os.path.basename(f) for f in glob.glob(os.path.join(wal_directory, "*"))
if hex_pattern.match(os.path.basename(f))), # 确保文件名是十六进制
key=lambda x: int(x, 16)
)
# 计算下一个编号
next_hex_number = f"{int(max_number, 16) + 1:024X}"
# 打印结果
print(f"最大日志文件编号: {max_number.zfill(24)}") # 确保格式为 24 位
print(f"最大日志文件编号加 1 后的日志: {next_hex_number}")
## 执行后的输出如下
最大日志文件编号: 000000010000000000000002
最大日志文件编号加 1 后的日志: 000000010000000000000003
这里清晰的介绍了如何计算得出参数 -l 的值。
参数 -x
参数 -x 的值是设置下一个事务 ID,需要查找 $KINGBASE_DATA/sys_xact 目录下的最大编号,然后加 1,再在末尾补位 00000,就可以得到 -x 参数的值:
## 最大编号为 0000
[kingbase@kes:/home/kingbase]$ ll /data/sys_xact/*
-rw------- 1 kingbase kingbase 262144 10月 8 17:28 /data/sys_xact/0000
## 加 1 后,末尾补位 00000
0x000100000
这同样也是一个 16 进制数,通过 python 计算可以得到值:
import os
import glob
import re
# 获取 sys_xact 目录路径
xact_directory = os.path.join(os.getenv("KINGBASE_DATA"), "sys_xact")
# 正则表达式匹配十六进制字符串
hex_pattern = re.compile(r'^[0-9A-Fa-f]+$')
# 查找所有符合十六进制格式的文件名并获取最大编号
max_number = max(
(os.path.basename(f) for f in glob.glob(os.path.join(xact_directory, "*"))
if hex_pattern.match(os.path.basename(f))), # 确保文件名是十六进制
key=lambda x: int(x, 16)
)
# 计算下一个编号并在末尾补位 00000
next_id = (int(max_number, 16) + 1) * 0x100000
next_hex_id = f"0x{next_id:09X}"
# 打印结果
print(f"最大事务编号列: {max_number}")
print(f"最大事务编号加 1 末尾补 00000 后的事务 ID: {next_hex_id}")
## 执行后的输出如下
最大事务编号列: 0000
最大事务编号加 1 末尾补 00000 后的事务 ID: 0x000100000
这里需要补位 00000,所以 print 打印出来需要 9 位。
参数 -m
参数 -x 的值有两个,需要查找 $KINGBASE_DATA/sys_multixact/offsets 目录下的最大编号和最小编号:
- 设置下一个多事务 ID:最大编号 + 1,再在末尾补位 0000
- 最旧的多事务 ID:最小编号末尾补位 0000
📢 注意:最旧的多事务 ID 不能为 0,如果为 0 也需要进行加 1 处理。
## 最大和最小均为 0000
[kingbase@kes:/home/kingbase]$ ll /data//sys_multixact/offsets
-rw------- 1 kingbase kingbase 8192 10月 8 17:28 0000
## 最大编号 +1,末尾补位 0000
0x00010000
## 最小编号末尾补位 0000,因为是 0,所以 +1
0x00000001
这同样也是 16 进制数,通过 python 计算可以得到值:
import os
import glob
import re
# 获取 offsets 目录路径
offsets_directory = os.path.join(os.getenv("KINGBASE_DATA"), "sys_multixact", "offsets")
# 正则表达式匹配十六进制字符串
hex_pattern = re.compile(r'^[0-9A-Fa-f]+$')
# 查找以数字开头的文件,并提取编号
log_files = [os.path.basename(f) for f in glob.glob(os.path.join(offsets_directory, "*"))
if hex_pattern.match(os.path.basename(f))]
# 设置最大和最小编号,处理没有文件的情况
max_number = max(log_files, key=lambda x: int(x, 16))
min_number = min(log_files, key=lambda x: int(x, 16))
# 计算下一个多事务 ID 和最旧的多事务 ID
def calculate_ids(max_hex, min_hex):
max_id = (int(max_hex, 16) + 1) * 0x10000
min_id = (int(min_hex, 16) * 0x10000) + (1 if int(min_hex, 16) == 0 else 0)
return f"0x{max_id:08X}", f"0x{min_id:08X}"
# 计算 ID
max_hex_result, min_hex_result = calculate_ids(max_number, min_number)
# 打印结果
print(f"最大多事务编号: {max_number}")
print(f"最小多事务编号: {min_number}")
print(f"下一个多事务 ID: {max_hex_result}")
print(f"下一个最旧的多事务 ID: {min_hex_result}")
## 执行后的输出如下
最大多事务编号: 0000
最小多事务编号: 0000
下一个多事务 ID: 0x00010000
下一个最旧的多事务 ID: 0x00000001
参数 -O
参数 -O 的值是设置下一个多事务偏移量,需要查找 $KINGBASE_DATA/sys_multixact/members 目录下的最大编号,加 1,然后乘以 0xCC80:
## 最大编号为 0000
[kingbase@kes:/home/kingbase]$ ll /data/sys_multixact/members
-rw------- 1 kingbase kingbase 8192 9月 24 21:13 0000
## 加 1,乘以 0xCC80
0xCC80
这同样也是 16 进制数,通过 python 计算可以得到值:
import os
import glob
import re
# 获取多事务成员目录路径
members_directory = os.path.join(os.getenv("KINGBASE_DATA"), "sys_multixact", "members")
# 正则表达式匹配十六进制字符串
hex_pattern = re.compile(r'^[0-9A-Fa-f]+$')
# 查找所有符合十六进制格式的文件名并获取最大编号
max_number = max(
(os.path.basename(f) for f in glob.glob(os.path.join(members_directory, "*"))
if hex_pattern.match(os.path.basename(f))), # 确保文件名是十六进制
key=lambda x: int(x, 16)
)
# 计算下一个编号和下一个事务偏移量
next_number = int(max_number, 16) + 1
next_hex_number = f"0x{next_number:08X}"
next_offset = next_number * 0xCC80
next_hex_offset = f"0x{next_offset:X}"
# 打印结果
print(f"最大多事务成员编号: {max_number}")
print(f"最大编号加1的编号: {next_hex_number}")
print(f"下一个事务偏移量: {next_hex_offset}")
## 执行后的输出如下
最大多事务成员编号: 0000
最大编号加1的编号: 0x00000001
下一个事务偏移量: 0xCC80
参数 -g
参数 -g 的值是数据库兼容模式:
- 1:oracle 风格;
- 0:pg 风格;
获取完参数值后,也就获得了恢复控制文件的命令:
sys_resetwal -f -l 000000010000000000000003 \ -x 0x000100000 \ -m 0x00010000,0x00000001 \ -O 0xCC80 \ -D /data \ -g 1
但是,在执行以上命令之前,需要先手工创建一个空的控制文件和删除 kingbase.pid 文件:
[kingbase@kes:/home/kingbase]$ touch /data/global/sys_control [kingbase@kes:/home/kingbase]$ rm -rf /data/kingbase.pid
执行 sys_resetwal 恢复控制文件:
[kingbase@kes:/home/kingbase]$ sys_resetwal -f -l 000000010000000000000003 \ -x 0x000100000 \ -m 0x00010000,0x00000001 \ -O 0xCC80 \ -D /data \ -g 1 sys_resetwal: 警告: sys_control存在,但已损坏或版本错误;忽略它 重置预写日志
启动数据库:
[kingbase@kes:/home/kingbase]$ sys_ctl start
等待服务器进程启动 ....2024-10-08 22:17:41.248 CST [16714] 日志: sepapower extension initialized
2024-10-08 22:17:41.252 CST [16714] 日志: 正在启动 KingbaseES V008R006C007B0024 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-28), 64-bit
2024-10-08 22:17:41.253 CST [16714] 日志: 正在监听IPv4地址"0.0.0.0",端口 54321
2024-10-08 22:17:41.253 CST [16714] 日志: 正在监听IPv6地址"::",端口 54321
2024-10-08 22:17:41.254 CST [16714] 日志: 在Unix套接字 "/tmp/.s.KINGBASE.54321"上侦听
2024-10-08 22:17:41.356 CST [16714] 日志: 日志输出重定向到日志收集进程
2024-10-08 22:17:41.356 CST [16714] 提示: 后续的日志输出将出现在目录 "sys_log"中.
完成
服务器进程已经启动
数据库已经正常启动,访问数据是否正常:
test=# \c test system
您现在已经连接到数据库 "test",用户 "system".
test=# table test;
id
----
1
2
3
4
(4 行记录)
访问正常,控制文件已恢复。
脚本一键恢复控制文件
基于 sys_resetwal 命令,对于每个参数的值如何脚本话获取,上面我已经列出了,所以通过脚本的方式一键恢复控制文件也就不难了,我写了一个 python 脚本实现,脚本支持传入 2 个参数:
[kingbase@kes:/home/kingbase]$ python3 recover_controlfile.py --help
usage: recover_controlfile.py [-h] [-cs {1,2}] [-kd KINGBASE_DATA]
KingbaseES 一键恢复控制文件
optional arguments:
-h, --help show this help message and exit
-cs {1,2}, --compatible_style {1,2}
兼容样式: 1-Oracle, 2-PostgreSQL(可选,默认为 1)
-kd KINGBASE_DATA, --kingbase_data KINGBASE_DATA
KINGBASE_DATA 参数(可选)
下面演示一下一键恢复脚本的使用过程,首先模拟控制文件丢失:
test=# \! rm -rf /data/global/sys_control
test=# checkpoint ;
警告: 中断联接, 因为其它服务器进程崩溃
描述: The kingbase has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
提示: 一会儿你将可以重联接数据库并且重复你的命令.
服务器意外地关闭了联接
这种现象通常意味着服务器在处理请求之前
或者正在处理请求的时候意外中止
然后执行一键恢复控制文件脚本:
[kingbase@kes:/home/kingbase]$ python3 recover_controlfile.py
==================================================
WAL 信息:
最大日志文件编号: 00000001000000000000000F
最大日志文件编号加 1 后的日志: 000000010000000000000010
==================================================
==================================================
XACT 事务信息:
最大事务编号列: 0000
最大事务编号加 1 末尾补 00000 后的事务 ID: 0x000100000
==================================================
==================================================
multixact 多事务信息:
最大多事务编号: 0000
最小多事务编号: 0000
下一个多事务 ID: 0x00010000
下一个最旧的多事务 ID: 0x00000001
==================================================
==================================================
多事务成员信息:
最大多事务成员编号: 0000
最大编号加 1 的编号: 0x00000001
下一个事务偏移量: 0xCC80
==================================================
==================================================
生成 sys_resetwal 恢复命令:
sys_resetwal -f -l 000000010000000000000010 \
-x 0x000100000 \
-m 0x00010000,0x00000001 \
-O 0xCC80 \
-D /data \
-g 1
==================================================
==================================================
创建一个空控制文件:
b'-rw-r--r-- 1 kingbase kingbase 0 10\xe6\x9c\x88 9 17:03 /data/global/sys_control'
==================================================
==================================================
正在删除 kingbase.pid 文件:
/data/kingbase.pid
==================================================
==================================================
正在执行 sys_resetwal 恢复控制文件:
重置预写日志
sys_resetwal: 警告: sys_control存在,但已损坏或版本错误;忽略它
==================================================
==================================================
恢复的控制文件所在路径及大小如下:
b'-rw-r--r-- 1 kingbase kingbase 8192 10\xe6\x9c\x88 9 17:03 /data/global/sys_control'
==================================================
正在启动数据库:
等待服务器进程启动 ....2024-10-09 17:03:00.573 CST [46332] 日志: sepapower extension initialized
2024-10-09 17:03:00.577 CST [46332] 日志: 正在启动 KingbaseES V008R006C007B0024 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-28), 64-bit
2024-10-09 17:03:00.578 CST [46332] 日志: 正在监听IPv4地址"0.0.0.0",端口 54321
2024-10-09 17:03:00.578 CST [46332] 日志: 正在监听IPv6地址"::",端口 54321
2024-10-09 17:03:00.584 CST [46332] 日志: 在Unix套接字 "/tmp/.s.KINGBASE.54321"上侦听
2024-10-09 17:03:00.702 CST [46332] 日志: 日志输出重定向到日志收集进程
2024-10-09 17:03:00.702 CST [46332] 提示: 后续的日志输出将出现在目录 "sys_log"中.
完成
服务器进程已经启动
恭喜!控制文件还原成功!!!
一键恢复完成,数据库成功开启:
test=# \c test system
您现在已经连接到数据库 "test",用户 "system".
test=# table test;
id
----
1
2
3
4
(4 行记录)
数据库可以正常访问。
写在最后
控制文件不仅记录着数据库的重要信息,还直接影响着数据库的运行状态,所以我们不仅要做好数据库的日常备份,还应该使用 control_file_copy 参数将控制文件的镜像存放在不同的存储设备上,避免发生单点故障。
最后,希望大家都永不宕机!!!




