1. 故障背景
因一些特殊的原因导致系统表pg_authid表中的内容被删除,过后用户自己恢复了所有的User,但是OID是系统生成的已经与原来的不一样,需要修复,用户联系到 乘数科技,然后我们对此情况进行了恢复。
2. 处理方式
由于系统表中OID全部都是原User OID与新User OID对不上,如果将用户表对应的用户的User OID全部更新为新的User OID工作量比较大,所以选择根据原User OID 重建pg_authid表。
由于是系统表,不能直接更新,所以我们创建一张与pg_authid完全相同的中间表my_authid,把这张表的内容换做成原先User OID的值,然后我们关闭数据库,然后用这张中间表的数据文件覆盖系统表pg_authid来完成User OID的修复。
2.1 具体步骤
2.1.1 找出原User OID对应关系
由于系统目前状况psql中使用\l 或者\d 我们看到的Owner都会是Unknow状态,并且会显示出原User的OID,让客户配合梳理出这些对象对应的用户则可以得出原User OID对应关系:
- 原User OID对应关系
16384 | u0124824936 | u023373 | pg_monitor3374 | pg_read_all_settings3375 | pg_read_all_stats3377 | pg_stat_scan_tables4200 | pg_signal_backend10 | postgres
- 新User OID对应关系
postgres=# select oid , rolname from pg_authid;oid | rolname----------+----------------------54036442 | pg_monitor54036443 | pg_read_all_settings54036444 | pg_read_all_stats54036445 | pg_stat_scan_tables54036446 | pg_signal_backend54036447 | u0154036448 | rep54036449 | u0254036441 | postgres
2.1.2 创建一张中间表(my_authid)
首先查看pg_authid表相关信息:
postgres=# SELECT pg_relation_filepath('pg_authid');pg_relation_filepath----------------------global/1260(1 row)postgres=# \d pg_authidTable "pg_catalog.pg_authid"Column | Type | Collation | Nullable | Default----------------+--------------------------+-----------+----------+---------rolname | name | | not null |rolsuper | boolean | | not null |rolinherit | boolean | | not null |rolcreaterole | boolean | | not null |rolcreatedb | boolean | | not null |rolcanlogin | boolean | | not null |rolreplication | boolean | | not null |rolbypassrls | boolean | | not null |rolconnlimit | integer | | not null |rolpassword | text | | |rolvaliduntil | timestamp with time zone | | |Indexes:"pg_authid_oid_index" UNIQUE, btree (oid), tablespace "pg_global""pg_authid_rolname_index" UNIQUE, btree (rolname), tablespace "pg_global"Tablespace: "pg_global"postgres=# SELECT pg_relation_filepath('pg_authid_oid_index');pg_relation_filepath----------------------global/2677(1 row)postgres=# SELECT pg_relation_filepath('pg_authid_rolname_index');pg_relation_filepath----------------------global/2676(1 row)postgres=# \d+ pg_authid_oid_indexIndex "pg_catalog.pg_authid_oid_index"Column | Type | Definition | Storage--------+------+------------+---------oid | oid | oid | plainunique, btree, for table "pg_catalog.pg_authid"Tablespace: "pg_global"postgres=# \d+ pg_authid_rolname_indexIndex "pg_catalog.pg_authid_rolname_index"Column | Type | Definition | Storage---------+---------+------------+---------rolname | cstring | rolname | plainunique, btree, for table "pg_catalog.pg_authid"Tablespace: "pg_global"
- 将表中数据导出并创建my_authid表
copy pg_authid to '/pgsql/data/backup/pg_authid.txt' with (oids);create table my_authid(like pg_authid) with oids;create unique index my_authid_oid_index on my_authid(oid);create unique index my_authid_rolname_index on my_authid(rolname);
- 导数据到my_authid表中
导入之前我们要编辑pg_authid.txt文件将对应的OID修改为原User OID对应的关系。另超级用户postgres的新OID为54036441,我们把原先postgres用户的那一行的用户名改成postgres2,然后再为postgres用户新加一行,这行数据的User OID 为10,其他客户建的业务用户的OID都改成原先的User OID,改完后,我们把文本的数据导入到my_authid中:
copy my_authid from '/pgsql/data/backup/pg_authid.txt' with (oids);VACUUM FULL FREEZE VERBOSE my_authid;vacuum my_authid;
- 查看my_authid相关信息
SELECT pg_relation_filepath('my_authid'), pg_relation_filepath('my_authid_oid_index'), pg_relation_filepath('my_authid_rolname_index');postgres=# SELECT pg_relation_filepath('my_authid'), pg_relation_filepath('my_authid_oid_index'), pg_relation_filepath('my_authid_rolname_index');pg_relation_filepath | pg_relation_filepath | pg_relation_filepath----------------------+----------------------+----------------------base/13806/54036458 | base/13806/54036464 | base/13806/54036465(1 row)
2.1.3 关闭数据库替换pg_authid表对应的物理文件
操作步骤:
- 关闭数据库
- 替换pg_authid表对应的物理文件
//整理出pg_authid表及索引与my_authid表物理文件对应管理global/1260 => base/13806/54036458global/2677 => base/13806/54036464global/2676 => base/13806/54036465//备份原pg_authid表及索引文件mkdir backupcp global/1260* ./backup/.cp global/2677* ./backup/.cp global/2676* ./backup/.//将my_authid表物理文件及索引拷贝覆盖原pg_authid对应的文件及索引cp base/13806/54036458 global/1260cp base/13806/54036458_fsm global/1260_fsmcp base/13806/54036458_vm global/1260_vmcp base/13806/54036464 global/2677cp base/13806/54036465 global/2676
- 检查观察文件时间及对比文件内容是否发生变化
ls -l global/1260*ls -l backup/1260*ls -l global/2677*ls -l backup/2677*ls -l global/2676*ls -l backup/2676*cmp global/1260 backup/1260cmp global/2677 backup/2677cmp global/2676 backup/2676
- 删除系统表cache文件
find . -name "pg_internal.init*"find . -name "pg_internal.init*" |xargs rm
2.1.4 启动数据库
启动数据库查看数据库及表的owner是否正常,发现不再是Unknow状态,进一步检查所有的函数、视图等等,发现这些对象的owner都正常,然后让用户再仔细检查一下,用户反馈都正常,自此恢复结束。