瀚高数据库创建新数据库卡住问题排查

文章目录

环境

系统平台:银河麒麟 (鲲鹏),Linux x86-64 Red Hat Enterprise Linux 8

版本:9.0.5,4.5.11,4.5.7,4.5.8

症状

1.执行CREATE DATABASE会话长时间挂起无返回,数据库实例不宕机,其他业务SQL可正常执行。

2.部分场景直接抛出报错:

  • template1 被占用:source database "template1" is being accessed by other users
    其他故障报错:锁超时、磁盘空间不足、目录权限拒绝等。
  • 建库会话状态为active,查询该会话pg_stat_activity视图中wait_event_type为Lock;

3.pg_blocking_pids()返回空数组,pg_locks无未授予锁记录,无法通过锁相关函数定位阻塞PID。

问题原因

1.template1模板库存在会话(最常见) CREATE DATABASE默认复制template1模板库;只要template1存在任意连接(idle空闲、idle in transaction、备份/监控工具连接),会直接报错或者会话挂起等待。

该阻塞为数据库上层逻辑校验:建库代码直接检查template1当前连接计数,只要连接数大于0就阻止建库,不会进入底层锁管理器的锁等待队列,锁视图、pg_blocking_pids()均捕获不到阻塞源。

2.长事务、对象锁阻塞:业务长事务持有系统对象锁,造成建库语句锁等待;该场景会话进入锁等待队列,pg_blocking_pids可以识别阻塞pid。

3.存储IO瓶颈:建库需要物理复制模板库文件;磁盘IO打满、await高拖慢复制过程;磁盘/Inode耗尽,无法生成新数据库文件。

4.表空间权限异常:指定表空间建库,表空间目录或上级目录缺少w写入、x进入权限;目录属主不是数据库运行用户;使用NFS/NAS网络存储,存在性能差、锁机制不兼容问题。

5.文件系统异常:目录只读、挂载异常,数据库进程无法新建目录、写入数据文件。

解决方案

复制代码
操作原则:

1、template1会话导致的报错/挂起,锁相关函数查不到阻塞源,必须单独查询template1会话列表;
2、优先使用template0建库,规避template1锁竞争;
3、生产环境终止会话前务必确认会话业务属性,禁止盲目杀会话。
4、以下排查情况,按照问题出现频率由高到低排序。

一、定位会话与阻塞源

sql 复制代码
--1.查看卡住的create database会话
highgo=# SELECT pid,usename,datname,state,wait_event_type,wait_event,now()-query_start AS running_time,query
FROM pg_stat_activity
WHERE query ILIKE '%CREATE DATABASE%' AND pid<>pg_backend_pid();

--2.普通锁阻塞查询
--注意:template1连接导致的报错/挂起,此查询blocking_pid为空,属于预期现象
highgo=# SELECT
  blocked.pid AS blocked_pid,
  blocking.pid AS blocking_pid,
  blocking.datname AS blocking_db,
  blocking.application_name,
  blocking.state,
  blocking.query AS blocking_query
FROM pg_stat_activity blocked
LEFT JOIN pg_stat_activity blocking
  ON blocking.pid = ANY(pg_blocking_pids(blocked.pid))
WHERE blocked.query ILIKE '%CREATE DATABASE%';

--3.【必执行】排查template1上所有会话
--说明:template1存在会话导致故障,只能靠本条SQL定位,锁视图无法捕获
highgo=# SELECT pid,usename,datname,application_name,client_addr,state,
       now()-backend_start AS conn_duration,
       now()-xact_start AS xact_duration,
       query
FROM pg_stat_activity
WHERE datname = 'template1'
ORDER BY backend_start;

--4.查看所有未授予锁,辅助确认锁等待
--有输出:代表发生底层锁管理器锁等待;
--无输出:说明没有锁排队,CREATE DATABASE故障大概率为template1上层逻辑连接数校验限制。
highgo=# SELECT l.pid,l.locktype,l.database,l.mode,l.granted,
       a.usename,a.datname,a.wait_event_type,a.wait_event,a.query
FROM pg_locks l
JOIN pg_stat_activity a ON l.pid = a.pid
WHERE NOT granted;

排查判断逻辑

1.步骤2查询返回blocking_pid不为null:属于普通对象锁阻塞,根据返回结果处理阻塞会话;

2.步骤2查询blocking_pid全部为空:直接看步骤3,如果template1存在会话,即为模板库占用导致故障;

3.步骤4无输出,进一步佐证是template1逻辑层连接数校验,不是锁等待。

阻塞场景 是否进入锁等待队列 pg_locks not granted pg_blocking_pids() 定位方式
template1存在会话(上层逻辑校验) ❌不进入锁队列 无记录 返回空 查询pg_stat_activity where datname='template1'
普通对象/事务锁阻塞 ✅进入锁队列 存在记录 返回阻塞 pid pg_blocking_pids + pg_locks

二、模板库占用导致卡住/报错处理

方案1:直接使用template0模板建库(优先推荐,避开template1锁竞争)

