对于Oracle的等待事件,我研究了二十多年,这也是我能够比别人能从AWR报告中看出更多问题的主要原因。目前在D-SMART中,有一个等待事件风险等级模型,通过这个帮助用户及时发现系统中等待事件存在的风险。
在等待事件实时监控的界面中,也提供了对当前系统等待事件的分析概要。
这些功能都是基于对Oracle等待事件多年分析的经验形成的。目前D-SMART中,只有针对Oracle数据库做了等待事件分析的工具,其他数据库还未涉及。这两天突然给了我一个灵感,既然PG数据库已经有了如此丰富的等待事件分类,我们为什么不基于PG数据库来做一个类似的工具呢。
PG的等待事件分为LWLOCK、LOCK、BUFFERPIN、ACTIVITY、IPC、IO、CLIENT、Timeout、EXTENSION九大类,合计接近200个(不同的版本数量不同)。我们完全可以通过对这些等待事件的梳理,形成知识图谱,然后利用知识图谱,实现对PG等待事件的深度分析。并通过等待事件的异常,发现系统存在的潜在问题,对严重的系统问题进行提前预警。
梳理知识图谱是这个工作中最难得一步,虽然PG的等待事件梳理不足Oracle的一半,不过因为我们对PG的研究还刚刚起步,接触到的使用案例也不够多,因此虽然我们可以借助开源项目的源码来理解一些等待事件的产生原因,但是实际上很多等待事件的内因并不简单,因为一段源码可能会在很多不同类型的场景中被使用,因此光是通过静态的源码还是不够的。最重要的是要从实战的案例中获得第一手的资料,来验证我们对某些等待事件的理解是否准确。
我想我们可以在春节后拿出一个初步的版本,来进行实战验证。届时,我也希望有兴趣的朋友可以在他们的系统上采集一些数据发给我们,让我们进行验证,共同改进这个知识图谱。今天上午还有一堆事情要处理,就写这么多吧。作为福利,最后我把我去年梳理了一部分的PG等待事件的表格附在后面,有兴趣的朋友可以下载保存。目前这张表格还没有做完,从中也可以看出我们梳理知识的一些思路吧。
分类 |
名称 |
描述 |
关联根因 |
LWLock |
ShmemIndexLock |
等待在共享内存中分配内存 |
共享内存操作,并发 |
LWLock |
OidGenLock |
等待分配OID |
并发DDL |
LWLock |
XidGenLock |
等待生成事务XID |
并发事务 |
LWLock |
ProcArrayLock |
等待获得snapshot或者在会话结束时清理XID |
并发事务 |
LWLock |
SInvalReadLock |
等待从共享缓冲失效队列中检索或删除消息 |
shared buffers,并发SQL |
LWLock |
SInvalWriteLock |
等待在共享缓冲失效队列中添加消息 |
shared buffers,并发SQL |
LWLock |
WALBufMappingLock |
等待替换 WAL 缓冲区中的页面 |
WAL BUFFER,DML,并发写入 |
LWLock |
WALWriteLock |
等待从WAL缓冲区中写数据到磁盘 |
DML,并发写入,磁盘IO性能 |
LWLock |
ControlFileLock |
等待读取或者修改控制文件,或者创建一个新的WAL文件 |
DML,并发写入,磁盘IO性能 |
LWLock |
CheckpointLock |
等待执行CKPT |
并发事务 |
LWLock |
CLogControlLock |
等待读取或者修改事务状态 |
并发事务 |
LWLock |
SubtransControlLock |
等待读取或者修改子事务信息 |
并发事务,子事务,SAVEPOINT |
LWLock |
MultiXactGenLock |
等待读取或者修改共享组合事务( multixact)状态 |
并发事务,共享组,SAVEPOINT |
LWLock |
MultiXactOffsetControlLock |
等待读取或者修改组合事务(multixact) 偏移映射信息 |
并发事务 |
LWLock |
MultiXactMemberControlLock |
等待读取或者修改组合事务(multixact) 成员映射信息 |
并发事务 |
LWLock |
RelCacheInitLock |
等待读写 relation cache初始化文件(pg_internal.init) |
磁盘IO性能,数据库中表的数量过多 |
LWLock |
CheckpointerCommLock |
等待管理fsync 请求 |
磁盘IO性能,并发写入 |
LWLock |
TwoPhaseStateLock |
等待读取或者修改prepared transaction的状态 |
分布式事务 |
LWLock |
TablespaceCreateLock |
等待创建或者删除表空间 |
表空间操作,磁盘IO性能,文件系统 |
LWLock |
BtreeVacuumLock |
等待读取或者修改vacuum相关的B树索引信息 |
VACUUM,索引 |
LWLock |
AddinShmemInitLock |
等待共享内存中的内存空间管理 |
共享内存初始化 |
LWLock |
AutovacuumLock |
等待Autovacuum worker 或者launcher等待读取或者修改 autovacuum worker的当前状态 |
VACUUM |
LWLock |
AutovacuumScheduleLock |
等待被选择做vacuum 的表仍然需要 vacuuming的确认信息 |
VACUUM |
LWLock |
SyncScanLock |
等待获取表上扫描的开始位置以便于进行同步扫描 |
表或索引扫描操作 |
LWLock |
RelationMappingLock |
等待更新用于存储目录到文件节点映射的关系映射文件 |
DDL操作 |
LWLock |
AsyncCtlLock |
等待读取或者修改共享通知状态 |
会话数,并发执行,并发事务 |
LWLock |
AsyncQueueLock |
等待读取或者修改通知消息 |
会话数,并发执行,并发事务 |
LWLock |
SerializableXactHashLock |
等待检索或者存储serializable事务相关的信息 |
事务隔离级别,并发事务 |
LWLock |
SerializableFinishedListLock |
等待访问serializable 事务完成清单 |
事务隔离级别,并发事务 |
LWLock |
SerializablePredicateLockListLock |
等待在一个被serializable事务锁锁定的清单上做操作 |
事务隔离级别,并发事务 |
LWLock |
OldSerXidLock |
等待读取或记录冲突的可序列化事务 |
事务隔离级别,并发事务 |
LWLock |
SyncRepLock |
等待读取或更新有关同步复制的信息 |
流复制,同步复制 |
LWLock |
BackgroundWorkerLock |
等待读取后者修改后台worker进程的状态 |
并行执行,后台进程启动,后台进程关闭 |
LWLock |
DynamicSharedMemoryControlLock |
等待读取或者修改动态共享内存状态 |
动态共享内存分配、释放 |
LWLock |
AutoFileLock |
等待修改postgresql.auto.conf 文件 |
参数文件修改 |
LWLock |
ReplicationSlotAllocationLock |
等待分配或者始放一个复制槽 |
流复制,复制槽 |
LWLock |
ReplicationSlotControlLock |
等待读取或者修改复制槽状态 |
流复制,复制槽 |
LWLock |
CommitTsControlLock |
等待读取或者修改事务提交时间戳 |
事务提交,页控制相关,DB CACHE,并发事务, |
LWLock |
CommitTsLock |
等待读取或者修改事务时间戳的最后值集合 |
事务提交,并发事务, |
LWLock |
ReplicationOriginLock |
等待设置、删除或使用复制源 |
流复制 |
LWLock |
MultiXactTruncationLock |
等待读取或者截断 multixact 信息 |
事务并发,大事务 |
LWLock |
OldSnapshotTimeMapLock |
等待读取或者修改旧的snapshot控制信息 |
事务并发,SAVEPOINT |
LWLock |
BackendRandomLock |
等待生成随机数 |
随机数生成 |
LWLock |
LogicalRepWorkerLock |
等待逻辑复制的WORKER结束任务 | |
LWLock |
CLogTruncationLock |
等待执行txid_status 或者将可获得的最老的transaction id赋给它 | |
LWLock |
WrapLimitsVacuumLock |
等待修改multixact消耗和transaction id的限制 | |
LWLock |
NotifyQueueTailLock |
等待修改通知消息存储限制 | |
LWLock |
clog |
等待CLOG缓冲区的IO操作 | |
LWLock |
commit_timestamp |
等待 commit timestamp buffer IO操作完成 | |
LWLock |
subtrans |
等待 subtransaction buffer IO操作完成 | |
LWLock |
multixact_offset |
等待 multixact offset buffer IO操作完成 | |
LWLock |
multixact_member |
等待 multixact_member buffer IO操作完成 | |
LWLock |
async |
等待async (notify) buffer IO完成 | |
LWLock |
oldserxid |
等待oldserxid buffer IO完成 | |
LWLock |
wal_insert |
等待将WAL插入缓冲区 | |
LWLock |
buffer_content |
等待在DB CACHE中读写数据页 | |
LWLock |
buffer_io |
等待数据页IO完成 | |
LWLock |
replication_origin |
等待读取或者修改复制进度 | |
LWLock |
replication_slot_io |
等待复制槽上的IO | |
LWLock |
proc |
等待读取或者修改快速路径锁的信息 | |
LWLock |
buffer_mapping |
等待将数据块与缓冲池中的缓冲区关联 | |
LWLock |
lock_manager |
在并行执行中,等待为后端添加或检查锁,或者等待加入或退出锁组 | |
LWLock |
predicate_lock_manager |
等待添加或检查谓词锁信息 | |
LWLock |
parallel_query_dsa |
等待并行查询动态共享内存分配锁 | |
LWLock |
tbm |
等待 TBM 共享迭代器锁 | |
Lock |
relation |
等待获取关系上的锁 | |
Lock |
extend |
等待扩展 relation结束 | |
Lock |
frozenid |
等待修改 pg_database.datfrozenxid和 pg_database.datminmxid. | |
Lock |
page |
等待获取relation中的一个页面的锁 | |
Lock |
tuple |
等待获取元组(tuple)锁 | |
Lock |
transactionid |
等待一个事务结束 | |
Lock |
virtualxid |
等待获取虚拟XID锁 | |
Lock |
speculative token |
等待获取推测插入锁 | |
Lock |
object |
等待一个非关系数据库锁 | |
Lock |
userlock |
等待获取用户锁 | |
Lock |
advisory |
等待获取建议用户锁 | |
BufferPin |
BufferPin |
等待获得BUFFER的PIN锁 | |
Activity |
ArchiverMain |
归档进程的主循环等待 | |
Activity |
AutoVacuumMain |
autovacuum启动进程的主循环等待 | |
Activity |
BgWriterHibernate |
后台写入进程等待,正在休眠 | |
Activity |
BgWriterMain |
bgwriter进程的主循环等待 | |
Activity |
CheckpointerMain |
CKPT进程主循环等待 | |
Activity |
LogicalApplyMain |
逻辑应用进程主循环等待 | |
Activity |
LogicalLauncherMain |
逻辑启动进程主循环等待 | |
Activity |
PgStatMain |
统计信息采集进程主循环等待 | |
Activity |
RecoveryWalAll |
实例恢复时等待WAL数据流到达 | |
Activity |
RecoveryWalStream |
在恢复时再次尝试检索 WAL 数据之前,等待任何类型的源(本地、存档或流)中的 WAL 数据不可用时 | |
Activity |
SysLoggerMain |
syslogger进程主循环等待 | |
Activity |
WalReceiverMain |
WAL接收进程主循环等待 | |
Activity |
WalSenderMain |
WAL发送进程主循环等待 | |
Activity |
WalWriterMain |
WAL写进程主循环等待 | |
Client |
ClientRead |
等待读取客户端输入 | |
Client |
ClientWrite |
等待向客户端发送数据 | |
Client |
LibPQWalReceiverConnect |
在 WAL 接收器中等待建立与远程服务器的连接。 | |
Client |
LibPQWalReceiverReceive |
等待 WAL 接收器接收来自远程服务器的数据。 | |
Client |
SSLOpenServer |
等待SSL连接 | |
Client |
WalReceiverWaitStart |
等待启动进程发送初始化复制数据流 | |
Client |
WalSenderWaitForWAL |
在WAL发送进程中等待WAL刷新 | |
Client |
WalSenderWriteData |
在 WAL 发送者进程中处理来自 WAL 接收者的回复时等待任何活动 | |
Extension |
Extension |
等待和extension交换数据或消息 | |
IPC |
BgWorkerShutdown |
等待后台worker关闭 | |
IPC |
BgWorkerStartup |
等待后台worker启动 | |
IPC |
BtreePage |
等待继续并行 B 树扫描所需的页可用(并行索引扫描) | |
IPC |
ExecuteGather |
执行Gather时等待子进程的活动 | |
IPC |
LogicalSyncData |
等待逻辑复制远程服务发送数据,用于初始表同步 | |
IPC |
LogicalSyncStateChange |
等待逻辑复制远程服务改变状态 | |
IPC |
MessageQueueInternal |
等待其他进程连接到共享消息队列中 | |
IPC |
MessageQueuePutMessage |
等待写一条协议消息到共享消息队列中 | |
IPC |
MessageQueueReceive |
等待从共享消息队列中接收字节 | |
IPC |
MessageQueueSend |
等待向共享消息队列发送字节 | |
IPC |
ParallelBitmapScan |
等待并行位图索引扫描初始化 | |
IPC |
ParallelFinish |
等待并行查询worker结束计算 | |
IPC |
ProcArrayGroupUpdate |
当事务结束时等待组leader清除transaction id | |
IPC |
ReplicationOriginDrop |
等待复制源变为非活动状态以被删除 | |
IPC |
ReplicationSlotDrop |
等待复制槽变为非活动状态以被删除 | |
IPC |
SafeSnapshot |
一个READ ONLY DEFERRABLE 事务等待snapshot | |
IPC |
SyncRep |
同步复制时等待远程服务确认 | |
Timeout |
BaseBackupThrottle |
在基础备份时等待限流 | |
Timeout |
PgSleep |
进程处于 pg_sleep等待 | |
Timeout |
RecoveryApplyDelay |
在恢复时因为WAL延迟到达产生的等待 | |
IO |
BufFileRead |
bffered文件读等待 | |
IO |
BufFileWrite |
buffered文件写等待 | |
IO |
ControlFileRead |
等待控制文件读 | |
IO |
ControlFileSync |
等待控制文件写入持久化存储 | |
IO |
ControlFileSyncUpdate |
等待控制文件修改到达持久化存储 | |
IO |
ControlFileWrite |
等待写入控制文件 | |
IO |
ControlFileWriteUpdate |
等待一个修改控制文件的写操作 | |
IO |
CopyFileRead |
COPY命令中的读等待 | |
IO |
CopyFileWrite |
COPY命令中的写等待 | |
IO |
DataFileExtend |
等待 relation数据文件扩展 | |
IO |
DataFileFlush |
等待 relation数据文件写入持久存储 | |
IO |
DataFileImmediateSync |
等待一个立即同步 relation 数据文件写入持久存储 | |
IO |
DataFilePrefetch |
等待从Relation数据文件异步预读数据 | |
IO |
DataFileRead |
等待从relation数据文件读数据 | |
IO |
DataFileSync |
等待 relation 数据文件的变化写入持久存储 | |
IO |
DataFileTruncate |
等待relation 数据文件截断 | |
IO |
DataFileWrite |
等待 relation数据文件写 | |
IO |
DSMFillZeroWrite |
等待向一个动态共享内存文件写入字节0 | |
IO |
LockFileAddToDataDirRead |
向数据字典锁文件添加一行时等待读操作 | |
IO |
LockFileAddToDataDirSync |
向数据字典锁文件添加一行时等待数据写入持久存储 | |
IO |
LockFileAddToDataDirWrite |
向数据字典锁文件添加一行时等待写操作 | |
IO |
LockFileCreateRead |
创建数据字典锁文件时等待读操作 | |
IO |
LockFileCreateSync |
创建数据字典锁文件时等待数据写入持久存储 | |
IO |
LockFileCreateWrite |
创建数据字典锁文件时等待写操作 | |
IO |
LockFileReCheckDataDirRead |
在重新检查数据字典锁文件期间等待读操作 | |
IO |
LogicalRewriteCheckpointSync |
CKPT时等待逻辑重写映射到达持久化存储 | |
IO |
LogicalRewriteMappingSync |
逻辑重写时等待映射数据达到持久化存储 | |
IO |
LogicalRewriteMappingWrite |
逻辑重写时等待写映射数据达到持久化存储 | |
IO |
LogicalRewriteSync |
等待逻辑重写映射到达持久化存储 | |
IO |
LogicalRewriteTruncate |
等待映射数据截断到达持久化存储 | |
IO |
LogicalRewriteWrite |
等待一个逻辑重写映射写操作 | |
IO |
RelationMapRead |
等待Relation Map文件读 | |
IO |
RelationMapSync |
等待Relation Map文件写入持久存储 | |
IO |
RelationMapWrite |
等待Relation Map文件写 | |
IO |
ReorderBufferRead |
RecorderBuffer管理中等待读操作(逻辑复制) | |
IO |
ReorderBufferWrite |
RecorderBuffer管理中等待写操作(逻辑复制) | |
IO |
ReorderLogicalMappingRead |
RecorderBuffer管理中等待逻辑映射文件读操作 | |
IO |
ReplicationSlotRead |
等待复制槽控制文件的读操作 | |
IO |
ReplicationSlotRestoreSync |
当复制槽控制文件从内存中复制时等待该文件写入持久存储 | |
IO |
ReplicationSlotSync |
等待复制槽控制文件写入持久存储 | |
IO |
ReplicationSlotWrite |
等待一个复制槽控制文件写操作 | |
IO |
SLRUFlushSync |
检查点或者数据库关闭的时候,等待 SLRU数据写入持久存储 | |
IO |
SLRURead |
等待SLRU页读取 | |
IO |
SLRUSync |
页写入后等待SLRU数据写入持久存储 | |
IO |
SLRUWrite |
等待 SLRU 页写操作 | |
IO |
SnapbuildRead |
等待读取序列化的历史目录快照 | |
IO |
SnapbuildSync |
等待序列化的历史目录快照写入持久存储 | |
IO |
SnapbuildWrite |
等待写入序列化的历史目录快照 | |
IO |
TimelineHistoryFileSync |
等待通过流式复制接收到的时间线历史文件写入持久存储 | |
IO |
TimelineHistoryFileWrite |
流式复制时等待时间线文件上的一个写操作被收到 | |
IO |
TimelineHistoryRead |
等待时间线历史文件上的读操作 | |
IO |
TimelineHistorySync |
等待新创建的时间线历史文件写入持久存储 | |
IO |
TimelineHistoryWrite |
等待新创建的时间线历史文件上的写操作 | |
IO |
TwophaseFileRead |
等待两阶段状态文件读操作 | |
IO |
TwophaseFileSync |
等待两阶段状态文件写入持久存储 | |
IO |
TwophaseFileWrite |
等待两阶段状态文件写操作 | |
IO |
WALBootstrapSync |
biitstrap的时候等待WAL文件写入持久存储 | |
IO |
WALBootstrapWrite |
bootstrap的时候等待WAL页写操作 | |
IO |
WALCopyRead |
当使用拷贝一个现有的WAL 段创建一个新WAL段的时候等待读操作 | |
IO |
WALCopySync |
当使用拷贝一个现有的WAL 段创建一个新WAL段的时候等待写入持久存储 | |
IO |
WALCopyWrite |
当使用拷贝一个现有的WAL 段创建一个新WAL段的时候等待写操作 | |
IO |
WALInitSync |
等待一个新初始化的WAL文件写入持久存储 | |
IO |
WALInitWrite |
初始化新的WAL文件的时候等待写操作 | |
IO |
WALRead |
等待WAL文件读 | |
IO |
WALSenderTimelineHistoryRead |
在 walsender 时间线命令期间等待从时间线历史文件中读取 | |
IO |
WALSyncMethodAssign |
WAL 同步模式时等待数据写入持久存储 | |
IO |
WALWrite |
等待WAL文件写 |
|
作者:白鳝
选自:《数据库杂谈》