sql 复制代码
highgo=# CREATE DATABASE testdb
WITH TEMPLATE template0
OWNER sysdba
ENCODING 'UTF8'
LC_COLLATE 'C'
LC_CTYPE 'C';

方案2:清理template1异常会话(生产务必确认会话业务属性)

sql 复制代码
--终止template1上除当前会话以外所有连接
highgo=# SELECT pg_terminate_backend(pid)
FROM pg_stat_activity WHERE datname='template1' AND pid<>pg_backend_pid();

--确认template1无残留会话
highgo=# SELECT pid,datname,state FROM pg_stat_activity WHERE datname='template1';

--重新执行建库
highgo=# CREATE DATABASE testdb;

方案3:长期预防,禁止普通业务连接template1

sql 复制代码
highgo=# ALTER DATABASE template1 WITH ALLOW_CONNECTIONS false;

三、处理长空闲事务阻塞

sql 复制代码
--查看空闲事务会话
highgo=# SELECT pid,usename,datname,state,now()-xact_start xact_age,query
FROM pg_stat_activity WHERE state='idle in transaction' ORDER BY xact_age DESC;

--永久开启空闲事务超时,自动释放,时间单位按需调整
highgo=# ALTER SYSTEM SET idle_in_transaction_session_timeout = '30min';
highgo=# SELECT pg_reload_conf();
highgo=# SHOW idle_in_transaction_session_timeout;

四、存储与IO问题处理

sql 复制代码
#1.检查磁盘空间、inode
[root@slave ~]# df -h
[root@slave ~]# df -i

#2.观察磁盘IO负载,%util接近100%、await数值高代表IO瓶颈
[root@slave ~]# iostat -x 2 10

1、磁盘空间不足:清理无用日志/过期归档或者扩容磁盘,严禁直接删除pg_wal、base目录文件。

2、IO打满:避开业务高峰执行CREATE DATABASE,业务高峰期不要批量新建数据库。

五、表空间权限异常修复

sql 复制代码
#1.确认数据库运行用户
[root@slave ~]# ps -ef | grep postgres |grep -v grep

#2.校验表空间目录权限示例,替换为实际表空间路径
[root@slave ~]# su - highgo -c "test -w /data/tbs01 && test -x /data/tbs01 && echo 权限正常 || echo 权限异常"

#3.修复属主和权限
[root@slave ~]# chown highgo:highgo /data/tbs01
[root@slave ~]# chmod 700 /data/tbs01
[root@slave ~]# chmod +x /data

禁止执行chown -R递归修改上层大目录属主;表空间禁止部署NFS/NAS存储,需要迁移本地高性能磁盘。

六、操作后验证

sql 复制代码
--校验数据库创建完成
highgo=# SELECT datname,pg_encoding_to_char(encoding),pg_size_pretty(pg_database_size('testdb'))
FROM pg_database WHERE datname='testdb';
#连接验证
psql -p 5866 -U sysdba -d testdb -c "select current_database()"

七、生产运维建议

1、监控、备份、脚本统一连接highgo库,不要连接template1。

2、生产新建数据库优先指定TEMPLATE template0。

3、开启idle_in_transaction_session_timeout,防止空闲事务长期持有锁。

4、新建数据库避开业务IO高峰期。

补充知识点:瀚高数据库中pg_backend_pid()返回值即为当前会话PID(会话ID),pid <> pg_backend_pid()作用是排除自身会话,避免误杀当前连接。

sql 复制代码
--查看当前会话pid
highgo=# select pg_backend_pid();
相关推荐
瑶总迷弟1 小时前
银河麒麟 V10 ARM64 安装 Oracle 19c 静默部署操作手册
数据库·oracle
飞浪纪元[FWC–FE]2 小时前
Qt 工程创建与 CMake / qmake 构建规范
开发语言·数据库·qt
Ivanqhz2 小时前
MoE + LLM 应用
数据库·人工智能·pytorch·python·深度学习·算法·1024程序员节
Tsuki_tl2 小时前
【总结】Redis五大数据类型应用场景及基本命令
数据库·redis·后端·缓存·缓存中间件·redis命令·redis 五大数据类型
Gauss松鼠会2 小时前
GaussDB 整体架构解析
运维·服务器·网络·数据库·sql·架构·gaussdb
系统集成-鹰翔2 小时前
ERP对接升级提示数据库迁移失败:SQLite逐版本事务到底回滚到哪一步
javascript·数据库·经验分享·后端
西瓜拿铁好喝2 小时前
开源和闭源 AI 办公工具,分别适合谁
java·前端·数据库
代码派2 小时前
业务不停机迁移 MySQL 到 TiDB,NineData 数据增量同步实操演示
数据库·mysql·tidb·ninedata·无停机迁移·增量迁移·全量迁移
Gauss松鼠会2 小时前
GaussDB 中 gsql 与 DBeaver(JDBC)客户端工具查询时间不一致:原因、排查与处理
运维·服务器·数据库·sql·gaussdb·经验总结