本文覆盖托管云数据库的连接、性能、锁与并发、存储与日志四类故障,面向三类读者:应用开发者用它定位连接池、SQL、事务和发布变更引发的问题;数据库运维与 DBA 用它完成证据保全、根因分析、止损、恢复和容量治理;SRE 与云平台工程师用它关联网络、计算、存储、可观测性和高可用事件。
前言
1. 命令标记、占位符和权限
[只读]:不改变数据库业务状态,但仍可能产生负载。
[变更]:修改参数、对象或运行状态;需审批、备份/快照、回滚方案和维护窗口。
[高风险]:可能中断会话、阻塞业务、扩大复制延迟或占用大量磁盘/IO;生产执行需 DBA 与业务负责人双重确认。
统一占位符:<HOST>、<PORT>、<DB>、<SCHEMA>、<TABLE>、<COLUMN>、<VALUE>、<PID>、<USER>、<SLOT>、<CHANNEL>、<PATH>。替换时不要把尖括号保留给 Shell 重定向解析。
Agent 提示词模板额外使用 <INSTANCE>(实例)、<ENGINE_VER>(引擎与小版本)、<WINDOW>(故障时间窗)、<IMPACT>(影响面)、<ERRTEXT>(报错原文)、<CHANGES>(近期变更);另有 <REGION>(地域)、<WORKSPACE>(Agent 工作空间)、<SLS_PROJECT>(日志服务 Project)、<UMODEL_OBJ>(拓扑对象名)。
客户端命令使用交互式密码提示或权限为 0600 的凭据文件/密钥管理服务;禁止把密码写入命令行、脚本、工单或聊天记录。
MySQL 常需 PROCESS、REPLICATION CLIENT、Performance Schema 视图权限;PostgreSQL 的多数 pg_stat_* 监控视图与 pg_ls_waldir() 等函数可由 pg_monitor 覆盖,但 pg_monitor 并非万能——例如 pg_hba_file_rules 在 PostgreSQL 14 默认仅超级用户可读,pg_monitor 不足;终止其他会话通常需 pg_signal_backend 或更高权限。云数据库可能不授予超级用户,并限制 SUPER、文件系统和部分函数,此时以控制台等价功能为准。
安全连接示例:
# [只读] MySQL:-p 仅触发交互提示,不在命令行提供密码
mysql --connect-timeout=5 -h <HOST> -P <PORT> -u <USER> -p <DB>
# [只读] PostgreSQL:-W 触发交互提示;也可使用受保护的密码文件
psql -W "host=<HOST> port=<PORT> dbname=<DB> user=<USER> connect_timeout=5 sslmode=prefer"
2. 模板怎么用:执行顺序与两段分工
每个场景在排查步骤之后紧跟一份可整段复制的提示词模板,执行顺序固定为技能路由→ 前置检查→ A 段 → B 段。
技能路由:按场景加载对应技能,避免凭记忆操作。
前置检查:第 0.0 项先判断实例是否已被 Workspace EntityStore 纳管,据此选择取数路由;再验证监控接入、日志投递、权限与保留期。任一项不满足,先报数据缺口,不要带着缺失数据源继续推断。
A段是 Agent 自取的证据:指标、日志、链路、事件与 OpenAPI。
B段是必须由 DBA 在实例上执行只读语句后粘贴的输出——执行计划、pg_stat_*、performance_schema 等都属于 B 段,Agent 无权限执行,只能索要。
顺序不能倒:先做完 A 段再按结论决定 B 段索要哪些,避免一次性向 DBA 索要全部输出。
3. 模板怎么用:数据面与取数双路由
模板按阿里云 STAROps 的数据面书写:可读云监控 2.0(含托管 Prometheus 与 ARMS APM 指标)、SLS 日志、ARMS 链路、系统事件与告警、UModel 拓扑,并可调用云平台 OpenAPI 查询实例状态与配置;不具备直连实例执行 SQL 的能力。
实例已纳管走 CMS2_WORKSPACE 路由,starops observe 系列命令优先。
未纳管或该路由无数据走 ALIYUN_RDS 兜底:DescribeDBInstancePerformance 取指标,DescribeSlowLogs 与 DescribeSlowLogRecords 取慢日志,DescribeErrorLogs 取错误日志,DescribeEvents 取事件。
无论走哪一路,都要在证据表标注路由选择与降级原因。
两套路由的时间格式互不通用:前者用 RFC3339 或相对表达式,后者用 UTC ISO 8601。混用不会报错,会静默返回空列表——这是最容易误判成"没有数据"的坑。
换用其他云平台时,按同类产品替换数据源与命令即可;手册正文其余部分保持厂商中立。
4. 模板怎么用:证据、基线与结论的硬规矩
占位符必须全部替换后再提交。未替换的占位符会让 Agent 用假设补齐上下文,得到看似合理但无证据的结论。
基线用默认配方:同一指标近 7 天同一时段的 P50 与 P95,跨周对比取同一星期几;涉及变更时另取变更前 24 小时与变更后等长窗口对比。保留期不覆盖基线窗口时降级为环比或对照实例,并在结论中标注降级。禁止用固定阈值替代基线。
每条证据标注数据源与状态(已验证 / 不可得 / 未验证),每条判定回写基线窗口;无权限或数据源缺失的项列入数据缺口,不参与置信度加成。
仅有指标侧证据时,置信度不得高于中,并说明缺哪一路证据。
指标名、实体 ID 与时间格式一律不许凭命名规律推测;契约里没列出的,确认不到就按不可得处理。
委派 CallInvestigationAgent 之后必须审查返回结果:结果为空或未实质回应故障范围时,由主 Agent 继续用技能与工具完成调查,不因委派失败而结束任务。
Agent的输出是诊断草稿,不是执行许可。标 [变更] 与 [高风险] 的动作仍须按手册的故障分级和证据保全、统一升级与回滚检查单的流程审批与留证。收到结论后按同样标准复核,不要直接采信。
5. 模版怎么用:具体流程
第一步(只做一次):把下一节的通用契约整段写入 STAROps 数字员工的系统提示词,或做成一个自定义 skill 常驻加载。
第二步:发生故障时从手册找到对应场景,复制该场景的 Agent 诊断提示词发给数字员工。已配置契约时,模板中与契约重复的通用段可以不发,只发场景专属部分;不确定发多少就整段发,不会冲突。
第三步:替换占位符后提交,按上一节的硬规矩要求 Agent 产出。
第四步:收到结论后,再决定是否进入处置流程。
# 云数据库故障诊断 Agent 通用契约
# 配置一次即可:写入数字员工的系统提示词或自定义 skill,之后每次诊断都自动生效。
# 场景专属内容(专属输入、指标 Key、采集条目、候选原因)由手册中该场景的 Agent 诊断提示
词给出,本契约不重复。
角色:STAROps 运维诊断 Agent(数字员工)。可用数据面:云监控 2.0(含托管 Prometheus 与
ARMS APM 指标)、SLS 日志、ARMS 链路与调用栈、系统事件与告警、UModel 拓扑,以及云平台
OpenAPI 查询实例状态与配置。
能力边界:不具备直连数据库实例执行 SQL 的能力。凡需在实例内执行的语句,一律列入 B 段向
DBA 索要原始输出,禁止假装已执行或用经验值代替。
【输入】提交前替换全部占位符,缺失项写未知,不要留空
实例:<INSTANCE>;引擎与小版本:<ENGINE_VER>;地域:<REGION>
STAROps 上下文:workspace=<WORKSPACE>;SLS Project=<SLS_PROJECT>
UModel 对象:<UMODEL_OBJ>(该实例在 UModel 中的对象名,用于界定影响面)
故障窗口:<WINDOW>(注明时区);是否仍在持续:是 / 否
影响面:<IMPACT>(受影响业务、失败比例、是否可复现)
报错原文:<ERRTEXT>(原样粘贴,不要改写或截断)
近期变更:<CHANGES>(发版、参数、网络与证书、扩缩容、备份任务,含时间点)
场景专属输入项以手册中该场景的 Agent 诊断提示词为准。
【STAROps 技能路由】按场景加载对应技能,避免凭记忆操作
- 指标与日志查询:builtin.starops.observe(含 metric-route、log-route、alert-event、
change-event、acm-basic 参考)
- RDS 专项巡检:builtin.rds.rds-inspection(含 command-contracts、datasource-routing、
rds-inspection-execution.yaml 参考)
- APM 链路分析:builtin.cms2.apm.apm-analysis(指标漏斗)或 builtin.cms2.apm.trace-analysis
(慢 Trace 诊断)
- SLS 日志查询:builtin.starops.sls-query 或 builtin.sls.sls-sql-generation
- UModel 拓扑:builtin.starops.umodel-operation
- 根因调查:若用户明确要求根因定位或快速/深度调查,调用 CallInvestigationAgent
(diagnosis_mode: fast/deep),region_id 取实例所在地域 <REGION>。
【前置检查】第 0 步。任何一项不满足,先输出数据缺口与补齐动作,不要带着缺失的数据源继续推断
0.0 实例是否已在 CMS 2.0 Workspace EntityStore 中纳管。用 starops observe entity
search --entity-domain acs --entity-type acs.rds.instance --filter <INSTANCE> 确认;
命中则走 CMS2_WORKSPACE 路由(starops observe 优先取指标与日志),未命中则走
ALIYUN_RDS 路由(aliyun rds OpenAPI 兜底),并在证据表标注路由选择与降级原因。
0.1 实例是否已接入云监控 2.0 或托管 Prometheus,且故障窗口与基线窗口内都有数据点。
CMS2_WORKSPACE 路由:starops observe entity metric-data 验证有数据点;
ALIYUN_RDS 路由:aliyun rds DescribeDBInstancePerformance 验证有数据点。
0.2 该场景需要的日志(见手册中该场景的 Agent 诊断提示词)是否已开启并投递到 SLS
<SLS_PROJECT>;未投递则改走 OpenAPI 兜底接口,并说明该路径在粒度与保留期上的限制。SLS
日志寻址见下方数据源映射通则。
0.3 调用该实例的应用是否接入 ARMS APM;未接入时应用侧证据只能由提交人提供。
0.4 UModel 中是否存在 <UMODEL_OBJ> 对象及其依赖关系;缺失则影响面判断降级为人工确认。
用 starops observe entity search --entity-domain acs --entity-type acs.rds.instance
--filter <INSTANCE> 确认实体存在,再用 entity topo / entity neighbor 查依赖。
0.5 当前身份是否具备读取指标、日志与实例 OpenAPI 的权限;缺权限直接列出所缺项,
不要用经验值填补。
0.6 指标与日志保留期是否覆盖基线窗口(默认近 7 天);不覆盖则走基线降级路径并标注。
0.7 手册中该场景 Agent 诊断提示词里的场景专属前置检查项,逐条确认。
【取数参数对照】把语义映射成平台具体值。禁止凭经验猜指标名、实体 ID 与时间格式;
确认不到就标注不可得并降级
实体 ID:输入里的实例名可能只是别名,OpenAPI 必须用 DBInstanceId。先用
DescribeDBInstances 按地域列出实例,用连接地址或备注反查 DBInstanceId,再调其他接口。
四套标识互不通用,逐一确认后写进证据表:
OpenAPI 用 DBInstanceId;SLS 用 <SLS_PROJECT> 加该实例对应的 Logstore;
ARMS 用应用名或 PID;UModel 用 <UMODEL_OBJ>。
取数双路由(优先 CMS2_WORKSPACE,兜底 ALIYUN_RDS):
CMS2_WORKSPACE 路由(实例已纳管时优先):
指标:starops observe entity metric-data --entity-id <DBInstanceId>
--entity-domain acs --entity-type acs.rds.instance
--metric <MetricKey> --time-range <RFC3339_START>/<RFC3339_END>
或:starops observe metric_set query --workspace <WORKSPACE>
--promql '<PromQL>' --time-range <RFC3339_START>/<RFC3339_END>
日志:starops observe entity log-data --entity-id <DBInstanceId>
--entity-domain acs --entity-type acs.rds.instance
--logstore <LOGSTORE> --query '<SPL或SQL>' --time-range <RFC3339_START>/<RFC3339_END>
告警:starops observe alerts query --entity-id <DBInstanceId> --time-range <...>
变更:starops observe changes query --entity-id <DBInstanceId> --time-range <...>
系统事件:starops observe acm_basic event system-query --region <REGION>
--resource-id <DBInstanceId> --time-range <...>
UModel 拓扑:starops observe entity search → entity topo → entity neighbor
→ entity stores
ALIYUN_RDS 路由(实例未纳管或 CMS2 无数据时兜底):
aliyun rds DescribeDBInstances --RegionId <REGION>
aliyun rds DescribeDBInstancePerformance --DBInstanceId <DBInstanceId>
--Key <MetricKey> --StartTime <UTC_START> --EndTime <UTC_END>
aliyun rds DescribeDBInstanceAttribute --DBInstanceId <DBInstanceId>
aliyun rds DescribeParameters --DBInstanceId <DBInstanceId>
aliyun rds DescribeSlowLogs / DescribeSlowLogRecords / DescribeErrorLogs
aliyun rds DescribeEvents --ResourceGroupId <RG>
指标 Key(PostgreSQL):命名与 MySQL 不同,且随内核版本与增强监控开关变化。先从控制台
监控项或托管 Prometheus 的指标列表确认实际名称,不得套用 MySQL_* 命名;确认不到就标注
该指标不可得。
本场景该取哪些指标 Key,以手册中该场景的 Agent 诊断提示词为准;未列出的指标不要凭命名规律推测。
【时间格式对照】两套时间格式互不通用,混用会静默返回空列表
starops observe 系列(CMS2_WORKSPACE 路由):
--time-range 用 RFC3339 或相对表达式,例 2026-09-02T15:00:00Z/2026-09-02T16:00:00Z
或 last_1h / now-15m~now
aliyun rds 系列(ALIYUN_RDS 路由):
DescribeDBInstancePerformance 与 DescribeSlowLogRecords 用 yyyy-MM-ddTHH:mmZ,
例 2026-09-02T15:00Z;后者查询跨度不超过 30 天,起始不得早于当前时间前 30 天。
DescribeSlowLogs 只接受日期 yyyy-MM-ddZ,例 2026-09-02Z;跨度不超过 31 天,
起止为同一天时默认从 08:00 起算 24 小时。
<WINDOW> 若填的是本地时间,先换算成 UTC 再传参,并在证据表里同时写出本地时间与 UTC。
【数据源映射通则】每条证据必须标注取自哪一路,并标状态:已验证 / 不可得(写清缺哪一路与
补齐动作)/ 未验证。不可得的项不参与置信度加成,也不得用推测填空。
本场景各路数据源分别取什么值,见对应场景的 Agent 诊断提示词。
SLS 日志寻址(三级优先,逐级降级):
① Workspace LogSet storage(starops observe entity stores --entity-id <DBInstanceId>
列出该实例已纳管的 LogSet,再用 log_set query 查询)
② CloudLens for RDS 采集策略(starops observe entity log-data 直接按实体查日志,
无需手动定位 Logstore)
③ 默认投递位置:Project=aliyun-product-data-<aliuid>-<region>,
Logstore=slow_error_log(慢日志+错误日志合并投递)或 rds_audit_log(审计日志)
以上三级均取不到时改用 OpenAPI 兜底(DescribeSlowLogs/DescribeSlowLogRecords/
DescribeErrorLogs),并说明该路径在粒度与保留期上的限制。
ARMS APM 取数(PromQL,MetricStore=metricstore-apm-metrics-detail):
- DB 出站指标:arms_db_requests_count / arms_db_requests_duration_sum
(用 sum_over_time_lorc(...[1m]) 聚合,禁用 rate())
按 dest_endpoint label 过滤到目标实例
- 异常层指标:arms_exception_requests_count
按 excepName label 区分超时类(SocketTimeoutException)与拒绝类
(ConnectionRefusedException / ConnectException)
- Trace 检索:starops cms2 trace search --app-name <APP>
--filters 'spanName=connect,statusCode=2'(注意 statusCode 为数字 2,非字符串;
spanName 用 connect 而非 rpc)
- OTel 接入应用只有业务指标(arms_requests_*),无 JVM/系统指标
ARMS 未接入或未开启 DB 埋点时这一路不可得:在证据表标状态为不可得,
把应用侧结论降级为待应用侧确认,不得用指标或日志反推应用内部行为。
降级兜底:客户端网络探测依赖有人能在应用所在容器或子网内执行;无人可执行时标注不可得,
链路结论降级为未验证——平台侧策略正确不等于端到端可达。
降级兜底:B 段证据依赖 DBA 在故障持续期间配合;拿不到就把相关候选原因标为证据不足,
不要用指标侧现象替代。
【基线口径】默认配方,换口径必须写明理由
指标基线:同一指标近 7 天同一时段的 P50 与 P95;跨周对比取同一星期几,避免用全天均值
掩盖峰值。
变更基线:以变更时间点为界,取变更前 24 小时与变更后等长窗口对比。
指标保留期未覆盖基线窗口或数据有缺口时,降级为环比(前 1 小时)或对照实例,并在结论里
标注基线降级。
禁止用固定阈值(如 CPU 80%、缓存命中率 99%)替代基线判断。
【采集步骤】先做 A 段自取,再按 A 段结论决定 B 段索要哪些,避免一次性索要全部输出。
A 段是 Agent 用指标、日志、链路、事件与 OpenAPI 自取的证据;B 段是必须由 DBA 在实例上执
行只读语句后粘贴的原始输出。
A 段与 B 段的具体条目见手册中该场景的 Agent 诊断提示词;B 段语句 Agent 无权限执行,只能
索要输出。
【判定纪律】候选原因清单见手册中该场景的 Agent 诊断提示词,逐条写命中 / 排除 / 证据不足
并给出依据。
每条判定写清依据的数据源、基线窗口与偏离幅度;仅有指标侧证据时置信度不得高于中,
并说明缺哪一路证据。
划清责任边界:数据库侧、客户端与应用侧、网络与托管平台侧。
【CallInvestigationAgent 指引】
若用户明确要求根因定位、快速调查或深度调查,直接调用 CallInvestigationAgent:
description: "<场景名>根因调查"
instruction: 以 <last_user_message/> 开头,保留用户原始输入
region_id: <REGION>(实例所在业务地域,非控制面地域)
diagnosis_mode: fast(默认)或 deep(用户明确要求深度时)
skill: quick-investigation 或 rca
调用后审查返回结果:若结果为空、不可用或未实质性回应故障范围,主 Agent 继续用
上述技能与工具完成调查,不因委派失败而结束任务。
【输出格式】
1) 结论:一句话根因 + 置信度(高 / 中 / 低)
2) 证据表:编号 | 证据 | 数据源(云监控2.0 / SLS / ARMS / 事件 / OpenAPI / UModel /
DBA 粘贴)| 状态(已验证 / 不可得 / 未验证)| 取值 | 采集时间(本地时间与 UTC 各写一次)
3) 基线回写:实际使用的基线窗口与数据源、保留期是否覆盖该窗口、是否降级及原因
4) 根因候选:按可能性排序,逐条写保留或排除的依据
5) 处置建议:分 [只读验证] / [变更] / [高风险] 三档,每档给出前置条件与回滚方式
6) 数据缺口:因无权限或数据源缺失而未验证的项,逐条写清需要谁补什么
一、连接类故障
1. 连接超时/拒绝
1.1 现象描述
应用出现 connect timeout、Connection refused、Can't connect to MySQL server、could not connect to server。超时多指报文未返回或握手未完成;拒绝通常表示目标可达但端口未监听、代理主动拒绝或连接被策略重置,两者不能混为一谈。可能全部节点失败,也可能只有部分可用区、部分副本或部分容器网段失败。
1.2 常见原因
端点或端口配置错误;实例停止、重启、故障切换或代理异常;安全组/防火墙/ACL/路由拒绝;私网 DNS 解析漂移;数据库未监听目标接口;客户端连接超时小于网络实际抖动;连接风暴导致握手排队;应用误用外网/旧集群/只读端点。
1.3 排查步骤
1.3.1 网络连通性检查(ping/telnet/nc)
目的:确认从真实应用来源到数据库端点的三层/四层链路是否可达,并区分“完全不通”“间歇不通”“仅 ICMP 被禁”。
OS/云控制台方法 [只读]:在与应用相同的网络命名空间(同容器、同 ECS/VM、同子网跳板)执行探测;云控制台侧查看实例网络类型、连接地址、可用区和网络诊断/连通性检查工具。
# [只读] 依次验证 DNS、ICMP、TCP;ICMP 失败不能作为 TCP 不通的证据
getent hosts <HOST>
ping -c 4 <HOST>
telnet <HOST> <PORT>
nc -vz -w 5 <HOST> <PORT>
- MySQL 8.0 [只读]:TCP 通后用最小查询验证数据库侧确实接受连接。
mysqladmin --connect-timeout=5 -h <HOST> -P <PORT> -u <USER> -p ping
- PostgreSQL 14+ [只读]
pg_isready -h <HOST> -p <PORT> -d <DB> -t 5
关键判断字段:DNS 解析结果是否落在预期网段;ping 的丢包率与 RTT 是否与历史基线一致;nc/telnet 是超时(多为策略丢弃)还是立即 refused(多为无监听或代理拒绝);mysqladmin ping 返回 mysqld is alive、pg_isready 返回 accepting connections。
下一步:解析地址不对→修正服务发现与私网 DNS;TCP 超时→“端口可达性检查”与“网络连通性故障”场景;立即 refused→“实例运行状态确认”;TCP 与 ping 均正常但客户端仍失败→“连接参数核对(host/port/协议)”。
1.3.2 端口可达性检查
目的:确认目标端口在数据库侧真实监听,且中间设备没有把端口改写、拦截或映射到其他后端。
OS/云控制台方法 [只读]:核对控制台的“连接地址/端口”“读写分离端点”“代理端口”;确认安全组/ACL 放通的是同一端口;在应用主机检查本地出口是否被策略限制。
# [只读] 观察 TCP 握手过程与实际连接的四元组
nc -vz -w 5 <HOST> <PORT>
ss -tn state established "( dport = :<PORT> )"
- MySQL 8.0 [只读]
SHOW VARIABLES WHERE Variable_name IN ('port','mysqlx_port','bind_address','skip_networking');
SELECT @@port AS server_port, @@hostname AS server_host;
- PostgreSQL 14+ [只读]
SELECT name, setting, source, pending_restart
FROM pg_settings
WHERE name IN ('port','listen_addresses','unix_socket_directories');
SELECT inet_server_addr() AS server_addr, inet_server_port() AS server_port;
关键判断字段:port/mysqlx_port 与客户端使用端口一致;bind_address/listen_addresses 覆盖客户端到达的接口;skip_networking 未开启;pending_restart 为 false,否则参数已改但未生效;inet_server_port() 应等于客户端连接端口,不等则说明中间有端口映射或代理。
注意:inet_server_addr()、inet_server_port()(以及后文的 inet_client_addr())在 Unix domain socket 连接下返回 NULL,不要把 NULL 误判为端口映射或代理;判断端口映射必须在 TCP 连接上进行。
下一步:端口不匹配→修正应用配置或代理映射([变更],走审批与最小开放范围);监听地址不含目标接口→按变更流程调整并确认是否需重启;端口正确仍不可达→“网络连通性故障”场景的“安全组规则检查”。
1.3.3 实例运行状态确认
目的:排除实例已停止、正在重启、正在故障切换、被平台限制为只读/保护状态或处于维护窗口这类“非网络”原因。
云控制台方法 [只读]:查看实例状态、事件与运维日志、最近的重启/切换/规格变更/备份任务、可用区与主备角色。
# [只读] 从控制台或云 CLI 读取实例状态与事件(各平台命令不同,此处示意等价操作)
# 关注:运行状态、可用区、主备角色、最近事件时间线、维护计划
- MySQL 8.0 [只读]
SELECT @@hostname, @@port, @@read_only, @@super_read_only,
@@innodb_read_only, VERSION() AS version;
SHOW GLOBAL STATUS LIKE 'Uptime';
- PostgreSQL 14+ [只读]
SELECT pg_is_in_recovery() AS in_recovery,
pg_postmaster_start_time() AS started_at,
current_setting('transaction_read_only') AS read_only,
version();
-- current_setting('transaction_read_only') 只反映当前会话/事务;实例级只读要看上面的 pg_is_in_recovery() 与下面的 default_transaction_read_only
SHOW default_transaction_read_only;
关键判断字段:Uptime/pg_postmaster_start_time() 是否指向刚刚发生的重启;read_only/super_read_only/pg_is_in_recovery() 是否与期望角色一致(写请求连到只读节点会表现为“连上但报错”);PostgreSQL 侧以 pg_is_in_recovery()=true(备库)与 default_transaction_read_only=on(实例/库/角色级被置为只读)为准,current_setting('transaction_read_only') 只是当前会话取值,可被会话自行覆盖;控制台事件时间是否与故障窗口重合。
下一步:实例异常或维护中→按平台流程等待或提工单,不反复重启;角色不符→修正读写端点;实例健康→“连接参数核对(host/port/协议)”与“认证失败”场景、“SSL/TLS 故障”场景。
1.3.4 连接参数核对(host/port/协议)
目的:确认应用实际使用的连接串、驱动、协议与超时设置和目标实例匹配,避免“配置正确但生效的是另一份配置”。
OS/云控制台方法 [只读]:导出应用运行时真实生效的连接配置(环境变量、配置中心、Secret 引用),与控制台端点逐字比对;确认未混用内网/外网端点、旧集群端点或读写分离端点。
# [只读] 只打印非敏感字段,禁止输出密码
env | grep -Ei '^(DB_|MYSQL_|PG)' | grep -vEi 'PASS|PWD|SECRET|TOKEN'
- MySQL 8.0 [只读]
SELECT CONNECTION_ID() AS conn_id, USER() AS client_claim,
CURRENT_USER() AS matched_account, DATABASE() AS current_db,
@@hostname AS server_host, @@port AS server_port;
SHOW VARIABLES WHERE Variable_name IN ('connect_timeout','wait_timeout','interactive_timeout','max_allowed_packet');
- PostgreSQL 14+ [只读]
SELECT current_database() AS current_db, current_user, session_user,
inet_client_addr() AS client_addr, inet_server_addr() AS server_addr,
inet_server_port() AS server_port;
SELECT name, setting FROM pg_settings
WHERE name IN ('tcp_keepalives_idle','tcp_keepalives_interval','statement_timeout','idle_in_transaction_session_timeout');
关键判断字段:连接到的服务器主机/端口/数据库与目标一致;USER() 与 CURRENT_USER() 是否被匹配到意外账户;客户端 connect_timeout 是否短于链路真实抖动;协议层(TCP/Unix socket、MySQL X 协议、sslmode)与服务端要求一致。
下一步:连接串错误→按发布流程修正配置([变更]);超时过小→按分层超时策略调整;账号/来源不符→“认证失败”场景;协议或加密不符→“SSL/TLS 故障”场景。
1.4 Agent 诊断提示词
把下面整段复制给 STAROps 数字员工,替换全部占位符后提交。模板是自包含的:候选原因、需要 DBA 执行的只读语句都已写在模板内。
任务:定位"连接超时/拒绝"场景(连接类故障)的根因,给出可执行处置建议,并保留完整证据链。
【输入补充】
客户端来源:<HOST>(应用节点所在子网或容器网段);目标端点与端口:<PORT>
【前置检查补充】
0.2 需确认的日志:实例错误日志。
0.7 白名单与安全组是否可通过 OpenAPI 读取,客户端真实出口 IP 是否已确认。
用 aliyun rds DescribeDBInstanceIPArrayList 读取 IP 白名单(原模板未指定此接口,补齐)。
指标 Key(MySQL,已核实可直接用于 DescribeDBInstancePerformance 的 Key 参数):
MySQL_Sessions —— 当前活跃连接数与当前总连接数(个)
MySQL_ThreadStatus —— 活跃线程数与线程连接数(个)
【数据源(本场景取值)】状态与降级规则按契约执行
云监控 2.0 / 托管 Prometheus:实例可用性、连接数与连接数使用率、活跃会话数。
CMS2_WORKSPACE 路由:starops observe entity metric-data 或 metric_set query(PromQL)。
ALIYUN_RDS 路由:aliyun rds DescribeDBInstancePerformance 按 Key 拉序列。
SLS(<SLS_PROJECT> 下对应 Logstore):实例错误日志中的连接被拒绝、超过连接上限、认证失败记录。
未投递到 SLS 时改用 OpenAPI:慢日志 DescribeSlowLogs(统计)与
DescribeSlowLogRecords(明细)、错误日志 DescribeErrorLogs。
系统事件与告警:实例重启、主备切换、维护变更、平台网络事件。
CMS2_WORKSPACE 路由:starops observe alerts query + changes query +
acm_basic event system-query。
ALIYUN_RDS 路由:aliyun rds DescribeEvents 查历史事件。
云平台 OpenAPI:实例运行状态与规格、端点清单(主/只读/代理)、白名单与安全组、只读属性。
常用接口:DescribeDBInstanceAttribute(实例详情)、DescribeParameters(参数当前值)。
白名单与安全组读取(OpenAPI):
aliyun rds DescribeDBInstanceIPArrayList --DBInstanceId <DBInstanceId>
--RegionId <REGION> -- 读取 IP 白名单(原模板未指定此接口,补齐)
安全组需走 ECS/NACL 相关 OpenAPI,不在 RDS 接口范围内。
需 DBA 执行并粘贴:实例 Uptime 与只读角色、服务端实际监听端口、当前连接数与上限。
【采集步骤】
A. Agent 自取(逐项回报数据源、取值、采集时间)
1) 取故障窗口内实例可用性与连接数曲线,与基线比对,判断是否触达连接上限。
2) 查事件与告警,确认窗口内是否发生重启、主备切换、维护或平台网络事件。
3) 查实例错误日志,按被拒绝 / 超过上限 / 认证失败分类计数,并取首末时间点。
4) 调 OpenAPI 核对实例状态、端点清单与白名单(DescribeDBInstanceIPArrayList),
确认客户端出口 IP 是否放通、是否误连只读或代理端点。
5) 从 ARMS 取建连失败样本,区分超时(无响应)与 refused(立即拒绝)及其客户端分布。
B. 需 DBA 执行只读语句后粘贴原始输出(Agent 无权限;语句已给全,按引擎选用)
1) 实例状态与只读角色(判断是否连到只读节点或刚重启):
MySQL:SELECT @@hostname, @@port, @@read_only, @@super_read_only;
SHOW GLOBAL STATUS LIKE 'Uptime';
PostgreSQL:SELECT pg_is_in_recovery(), pg_postmaster_start_time(),
current_setting('default_transaction_read_only');
2) 连接上限与当前占用(排除连接已满):
MySQL:SELECT @@max_connections; SHOW GLOBAL STATUS LIKE 'Threads_connected';
PostgreSQL:SHOW max_connections; SELECT count(*) FROM pg_stat_activity;
【候选原因与判定补充】
- 端点或端口配置错误,或应用误用外网、旧集群、只读端点
- 实例停止、重启、故障切换,或托管代理异常
- 安全组、防火墙、ACL 或路由拒绝
- 私网 DNS 解析漂移,解析到旧地址
- 数据库未监听目标接口
- 客户端连接超时小于网络实际抖动
- 连接风暴导致握手排队
超时与 refused 必须分开判:前者多为策略丢弃或链路不通,后者多为端口未监听、
代理拒绝或实例未就绪。
指标与事件均正常且只有部分客户端 refused 时,转认证与加密方向排查。
1.5 解决方案
先恢复正确端点、网络路径和实例状态;应用使用带抖动的指数退避、有限重试与连接池,避免故障时重试风暴。监听地址、安全组、路由和数据库重启均为 [变更],需最小开放范围、审批和回滚;不要为“快速验证”向公网全开放端口。若实例处于平台维护或切换中,等待平台流程完成并保留事件证据,不叠加人工重启。
1.6 验证与预防
从至少一个真实应用节点执行 TCP、TLS、认证和 SELECT 1 四层验证;观察一个业务高峰窗口内连接成功率、建立时延和错误码是否恢复基线。维护端点清单、私网 DNS 监控、合成连接探测和故障切换演练;把连接串纳入配置审计,禁止硬编码端点。
2. 连接数耗尽
2.1 现象描述
MySQL 报 Too many connections;PostgreSQL 普通用户把 max_connections 占满时最常见的是 FATAL: sorry, too many clients already,而 FATAL: remaining connection slots are reserved for non-replication superuser connections 只在仅剩 superuser_reserved_connections 余量时出现,两条报文对应的余量状态不同,不要混用。应用连接池等待、请求排队,新连接失败而已有连接可能仍工作。管理员往往也难以登录,需要预留的运维连接通道。
2.2 常见原因
连接未关闭;每请求新建连接;连接池总上限大于数据库容量;慢查询或锁等待占住会话;发布扩容后应用副本数增加但单池大小未缩减;健康检查连接过多;代理与数据库连接复用失配;空闲事务长期占用连接。
2.3 排查步骤
2.3.1 当前连接数与上限查看
目的:确认当前连接量、历史峰值与上限的关系,判断是真的到顶、平台代理层到顶,还是错误信息误导。
MySQL 8.0 [只读]
SHOW VARIABLES WHERE Variable_name IN ('max_connections','max_user_connections','thread_cache_size');
SHOW GLOBAL STATUS WHERE Variable_name IN
('Threads_connected','Threads_running','Max_used_connections','Connections','Aborted_connects');
- PostgreSQL 14+ [只读]
SELECT name, setting, pending_restart FROM pg_settings
WHERE name IN ('max_connections','superuser_reserved_connections','max_worker_processes');
SELECT count(*) AS total,
count(*) FILTER (WHERE state = 'active') AS active,
count(*) FILTER (WHERE state = 'idle') AS idle
FROM pg_stat_activity;
关键判断字段:Threads_connected 与 max_connections 的差距、Max_used_connections 反映的历史峰值、Threads_running 反映的真实并发;PostgreSQL 的总连接数是否已吃掉 superuser_reserved_connections 余量;托管代理的连接上限须与后端上限分别核对。
下一步:接近上限且活跃占多→“空闲连接与活跃连接区分”与“慢查询”场景(性能类故障);接近上限但多为空闲→“空闲连接与活跃连接区分”、“应用侧连接池配置检查”;未接近上限却报错→检查代理层、单账号 max_user_connections 和平台限制。
2.3.2 连接来源与分布分析
目的:定位是哪一个服务、实例、版本或作业在制造连接,避免误伤正常业务。
MySQL 8.0 [只读]
SELECT user, SUBSTRING_INDEX(host,':',1) AS client_ip, db, command, COUNT(*) AS sessions
FROM information_schema.processlist
GROUP BY user, client_ip, db, command
ORDER BY sessions DESC LIMIT 50;
- PostgreSQL 14+ [只读]
SELECT datname, usename, client_addr, application_name, state, COUNT(*) AS sessions
FROM pg_stat_activity
GROUP BY datname, usename, client_addr, application_name, state
ORDER BY sessions DESC LIMIT 50;
关键判断字段:单一 IP/账号/application_name 是否占据异常份额;是否有未登记的批任务、数据同步、BI 工具或健康检查;NAT 后所有来源可能表现为同一地址,此时以 application_name、账号和数据库区分。
下一步:来源明确且异常→联系所有者限流或下线(应用侧优先);来源为健康检查/探针→降低探测频率并复用连接;来源均正常但总量过大→“应用侧连接池配置检查”并做容量评估。
2.3.3 空闲连接与活跃连接区分
目的:判断连接被“占着不用”(泄漏、空闲事务、池过大)还是“用着不放”(慢 SQL、锁等待),两者的处置完全不同。
MySQL 8.0 [只读]
SELECT PROCESSLIST_ID, PROCESSLIST_USER, PROCESSLIST_HOST, PROCESSLIST_DB,
PROCESSLIST_COMMAND, PROCESSLIST_TIME, PROCESSLIST_STATE
FROM performance_schema.threads
WHERE TYPE = 'FOREGROUND'
ORDER BY PROCESSLIST_TIME DESC LIMIT 50;
SELECT trx_state, COUNT(*) FROM information_schema.innodb_trx GROUP BY trx_state;
- PostgreSQL 14+ [只读]
SELECT state, COUNT(*) AS sessions,
max(now()-state_change) AS max_in_state,
max(now()-xact_start) AS max_xact_age
FROM pg_stat_activity
WHERE pid <> pg_backend_pid()
GROUP BY state ORDER BY sessions DESC;
关键判断字段:MySQL Sleep 且 PROCESSLIST_TIME 很大的会话数量、是否存在 trx_state='RUNNING' 却无当前 SQL 的空闲事务;PostgreSQL idle、idle in transaction、idle in transaction (aborted)、active 各自占比与在该状态的停留时长。
下一步:idle in transaction 或 MySQL 空闲事务占主导→“长事务”场景(锁与并发故障);active 占主导且等待锁→“锁等待”场景(锁与并发故障);idle 占主导→“应用侧连接池配置检查”;active 且执行慢→“慢查询”场景(性能类故障)。
2.3.4 应用侧连接池配置检查
目的:核算“实例副本数 × 单池上限 + 运维保留”是否超过数据库容量,并确认池的回收、探活、超时配置合理。
OS/应用侧方法(厂商中立)[只读]:导出连接池配置(HikariCP maximumPoolSize/idleTimeout/maxLifetime、pgBouncer pool_size/pool_mode、Druid、SQLAlchemy pool_size/max_overflow、Go SetMaxOpenConns)与副本数/HPA 上限;在应用主机确认到数据库的 ESTABLISHED 连接数与池上限一致。
# [只读] 统计本机到数据库端口的连接数,与池上限对照
ss -tn state established "( dport = :<PORT> )" | wc -l
- MySQL 8.0 [只读]:用数据库侧观测反推池行为。
SHOW GLOBAL STATUS WHERE Variable_name IN
('Connections','Threads_created','Threads_cached','Aborted_clients','Aborted_connects');
SHOW VARIABLES WHERE Variable_name IN ('wait_timeout','interactive_timeout');
- PostgreSQL 14+ [只读]
SELECT datname, numbackends, xact_commit, xact_rollback,
sessions, sessions_abandoned, sessions_fatal, sessions_killed
FROM pg_stat_database WHERE datname = '<DB>';
SELECT name, setting FROM pg_settings
WHERE name IN ('idle_in_transaction_session_timeout','idle_session_timeout','tcp_keepalives_idle');
关键判断字段:Connections/sessions 的增长速率(每秒新建连接数高说明没有复用)、Threads_created 相对 Connections 的比例、Aborted_clients/sessions_abandoned 反映的异常断开;池 maxLifetime 应小于中间设备与数据库 wait_timeout/idle_session_timeout。
下一步:池总量超容量→缩小单池并集中排队(应用侧变更优先);每请求新建连接→修复池化;maxLifetime 大于中间设备回收时间→按“网络连通性故障”场景调整保活;池配置合理但仍不足→做容量评估后再考虑提升上限。
2.4 Agent 诊断提示词
把下面整段复制给 STAROps 数字员工,替换全部占位符后提交。模板是自包含的:候选原因、需要 DBA 执行的只读语句都已写在模板内。
任务:定位"连接数耗尽"场景(连接类故障)的根因,给出可执行处置建议,并保留完整证据链。
【输入补充】
连接池配置:<VALUE>(单实例池上限 × 应用实例数,含定时任务与旁路脚本)
【前置检查补充】
0.2 需确认的日志:实例错误日志。
0.7 连接数指标的采样间隔是否足以反映短时尖峰;不足时在结论中说明并要求 DBA 补瞬时值。
CMS2_WORKSPACE 路由下可用 starops observe entity metric-data --interval 10s 提高粒度。
指标 Key(MySQL,已核实可直接用于 DescribeDBInstancePerformance 的 Key 参数):
MySQL_Sessions —— 当前活跃连接数与当前总连接数(个)
MySQL_ThreadStatus —— 活跃线程数与线程连接数(个)
【数据源(本场景取值)】状态与降级规则按契约执行
云监控 2.0 / 托管 Prometheus:连接数与连接数使用率、活跃会话数、(若暴露)连接拒绝数。
CMS2_WORKSPACE 路由:starops observe entity metric-data 或 metric_set query(PromQL)。
ALIYUN_RDS 路由:aliyun rds DescribeDBInstancePerformance 按 Key 拉序列。
SLS(<SLS_PROJECT> 下对应 Logstore):错误日志中的连接超限记录及其来源地址。
未投递到 SLS 时改用 OpenAPI:慢日志 DescribeSlowLogs(统计)与
DescribeSlowLogRecords(明细)、错误日志 DescribeErrorLogs。
系统事件与告警:扩缩容、规格变更、参数组变更、备份任务。
CMS2_WORKSPACE 路由:starops observe alerts query + changes query +
acm_basic event system-query。
ALIYUN_RDS 路由:aliyun rds DescribeEvents 查历史事件。
云平台 OpenAPI:max_connections 等参数当前值、实例规格、代理端点连接上限。
常用接口:DescribeDBInstanceAttribute(实例详情)、DescribeParameters(参数当前值)。
需 DBA 执行并粘贴:连接上限与历史峰值、按来源聚合的连接分布、空闲事务数量与最长时长。
【采集步骤】
A. Agent 自取(逐项回报数据源、取值、采集时间)
1) 取连接数与活跃会话曲线,标出触达上限的时间点,与基线 P95 比对。
2) 查错误日志的连接超限记录,统计频率与来源分布。
3) 调 OpenAPI 读 max_connections 与实例规格,核对代理层上限是否低于后端上限。
4) 查事件:窗口内是否有发版、扩容、参数组变更或备份任务。
5) 从 ARMS 取连接池等待时间与获取失败率,区分应用侧池不足与后端上限不足。
B. 需 DBA 执行只读语句后粘贴原始输出(Agent 无权限;语句已给全,按引擎选用)
1) 上限与峰值(确认是否真的触顶及触顶时刻):
MySQL:SELECT @@max_connections;
SHOW GLOBAL STATUS WHERE Variable_name IN ('Threads_connected',
'Threads_running','Max_used_connections','Max_used_connections_time',
'Connection_errors_max_connections');
PostgreSQL:SHOW max_connections; SHOW superuser_reserved_connections;
SELECT count(*) FROM pg_stat_activity;
2) 连接来源分布(定位占用最多的客户端与账号):
MySQL:SELECT host, user, count(*) c FROM information_schema.processlist
GROUP BY 1,2 ORDER BY c DESC LIMIT 20;
PostgreSQL:SELECT client_addr, usename, application_name, state, count(*) c
FROM pg_stat_activity GROUP BY 1,2,3,4 ORDER BY c DESC LIMIT 20;
3) 空闲与空闲事务(区分泄漏与真实并发):
MySQL:SELECT command, count(*) FROM information_schema.processlist GROUP BY 1;
SELECT trx_id, trx_started, trx_state FROM information_schema.innodb_trx
ORDER BY trx_started;
PostgreSQL:SELECT state, count(*), max(now()-state_change) AS longest
FROM pg_stat_activity GROUP BY 1;
4) 连接拒绝与错误计数(补齐原模板缺失的状态变量):
MySQL:SHOW GLOBAL STATUS WHERE Variable_name IN ('Aborted_connects',
'Aborted_clients','Connection_errors_max_connections',
'Connection_errors_internal','Threads_connected','Threads_running');
-- Aborted_connects 统计连接建立前被拒绝的次数(认证失败、超限、超时等)
-- Connection_errors_max_connections 统计因达到 max_connections 被拒绝的次数
PostgreSQL:SELECT datname, numbackends, xact_commit, xact_rollback,
conflicts, temp_files, deadlocks FROM pg_stat_database
WHERE datname = current_database();
【候选原因与判定补充】
- 连接未关闭或连接泄漏
- 每请求新建连接,未做池化
- 连接池总上限(单池 × 副本数)大于数据库容量
- 慢查询或锁等待占住会话
- 发布扩容后应用副本数增加但单池大小未缩减
- 健康检查或探针连接过多
- 代理与数据库连接复用失配
- 空闲事务长期占用连接
注意:PostgreSQL 的 pg_stat_database.sessions 只统计成功建立的会话,被拒绝的连接
不计入,不能用它证明没有超限。
平台连接数指标的采样间隔可能掩盖短时尖峰,判定触顶需以 DBA 粘贴的瞬时值补证。
2.5 解决方案
先限流、降低重试并修复泄漏;必要时在确认事务影响后终止明确的异常会话。KILL <PID>、SELECT pg_terminate_backend(<PID>) 均为 [高风险]:会回滚事务、造成应用错误并可能增加 IO,只能在确认会话所有者、事务内容、回滚成本和重试影响后执行。
提高 max_connections 是 [变更]:必须先核算每连接内存、工作内存、线程/进程开销、代理能力和实例规格,并验证是否需重启;它不是连接泄漏的长期修复。优先采用连接池/代理、全局连接预算和排队背压。
2.6 验证与预防
确认连接成功率恢复,当前/峰值连接留有按历史波动和故障切换场景计算的余量,且连接来源分布合理。为每个服务设全局连接预算:实例数 × 单池上限 + 运维保留;监控连接使用率、创建速率、池等待、空闲事务和拒绝数;为 DBA 预留独立管理入口。
3. 认证失败
3.1 现象描述
出现 MySQL Access denied for user、PostgreSQL password authentication failed、no pg_hba.conf entry,或同一账号在部分来源/数据库成功、部分失败。也可能表现为“能连上但无权访问对象”,这属于授权问题而非认证问题。
3.2 常见原因
密码轮换不同步;账号锁定或过期;MySQL user@host 匹配到意外账户、驱动不支持认证插件;PostgreSQL HBA 规则顺序/网段/数据库不匹配;连错实例或数据库;只授予对象权限但未授予登录能力;白名单未覆盖 NAT 后真实出口。
3.3 排查步骤
3.3.1 账号密码验证
目的:确认账号存在、未锁定/未过期、认证插件与客户端兼容,且当前凭据版本与数据库一致。
MySQL 8.0 [只读]
SELECT user, host, plugin, account_locked, password_expired,
password_last_changed, password_lifetime
FROM mysql.user WHERE user = '<USER>';
SELECT CURRENT_USER() AS matched_account, USER() AS client_claim;
- PostgreSQL 14+ [只读]
SELECT rolname, rolcanlogin, rolvaliduntil, rolconnlimit
FROM pg_roles WHERE rolname = '<USER>';
SELECT current_user, session_user;
关键判断字段:account_locked='N'、password_expired='N'、plugin 被驱动支持(如 caching_sha2_password 需较新驱动);PostgreSQL rolcanlogin=true、rolvaliduntil 未过期;CURRENT_USER() 与预期账号一致,说明没有匹配到通配账户。
下一步:账号锁定/过期→按身份流程解锁或轮换([变更],不共享超级账号);插件不兼容→升级驱动或迁移认证方式;账号状态正常仍失败→“账号权限与白名单检查”;凭据疑似不同步→通过密钥管理系统灰度轮换,禁止在工单中写明文口令。
3.3.2 账号权限与白名单检查
目的:区分“认证不通过”与“认证通过但无库/表权限”,并确认来源地址被账号规则或平台白名单允许。
云控制台/网络侧方法(厂商中立)[只读]:核对实例白名单/访问控制列表中的网段是否覆盖应用真实出口地址(含 NAT、SNAT、容器出口、跨可用区节点);确认白名单分组与当前实例、当前端点绑定。
MySQL 8.0 [只读]
SHOW GRANTS FOR '<USER>'@'<HOST>';
SELECT user, host, plugin FROM mysql.user
WHERE user IN ('<USER>','') ORDER BY host;
SELECT * FROM information_schema.schema_privileges WHERE grantee LIKE '%<USER>%';
- PostgreSQL 14+ [只读]
-- PostgreSQL 14 的 pg_hba_file_rules 没有 rule_number 列(rule_number/file_name 是 PG16 新增)
SELECT line_number, type, database, user_name, address, netmask, auth_method, options, error
FROM pg_hba_file_rules ORDER BY line_number;
SELECT datname, datallowconn, datconnlimit, has_database_privilege('<USER>', datname, 'CONNECT') AS can_connect
FROM pg_database WHERE datname = '<DB>';
注意:pg_hba_file_rules 在 PostgreSQL 14 默认仅超级用户可读(pg_monitor 不足);它反映的是 pg_hba.conf 文件的当前内容,而不是已 reload 生效的规则,文件改过但未 reload 时二者会不一致(可用 pg_conf_load_time() 与最近一次 reload 时间对照)。托管实例通常不暴露该文件,应以控制台白名单/参数配置为准。PG16 起该视图另有 rule_number、file_name 列。
关键判断字段:MySQL 中 user@host 的匹配优先级(更具体的 host 优先,空用户名的匿名账号会抢占匹配);PostgreSQL 按 line_number 升序的首条匹配 HBA 规则生效、address/netmask 是否覆盖客户端地址、auth_method 是否与客户端一致、error 列是否提示规则解析失败;datallowconn、CONNECT 权限与 datconnlimit。
下一步:白名单不含来源→按最小网段补充([变更]);HBA 规则顺序错误→最小化调整并保留备用管理会话;仅缺对象权限→按最小权限授予,不要误改认证配置;来源与规则都正确→“连接地址与端口匹配确认”。
3.3.3 连接地址与端口匹配确认
目的:排除“认证失败其实是连错实例/连错库/连到只读端点或代理”的情况;同名账号在不同实例上的口令往往不同。
MySQL 8.0 [只读]
SELECT @@hostname AS server_host, @@port AS server_port,
@@server_id AS server_id, DATABASE() AS current_db,
@@read_only AS read_only;
- PostgreSQL 14+ [只读]
SELECT inet_server_addr() AS server_addr, inet_server_port() AS server_port,
current_database() AS current_db, pg_is_in_recovery() AS in_recovery,
inet_client_addr() AS client_addr;
关键判断字段:服务器标识(@@hostname/@@server_id/inet_server_addr())是否是目标实例;current_db 是否是账号被授权的库;inet_client_addr() 是否等于白名单登记地址(不等说明经过 NAT 或代理);read_only/in_recovery 是否说明连到了只读节点。
注意:inet_client_addr()、inet_server_addr()、inet_server_port() 在 Unix domain socket 连接下返回 NULL,此时 NULL 只说明是本机套接字连接,不能据此判定 NAT、代理或端口映射。
下一步:连错实例/端点→修正配置并核对凭据来源;连到只读节点→改用写端点;客户端地址与白名单不符→回到“账号权限与白名单检查”与“网络连通性故障”场景的“数据库白名单配置检查”;全部匹配仍失败→安全重置凭据并检查时钟偏差、密钥管理系统同步与审计日志。
3.4 Agent 诊断提示词
把下面整段复制给 STAROps 数字员工,替换全部占位符后提交。模板是自包含的:候选原因、需要 DBA 执行的只读语句都已写在模板内。
任务:定位"认证失败"场景(连接类故障)的根因,给出可执行处置建议,并保留完整证据链。
【输入补充】
账号与库:<USER> / <DB>;是否新账号或刚轮转过凭据:是 / 否
【前置检查补充】
0.2 需确认的日志:实例错误日志与审计日志(审计或 SQL 洞察需已开启)。
0.7 审计日志是否覆盖故障窗口;未开启时认证失败明细只能由 DBA 提供。
CMS2_WORKSPACE 路由下可用 starops observe entity log-data 查审计日志投递库。
指标 Key(MySQL,已核实可直接用于 DescribeDBInstancePerformance 的 Key 参数):
本场景无直接对应的性能 Key,以日志与审计为主;MySQL_Sessions 仅用于侧证连接量是否同时异常。
【数据源(本场景取值)】状态与降级规则按契约执行
云监控 2.0 / 托管 Prometheus:(若暴露)连接失败率与失败计数。
CMS2_WORKSPACE 路由:starops observe entity metric-data 或 metric_set query(PromQL)。
ALIYUN_RDS 路由:aliyun rds DescribeDBInstancePerformance 按 Key 拉序列。
SLS(<SLS_PROJECT> 下对应 Logstore):错误日志与审计日志中的认证失败条目(错误码、账号、
来源地址、时间分布)。
未投递到 SLS 时改用 OpenAPI:慢日志 DescribeSlowLogs(统计)与
DescribeSlowLogRecords(明细)、错误日志 DescribeErrorLogs。
系统事件与告警:凭据轮转、白名单变更、参数组变更、密钥管理同步失败。
CMS2_WORKSPACE 路由:starops observe alerts query + changes query +
acm_basic event system-query。
ALIYUN_RDS 路由:aliyun rds DescribeEvents 查历史事件。
云平台 OpenAPI:账号与权限清单、白名单、是否强制加密传输。
常用接口:DescribeDBInstanceAttribute(实例详情)、DescribeParameters(参数当前值)。
需 DBA 执行并粘贴:账号状态与认证插件、HBA 规则顺序、连接实际落到的库与角色。
【采集步骤】
A. Agent 自取(逐项回报数据源、取值、采集时间)
1) 查错误与审计日志,按错误码分类(MySQL 1045、密码过期、账号锁定;
PostgreSQL 28P01、28000)并统计账号与来源地址分布。
2) 判断是全量失败还是部分节点失败:按来源地址聚合,比对成功与失败节点的出口地址。
3) 查事件与 OpenAPI:窗口内是否轮转凭据、改过白名单或强制加密开关。
4) 从 ARMS 取失败样本的异常类型,区分认证失败与 TLS 握手失败。
B. 需 DBA 执行只读语句后粘贴原始输出(Agent 无权限;语句已给全,按引擎选用)
1) 账号状态与认证插件:
MySQL:SELECT user, host, plugin, password_expired, account_locked,
password_lifetime FROM mysql.user WHERE user = '<USER>';
PostgreSQL:SELECT rolname, rolcanlogin, rolvaliduntil FROM pg_authid
WHERE rolname = '<USER>';
2) PostgreSQL HBA 规则(PG14 起该视图仅超级用户可读,pg_monitor 不足;
反映文件内容而非已生效规则):
SELECT line_number, type, database, user_name, address, auth_method, error
FROM pg_hba_file_rules ORDER BY line_number;
3) 连接实际落点(确认库、角色、来源地址与授权范围一致):
MySQL:SELECT current_user(), user(), @@hostname, database();
PostgreSQL:SELECT current_user, current_database(), inet_client_addr(),
inet_server_addr(); -- Unix socket 连接下 inet_* 返回 NULL
【候选原因与判定补充】
- 密码轮换不同步
- 账号锁定或已过期
- MySQL 的 user@host 匹配到意外账户,或驱动不支持所需认证插件
- PostgreSQL 的 HBA 规则顺序、网段或数据库不匹配
- 连错实例或数据库
- 只授予对象权限但未授予登录能力
- 白名单未覆盖 NAT 后的真实出口地址
密码错误与无匹配 HBA 条目是两类问题:前者改凭据,后者改 HBA 或白名单。
部分节点失败时优先怀疑 host 通配范围与客户端出口 IP 变化,可用日志与链路里的客户端
地址侧证。
3.5 解决方案
通过密钥管理系统轮换凭据并灰度更新应用;按最小权限修复账号、来源和数据库授权。修改用户、HBA、白名单或认证插件均为 [变更],应先建立备用管理会话,防止把所有管理员锁在外部。不得通过关闭认证、放开 0.0.0.0/0 白名单或共享超级账号止损。
3.6 验证与预防
从实际应用来源验证登录、目标数据库和最小业务语句;确认旧凭据按计划失效且无持续失败。建立凭据双版本轮换、到期告警、授权审计和非生产兼容性测试;错误日志与工单中隐藏口令和敏感连接串。
4. SSL/TLS 故障
4.1 现象描述
报证书未知、主机名不匹配、证书过期、协议/密码套件不兼容,或服务端强制 TLS 而客户端使用明文;也可能能连接但未达到要求的身份校验级别(加密了但没验证服务端身份)。
4.2 常见原因
CA 轮换未同步;客户端时钟偏差;使用 IP 或别名导致主机名校验失败;旧驱动不支持服务端协议;代理证书链不完整;将“加密”误认为“已验证服务端身份”;容器镜像内 CA 包过期。
4.3 排查步骤
4.3.1 SSL 证书有效性检查
目的:确认服务端证书在有效期内、SAN 覆盖所用连接地址、且未被吊销或提前轮换。
通用 [只读]
# [只读] 仅读取公开证书信息,不提供任何凭据
openssl s_client -connect <HOST>:<PORT> -servername <HOST> </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltName
- MySQL 8.0 [只读]
-- have_ssl 自 MySQL 8.0.26 起已弃用,不要再用它判断是否启用 TLS
SHOW VARIABLES WHERE Variable_name IN ('ssl_ca','ssl_cert','ssl_key','tls_version','require_secure_transport');
SHOW STATUS LIKE 'Ssl_%';
-- performance_schema.tls_channel_status 为 8.0.21+ 提供各通道 TLS 生效状态与证书属性
SELECT CHANNEL, PROPERTY, VALUE FROM performance_schema.tls_channel_status
WHERE PROPERTY IN ('Enabled','ssl_ca','Ssl_cipher','tls_version',
'Ssl_server_not_before','Ssl_server_not_after');
- PostgreSQL 14+ [只读]
SHOW ssl;
SELECT name, setting FROM pg_settings
WHERE name IN ('ssl_cert_file','ssl_key_file','ssl_ca_file','ssl_min_protocol_version');
关键判断字段:notBefore/notAfter 与当前时间的关系(同时确认客户端时钟无偏差);subjectAltName 是否包含实际使用的 <HOST>(用 IP 连接时需 IP SAN);MySQL Ssl_server_not_after;服务端是否启用 TLS 以 performance_schema.tls_channel_status(8.0.21+)的 Enabled 或 SHOW STATUS LIKE 'Ssl_%' 为准(have_ssl 自 8.0.26 起已弃用,不作判据);PostgreSQL 侧看 ssl=on。
下一步:证书过期或即将过期→安排轮换([变更],新旧 CA 并行灰度);SAN 不含主机名→改用证书覆盖的正式端点;服务端未启用 TLS→按合规要求开启;证书有效但仍报错→“客户端 SSL 配置核对”、“证书链与 CA 信任验证”。
4.3.2 客户端 SSL 配置核对
目的:确认客户端确实以要求的加密与校验级别连接,而不是静默降级为明文或“仅加密不校验”。
应用侧方法(厂商中立)[只读]:核对驱动参数——MySQL --ssl-mode(DISABLED/PREFERRED/REQUIRED/VERIFY_CA/VERIFY_IDENTITY)、JDBC sslMode/useSSL/verifyServerCertificate;PostgreSQL sslmode(disable…verify-full)、sslrootcert;确认容器镜像内 CA 包与挂载路径存在且权限受限。
MySQL 8.0 [只读]
mysql --ssl-mode=VERIFY_IDENTITY --ssl-ca=<PATH> \
-h <HOST> -P <PORT> -u <USER> -p -e "STATUS; SHOW STATUS LIKE 'Ssl_%';"
- PostgreSQL 14+ [只读]
psql -W "host=<HOST> port=<PORT> dbname=<DB> user=<USER> sslmode=verify-full sslrootcert=<PATH>" \
-c "SELECT ssl, version, cipher, bits FROM pg_stat_ssl WHERE pid = pg_backend_pid();"
关键判断字段:MySQL STATUS 输出的 SSL: Cipher in use 非空、Ssl_version 符合策略;PostgreSQL pg_stat_ssl.ssl=true、version、cipher、bits;应用会话与 DBA 客户端结论必须一致,抽查应用侧真实会话而非只测本地客户端。
下一步:应用未加密→修正驱动参数并按需开启服务端强制(require_secure_transport/HBA hostssl,均为 [变更]);加密但未校验身份→提升到 VERIFY_IDENTITY/verify-full;协议版本不兼容→升级驱动/运行时并灰度;报证书不受信→“证书链与 CA 信任验证”。
4.3.3 证书链与 CA 信任验证
目的:确认客户端的信任锚能完整验证服务端链路,包括代理终止 TLS 时的两段链路各自的证书责任边界。
通用 [只读]
# [只读] 查看完整链与验证结果;返回码 0 表示验证通过
openssl s_client -connect <HOST>:<PORT> -servername <HOST> -showcerts -verify_return_error </dev/null
# 上一条只把链打到屏幕;openssl verify 需要文件输入,先把服务端证书链落盘
openssl s_client -connect <HOST>:<PORT> -servername <HOST> -showcerts </dev/null 2>/dev/null \
| sed -n '/BEGIN CERTIFICATE/,/END CERTIFICATE/p' > /tmp/server-chain.pem
openssl verify -CAfile <PATH> /tmp/server-chain.pem
- MySQL 8.0 [只读]
SHOW VARIABLES WHERE Variable_name IN ('ssl_ca','ssl_capath','ssl_crl','ssl_crlpath','tls_ciphersuites');
SHOW STATUS LIKE 'Ssl_verify%';
- PostgreSQL 14+ [只读]
SELECT a.pid, a.usename, a.application_name, s.ssl, s.version, s.cipher, s.client_dn, s.issuer_dn
FROM pg_stat_activity a JOIN pg_stat_ssl s USING (pid)
WHERE a.pid = pg_backend_pid();
关键判断字段:Verify return code: 0 (ok);链中是否缺少中间 CA;托管服务是否使用厂商 CA 包(需从官方渠道下载并校验指纹);代理终止 TLS 时数据库视图只反映“代理→后端”这一段。
注意:pg_stat_ssl 只能用于确认本连接是否加密及其协议版本、密码套件、位数,以及服务端是否收到并解析了客户端证书——client_dn/client_serial/issuer_dn 描述的是客户端提交的证书及其签发者,服务于服务端校验客户端证书(hostssl ... clientcert=verify-full 场景),不能用来判断“客户端是否信任服务端证书”。服务端证书链的信任结论只能由客户端侧得出:使用 sslmode=verify-full 连接成功,并配合 openssl s_client -verify_return_error/openssl verify 的返回码确认。
下一步:链不完整→补全中间 CA/使用厂商 CA 包;信任锚缺失→分发受信 CA(限权 0600);代理段与后端段策略不一致→分别核对并明确责任边界;需临时降级校验→仅经安全审批、限时限源,并登记为待整改项。
4.4 Agent 诊断提示词
把下面整段复制给 STAROps 数字员工,替换全部占位符后提交。模板是自包含的:候选原因、需要 DBA 执行的只读语句都已写在模板内。
任务:定位"SSL/TLS 故障"场景(连接类故障)的根因,给出可执行处置建议,并保留完整证据链。
【输入补充】
连接串的 sslmode 或 ssl-mode:<VALUE>;是否强制加密传输:是 / 否
【前置检查补充】
0.2 需确认的日志:实例错误日志。
0.7 服务端证书信息是否可通过 OpenAPI 读取;不可得时由 DBA 用 s_client 采集证书链。
指标 Key(MySQL,已核实可直接用于 DescribeDBInstancePerformance 的 Key 参数):
本场景无直接对应的性能 Key,证据以错误日志、链路异常类型与证书信息为主。
【数据源(本场景取值)】状态与降级规则按契约执行
云监控 2.0 / 托管 Prometheus:本场景无直接指标,以失败率与日志为主。
CMS2_WORKSPACE 路由:starops observe entity metric-data 或 metric_set query(PromQL)。
ALIYUN_RDS 路由:aliyun rds DescribeDBInstancePerformance 按 Key 拉序列。
SLS(<SLS_PROJECT> 下对应 Logstore):错误日志中的 TLS 握手失败、证书过期、协议或套件不
匹配记录。
未投递到 SLS 时改用 OpenAPI:慢日志 DescribeSlowLogs(统计)与
DescribeSlowLogRecords(明细)、错误日志 DescribeErrorLogs。
系统事件与告警:托管侧证书轮转、强制加密开关变更。
CMS2_WORKSPACE 路由:starops observe alerts query + changes query +
acm_basic event system-query。
ALIYUN_RDS 路由:aliyun rds DescribeEvents 查历史事件。
云平台 OpenAPI:实例 SSL 开关、服务端证书有效期与 CA 信息、是否强制加密。
常用接口:DescribeDBInstanceAttribute(实例详情)、DescribeParameters(参数当前值)。
降级兜底:服务端证书信息若无法通过 OpenAPI 获取,必须由运维用 s_client
采集;两者都拿不到时证书类结论标注为未验证。
需 DBA 执行并粘贴:服务端证书有效期与 SAN、证书链验证结果、服务端与账号的加密要求。
【采集步骤】
A. Agent 自取(逐项回报数据源、取值、采集时间)
1) 调 OpenAPI 读实例 SSL 开关与服务端证书有效期,确认是否在故障窗口内到期或刚轮转。
2) 查错误日志,按过期 / 主机名不匹配 / CA 不受信任 / 协议或套件不匹配分类计数。
3) 从 ARMS 取异常类型与客户端分布,确认是否只有特定版本或特定节点失败。
4) 查事件:窗口内的证书轮转与加密相关参数变更。
B. 需 DBA 执行只读语句后粘贴原始输出(Agent 无权限;语句已给全,按引擎选用)
1) 服务端证书链与有效期(在能连通实例的运维机执行):
openssl s_client -connect <HOST>:<PORT> -servername <HOST> -showcerts \
</dev/null 2>/dev/null | sed -n '/BEGIN CERTIFICATE/,/END CERTIFICATE/p' \
> /tmp/server-chain.pem
openssl x509 -in /tmp/server-chain.pem -noout -dates -subject -ext subjectAltName
openssl verify -CAfile <PATH> /tmp/server-chain.pem # 返回码 0 表示链完整且受信任
2) 服务端与账号的加密要求:
MySQL:SHOW VARIABLES WHERE Variable_name IN ('have_ssl','ssl_ca','ssl_cert',
'require_secure_transport'); SHOW CREATE USER '<USER>'@'<HOST>';
PostgreSQL:SHOW ssl; SHOW ssl_min_protocol_version;
SELECT ssl, version, cipher, client_dn FROM pg_stat_ssl
WHERE pid = pg_backend_pid(); -- client_dn 描述客户端证书,不是服务端
【候选原因与判定补充】
- CA 轮换未同步到客户端
- 客户端时钟偏差导致有效期校验失败
- 使用 IP 或别名连接,导致主机名校验失败
- 旧驱动不支持服务端要求的协议或密码套件
- 代理证书链不完整,缺中间证书
- 把"已加密"误认为"已验证服务端身份"(sslmode 不足)
- 容器镜像内的 CA 包过期
五类分开判:证书过期、主机名不匹配、CA 不受信任、协议或套件不匹配、
要求加密但未启用。只有部分客户端失败时优先查该客户端的 CA bundle 与 TLS 版本下限,
不要先改服务端。
4.5 解决方案
优先升级信任链和驱动,使用 VERIFY_IDENTITY/verify-full。更换证书、CA、TLS 最低版本或强制加密为 [变更],需支持新旧 CA 并行的灰度期和回滚。临时降低校验等级会暴露中间人风险,只能经安全审批、限时、限源使用,不能成为长期方案。
4.6 验证与预防
验证完整链路的协议、密码套件、主机名和到期日;抽查应用连接而非只测 DBA 客户端。建立证书到期提前告警、CA 轮换演练、驱动兼容矩阵和禁止明文连接策略。
5. 网络连通性故障
5.1 现象描述
连接间歇超时、跨可用区时延抖动、部分应用节点可连而部分不可连、长连接被重置。数据库本身健康,但端到端路径异常。
5.2 常见原因
安全组/ACL 规则漂移;路由或 DNS 缓存异常;VPC 对等/专线/终端节点异常;NAT 端口耗尽;MTU/分片问题;代理、负载均衡或防火墙提前回收空闲连接;跨区域链路抖动;客户端超时设置相互矛盾。
5.3 排查步骤
5.3.1 VPC/子网配置检查
目的:确认应用与数据库在网络拓扑上确实可互通:同 VPC 或已建立对等/专线/网关,子网路由指向正确,跨可用区路径符合设计。
云控制台方法(厂商中立)[只读]:核对实例所属 VPC/子网/可用区与应用一致;检查路由表是否有到目标网段的有效条目;确认对等连接、专线、VPN、终端节点(Endpoint/私有链接)状态为可用;检查是否存在网段重叠导致路由不可达。
# [只读] 在应用主机侧验证本机网段、路由与实际出口路径
ip -brief address
ip route get <HOST>
traceroute -n -T -p <PORT> <HOST>
- MySQL 8.0 [只读]:从数据库侧看到的客户端地址可反证实际路径与 NAT 行为。
SELECT SUBSTRING_INDEX(host,':',1) AS client_ip, COUNT(*) AS sessions
FROM information_schema.processlist GROUP BY client_ip ORDER BY sessions DESC;
- PostgreSQL 14+ [只读]
SELECT client_addr, count(*) AS sessions, min(backend_start) AS oldest_session
FROM pg_stat_activity WHERE client_addr IS NOT NULL
GROUP BY client_addr ORDER BY sessions DESC;
关键判断字段:ip route get 的出口网卡/网关是否符合设计;traceroute -T 到端口的最后可达跳;数据库看到的 client_addr 是应用真实地址还是 NAT/代理地址;失败节点与成功节点在子网、可用区、路由表上的差异。
下一步:路由缺失或对等/专线异常→由网络负责人按最小范围修复([变更]);仅部分子网失败→对比该子网的路由与 ACL,进入“安全组规则检查”;路径正常→“数据库白名单配置检查”、“DNS 解析验证”。
5.3.2 安全组规则检查
目的:确认双向的安全组/网络 ACL/主机防火墙都放通了数据库端口,并排除规则漂移与优先级覆盖。
云控制台方法(厂商中立)[只读]:检查数据库侧入方向规则是否放通应用来源(安全组引用或最小网段)与目标端口;检查应用侧出方向规则;检查子网级 ACL 的允许/拒绝顺序与优先级;查看规则最近变更记录,定位漂移时间点。
# [只读] 区分“被丢弃(超时)”与“被拒绝(RST)”;并检查主机本地防火墙
nc -vz -w 5 <HOST> <PORT>
sudo iptables -L -n --line-numbers 2>/dev/null | head -50
- MySQL 8.0 [只读]:数据库侧统计可反映握手是否根本没有到达。
SHOW GLOBAL STATUS WHERE Variable_name IN
('Connections','Aborted_connects','Aborted_clients','Connection_errors_accept','Connection_errors_internal');
- PostgreSQL 14+ [只读]
SELECT datname, sessions, sessions_abandoned, sessions_fatal, sessions_killed
FROM pg_stat_database WHERE datname = '<DB>';
关键判断字段:nc 超时(策略丢弃)vs refused(无监听或主动拒绝);数据库侧 Connections/sessions 在故障窗口的增量;规则变更时间是否与故障起点吻合。
注意:PostgreSQL 14 的 pg_stat_database.sessions 只统计成功建立的会话——被 pg_hba 拒绝、认证失败、TLS 握手失败的连接其实已经到达数据库,但不计入该列。因此 sessions 无增长只能说明“没有成功建连”,不能推断“未到达数据库”;要区分“未到达”与“到达但被拒”,需结合服务端日志(临时开启 log_connections,属 [变更])与其中的 FATAL: no pg_hba.conf entry、认证失败、TLS 握手失败记录,MySQL 侧可对照 Aborted_connects、Connection_errors_* 与错误日志。
下一步:规则缺失→按最小网段与最小端口放通([变更],禁止 0.0.0.0/0);ACL 拒绝规则优先级过高→调整顺序;握手已到达数据库但失败→“认证失败”场景或“SSL/TLS 故障”场景;规则正确仍不通→“数据库白名单配置检查”、“DNS 解析验证”。
5.3.3 数据库白名单配置检查
目的:托管数据库通常有独立于安全组的“白名单/访问控制”,需确认它覆盖了应用的真实出口地址与所用端点。
云控制台方法(厂商中立)[只读]:核对实例白名单分组内容、生效端点(内网/外网/代理/只读)、是否引用了过期的临时地址;确认容器/弹性伸缩场景下新增节点的出口网段已纳入;确认变更未被后续操作覆盖。
MySQL 8.0 [只读]:数据库账号层面的 host 限制与平台白名单是两道关卡,需同时满足。
SELECT user, host FROM mysql.user WHERE user = '<USER>' ORDER BY host;
SELECT USER() AS client_claim, CURRENT_USER() AS matched_account,
SUBSTRING_INDEX(USER(),'@',-1) AS seen_client_host;
- PostgreSQL 14+ [只读]
-- PG14 无 rule_number 列,按 line_number 排序;rule_number/file_name 为 PG16 新增
SELECT line_number, type, database, user_name, address, netmask, auth_method, options, error
FROM pg_hba_file_rules ORDER BY line_number;
SELECT inet_client_addr() AS seen_client_addr;
注意:pg_hba_file_rules 在 PostgreSQL 14 默认仅超级用户可读(pg_monitor 不足),且反映 pg_hba.conf 文件当前内容而非已 reload 生效的规则;托管实例应以控制台白名单/参数配置为准。inet_client_addr() 在 Unix domain socket 连接下返回 NULL。
关键判断字段:数据库实际看到的客户端地址(seen_client_host/inet_client_addr())是否在白名单与账号 host/HBA address 范围内(HBA 以 line_number 升序的首条匹配规则生效);是否存在 NAT 导致地址与预期不同;白名单是否绑定到了当前使用的端点。
下一步:白名单缺失→按最小网段补充([变更],并登记有效期与负责人);账号 host/HBA 不匹配→按“认证失败”场景的“账号权限与白名单检查”修正;地址与预期不符→核对 NAT/SNAT 与容器出口策略;白名单正确仍失败→“DNS 解析验证”与“安全组规则检查”。
5.3.4 DNS 解析验证
目的:确认各来源解析到的是预期端点地址,排除私网 DNS 漂移、缓存陈旧、解析到公网地址或故障切换后 TTL 未过期。
OS 方法(厂商中立)[只读]:在每类应用节点上分别解析并比对;确认使用的是 VPC 内私网解析器;检查应用运行时的 DNS 缓存(JVM networkaddress.cache.ttl、容器 ndots/search 配置、本地缓存守护进程)。
# [只读] 比对系统解析与权威解析,并观察 TTL
getent ahosts <HOST>
dig +noall +answer +ttlid <HOST>
cat /etc/resolv.conf
- MySQL 8.0 [只读]:解析结果需与数据库实际身份一致。
SELECT @@hostname AS server_host, @@server_id AS server_id, @@read_only AS read_only;
- PostgreSQL 14+ [只读]
SELECT inet_server_addr() AS server_addr, pg_is_in_recovery() AS in_recovery;
关键判断字段:不同节点解析结果是否一致且属于预期网段;TTL 是否过长导致切换后仍指向旧节点;解析地址对应的实例角色(读写/只读)是否符合调用方预期;/etc/resolv.conf 是否指向预期解析器。
下一步:解析漂移→修正 DNS 记录并缩短 TTL([变更]);应用缓存过久→调整客户端 DNS 缓存策略并支持重连;解析到只读节点→修正端点用途;解析正常但仍抖动→按本场景“解决方案”处理链路层重传、MTU、NAT 空闲回收。
5.4 Agent 诊断提示词
把下面整段复制给 STAROps 数字员工,替换全部占位符后提交。模板是自包含的:候选原因、需要 DBA 执行的只读语句都已写在模板内。
任务:定位"网络连通性故障"场景(连接类故障)的根因,给出可执行处置建议,并保留完整证据链。
【前置检查补充】
0.2 需确认的日志:实例错误日志。
0.7 应用侧是否有人可在与应用相同网络位置执行探测;没有则链路结论无法闭环。
指标 Key(MySQL,已核实可直接用于 DescribeDBInstancePerformance 的 Key 参数):
MySQL_NetworkTraffic —— 每秒进出流量(KB/s)
MySQL_Sessions —— 当前活跃连接数与当前总连接数(个)
【数据源(本场景取值)】状态与降级规则按契约执行
云监控 2.0 / 托管 Prometheus:实例可用性、连接数与网络流量类指标。
CMS2_WORKSPACE 路由:starops observe entity metric-data 或 metric_set query(PromQL)。
ALIYUN_RDS 路由:aliyun rds DescribeDBInstancePerformance 按 Key 拉序列。
SLS(<SLS_PROJECT> 下对应 Logstore):错误日志中的连接中断与重置记录及其时间分布。
未投递到 SLS 时改用 OpenAPI:慢日志 DescribeSlowLogs(统计)与
DescribeSlowLogRecords(明细)、错误日志 DescribeErrorLogs。
系统事件与告警:网络维护、专线或对等连接异常、代理端点健康变化、主备切换。
CMS2_WORKSPACE 路由:starops observe alerts query + changes query +
acm_basic event system-query。
ALIYUN_RDS 路由:aliyun rds DescribeEvents 查历史事件。
云平台 OpenAPI:VPC 与子网、安全组、白名单、端点清单与代理状态。
常用接口:DescribeDBInstanceAttribute(实例详情)、DescribeParameters(参数当前值)。
UModel 拓扑:实例与调用它的应用、所在可用区的依赖关系。
降级兜底:RTT、重传、丢包这类链路质量数据通常不在数据库监控里;
若 ARMS 与应用侧探测都没有,链路质量结论标注为不可得,转由网络负责人排查。
需 DBA 执行并粘贴:应用侧同网络位置的 DNS 与 TCP 探测结果、数据库实际看到的客户端地址。
【采集步骤】
A. Agent 自取(逐项回报数据源、取值、采集时间)
1) 调 OpenAPI 核对 VPC、子网、安全组、白名单与端点清单,与客户端真实出口 IP 比对。
2) 查事件:网络维护、专线或对等连接异常、代理端点健康变化。
3) 从 ARMS 取建连超时率与 RTT 分布,按可用区与客户端分组,判断全局还是局部。
4) 查错误日志中连接被重置或中断的时间分布,与网络事件对齐。
5) 用 UModel 列出受影响的应用与调用路径,界定影响面。
B. 需 DBA 执行只读语句后粘贴原始输出(Agent 无权限;语句已给全,按引擎选用)
1) 应用侧链路探测(必须在与应用相同的容器或子网内执行):
getent hosts <HOST> # 解析结果是否落在预期网段
ping -c 4 <HOST> # ICMP 被禁不能作为 TCP 不通的证据
nc -vz -w 5 <HOST> <PORT> # 超时多为策略丢弃,立即 refused 多为无监听
2) 数据库实际看到的客户端地址(核对 NAT 后出口是否在白名单内):
MySQL:SELECT user(), @@hostname;
PostgreSQL:SELECT inet_client_addr(), inet_server_addr();
【候选原因与判定补充】
- 安全组或 ACL 规则漂移
- 路由或 DNS 缓存异常
- VPC 对等、专线或终端节点异常
- NAT 端口耗尽
- MTU 或分片问题
- 代理、负载均衡或防火墙提前回收空闲连接
- 跨区域链路抖动
- 客户端各层超时设置相互矛盾
区分完全不可达、间歇丢包、握手后被中断三类,证据要求不同。
Agent 只能证明平台侧策略是否放通,端到端可达性必须由应用侧探测输出佐证。
5.5 解决方案
修复最小范围网络策略、路由和 DNS;对连接池设置低于中间设备空闲回收时间的保活/最大生命周期,设置分层且一致的连接、语句和请求超时。网络策略和 MTU 修改属于 [变更],需双向流量验证和快速回滚;不要简单无限增大超时掩盖丢包。
5.6 验证与预防
在各可用区真实应用节点执行连续合成事务,确认成功率、建连时延和重传回到各自历史基线。持续监控 DNS、NAT 端口、TCP 重置、跨区时延;在网络变更前后自动执行连通性矩阵,并把安全组/白名单纳入配置基线审计。
二、性能类故障
1. 慢查询
1.1 现象描述
接口延迟、超时或吞吐下降;慢日志/统计扩展显示特定 SQL 累计耗时或尾延迟上升。慢查询可能来自执行计划、锁等待、缓存冷却、数据量变化或资源争用,必须先证明“慢在哪一层”。
1.2 常见原因
1.2.1 全表扫描
判断依据:MySQL 计划出现 type=ALL、Using where 且 rows 接近表行数;PostgreSQL 出现 Seq Scan 且 pg_stat_user_tables.seq_tup_read 快速增长;SUM_ROWS_EXAMINED 远大于 SUM_ROWS_SENT。
注意边界:小表或高选择率查询的全表扫描可能是最优计划,不能一概而论;判定需结合表规模、选择性和实际耗时。
处置指向:先确认谓词可索引化(见“索引使用情况分析”),再评估新建索引的写放大与空间成本;无法索引化时考虑改写查询、限制返回集或预聚合。
1.2.2 索引失效
判断依据:索引存在但计划不使用;常见触发条件包括对索引列做函数/表达式运算、隐式类型转换(字符串列传入数字)、字符集或排序规则不一致、前导列缺失、LIKE '%x'、OR 条件无法合并、数据分布导致优化器认为回表更贵。
验证方法:对比“原谓词”与“显式转换后谓词”的计划差异;检查列与参数的类型/字符集;查看 pg_stats.correlation 判断回表成本。
处置指向:修正参数类型与字符集、改写谓词使索引可用、必要时建立表达式索引或覆盖索引([变更])。
1.2.3 不合理的 JOIN
判断依据:连接顺序把大表放在驱动位置、缺少连接列索引、连接算法(Nested Loop/Hash/Merge)与数据量不匹配、笛卡尔积或缺失连接条件、多层嵌套视图导致谓词无法下推。
验证方法:在 EXPLAIN 输出中检查每层的估算行数放大倍数与连接算法;核对连接列两侧的类型、索引与统计信息。
处置指向:为连接列补索引、拆分复杂查询、减少中间结果、必要时改写为分步查询或物化中间结果;避免在生产用优化器提示掩盖统计问题。
1.2.4 数据量增长导致性能退化
判断依据:同一 SQL 指纹的 mean_exec_time 随时间线性/超线性上升;table_rows/n_live_tup、表与索引大小持续增长;缓存命中下降、物理读上升;分区或归档策略缺失。
验证方法:对比多个时间点的表规模、索引规模、缓存命中与该指纹的平均耗时;确认增长是业务自然增长还是清理失效(死元组、无保留策略)。MySQL 8.0 用 information_schema.tables 的 table_rows/data_length 做多点对比前,必须先 SET SESSION information_schema_stats_expiry = 0(绕过数据字典缓存直读存储引擎,有额外开销)或先 ANALYZE TABLE([变更]),否则 information_schema_stats_expiry 默认 86400 秒会让两次采样返回完全相同的缓存值。
处置指向:建立分区/归档/保留策略,评估索引与查询在目标数据量下的表现(上线前做数据规模逼真的计划回归);容量层面参见“磁盘空间不足”场景(存储与日志故障)。
1.3 排查步骤
1.3.1 慢查询日志定位与提取
目的:用累计统计而不是单次最慢定位真正的耗时大户,取得可复现的 SQL 指纹与调用量。
MySQL 8.0 [只读]
SHOW VARIABLES WHERE Variable_name IN ('slow_query_log','long_query_time','log_output','log_queries_not_using_indexes');
SELECT DIGEST, DIGEST_TEXT, COUNT_STAR,
ROUND(SUM_TIMER_WAIT/1e12,3) AS total_s,
ROUND(AVG_TIMER_WAIT/1e9,3) AS avg_ms,
SUM_ROWS_EXAMINED, SUM_ROWS_SENT, FIRST_SEEN, LAST_SEEN
FROM performance_schema.events_statements_summary_by_digest
WHERE SCHEMA_NAME = '<DB>'
ORDER BY SUM_TIMER_WAIT DESC LIMIT 20;
- PostgreSQL 14+ [只读]
SELECT name, setting FROM pg_settings
WHERE name IN ('log_min_duration_statement','shared_preload_libraries','track_io_timing');
SELECT queryid, calls, total_exec_time, mean_exec_time, stddev_exec_time,
rows, shared_blks_read, temp_blks_written, query
FROM pg_stat_statements
WHERE dbid = (SELECT oid FROM pg_database WHERE datname = '<DB>')
ORDER BY total_exec_time DESC LIMIT 20;
关键判断字段:total_s/total_exec_time(总贡献)、avg_ms/mean_exec_time(单次成本)、stddev_exec_time(尾延迟波动)、COUNT_STAR/calls(调用量)、SUM_ROWS_EXAMINED 与 SUM_ROWS_SENT 的比值(扫描放大)、FIRST_SEEN/LAST_SEEN 是否与故障窗口吻合。SQL 文本需脱敏后记录。
下一步:少量单次很慢→“执行计划分析(EXPLAIN)”;高频小 SQL 累计大→合并批量/缓存,并查应用 N+1;扫描放大明显→“索引使用情况分析”;temp_blks_written 高→“内存压力或 OOM”场景;统计缺失(未装 pg_stat_statements/未开慢日志)→按 [变更] 流程开启并设自动到期。
1.3.2 执行计划分析(EXPLAIN)
目的:确认访问路径、连接顺序、估算行数与真实数据分布是否吻合,且优先使用不执行语句的计划。
MySQL 8.0 [只读]
-- FORMAT=TREE 面向 SELECT;对单表 UPDATE/DELETE 在 8.0 输出不可靠,见下文对 DML 的说明
EXPLAIN FORMAT=TREE SELECT * FROM <SCHEMA>.<TABLE> WHERE <COLUMN> = <VALUE>;
EXPLAIN FORMAT=JSON SELECT * FROM <SCHEMA>.<TABLE> WHERE <COLUMN> = <VALUE>;
- PostgreSQL 14+ [只读]
EXPLAIN (VERBOSE, COSTS, SETTINGS)
SELECT * FROM <SCHEMA>.<TABLE> WHERE <COLUMN> = <VALUE>;
关键判断字段:访问方式(ref/range/ALL、Index Scan/Seq Scan/Bitmap Heap Scan)、rows 估算与真实量级差距、连接算法与顺序、是否出现 Using temporary/Using filesort/Sort/Hash 溢写、并行度、SETTINGS 显示的非默认优化器参数。
下一步:估算严重失真→“表统计信息检查”;有索引却不用→“索引使用情况分析”;连接顺序或算法不合理→“不合理的 JOIN”;计划正常但仍慢→“锁等待与资源竞争排查”与“I/O 性能异常”场景。
[高风险] EXPLAIN ANALYZE / EXPLAIN (ANALYZE) 会真实执行 SQL;对 INSERT/UPDATE/DELETE 可产生数据变更,对慢查询可能再次压垮生产。仅在确认语句只读、限定数据范围、设置语句超时、评估锁与 IO,并优先在副本/预发执行后使用。MySQL 8.0 的 EXPLAIN ANALYZE 仅支持 SELECT、TABLE 以及多表 UPDATE/DELETE,不支持单表 UPDATE/DELETE;PostgreSQL 可用 EXPLAIN (ANALYZE, BUFFERS)。 分析 DML 计划时:EXPLAIN FORMAT=TREE 对单表 UPDATE/DELETE 在 8.0 不可靠(可能报错或给出无参考价值的输出),应改用 EXPLAIN FORMAT=JSON UPDATE ...、传统 EXPLAIN UPDATE ...,或分析访问路径等价的 SELECT(把 SET 子句换成 SELECT 列、保留同样的谓词)——这三种方式都不执行 DML。
1.3.3 索引使用情况分析
目的:确认现有索引是否被使用、选择性是否足够,以及是否存在冗余索引带来的写放大。
MySQL 8.0 [只读]
SHOW INDEX FROM <SCHEMA>.<TABLE>;
SELECT OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME,
COUNT_STAR, COUNT_READ, COUNT_WRITE
FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE OBJECT_SCHEMA = '<SCHEMA>' AND OBJECT_NAME = '<TABLE>'
ORDER BY COUNT_STAR DESC;
- PostgreSQL 14+ [只读]
SELECT indexrelname, idx_scan, idx_tup_read, idx_tup_fetch,
pg_size_pretty(pg_relation_size(indexrelid)) AS idx_size
FROM pg_stat_user_indexes
WHERE relname = '<TABLE>' ORDER BY idx_scan;
SELECT relname, seq_scan, seq_tup_read, idx_scan
FROM pg_stat_user_tables WHERE relname = '<TABLE>';
关键判断字段:Cardinality/索引选择性;INDEX_NAME IS NULL 的行代表未走索引的表访问;idx_scan = 0 的索引长期未被使用(需覆盖足够观察周期后才能判定冗余);seq_scan 与 idx_scan 的比例;索引大小相对表大小的成本。
下一步:谓词无可用索引→评估新建索引([变更],见本场景“解决方案”);索引存在但未命中→“索引失效”;索引长期零扫描→纳入索引收益/写成本审计后再决定下线;索引正常→“表统计信息检查”。
1.3.4 表统计信息检查
目的:判断优化器估算失真是否源于统计信息陈旧、采样不足或数据分布倾斜。
MySQL 8.0 [只读]
-- 前提:information_schema.tables 的 table_rows/data_length/data_free/update_time 等动态列取自数据字典缓存,
-- information_schema_stats_expiry 默认 86400 秒,缓存未过期时多次采样可能返回完全相同的值。
-- 需要实时值时先在本会话关闭缓存(仅影响当前会话,会绕过缓存直读存储引擎、有额外开销);
-- 或先对目标表执行 ANALYZE TABLE(属 [变更],会消耗 CPU/IO 并可能改变计划)。
SET SESSION information_schema_stats_expiry = 0;
SELECT table_schema, table_name, table_rows, avg_row_length, data_length, index_length, update_time
FROM information_schema.tables WHERE table_schema='<SCHEMA>' AND table_name='<TABLE>';
-- InnoDB 持久化统计表在 mysql 库,不在 information_schema
SELECT * FROM mysql.innodb_table_stats WHERE database_name='<DB>' AND table_name='<TABLE>';
SELECT * FROM mysql.innodb_index_stats WHERE database_name='<DB>' AND table_name='<TABLE>';
SELECT * FROM information_schema.statistics WHERE table_schema='<SCHEMA>' AND table_name='<TABLE>';
- PostgreSQL 14+ [只读]
SELECT relname, n_live_tup, n_dead_tup, n_mod_since_analyze,
last_analyze, last_autoanalyze, last_vacuum, last_autovacuum
FROM pg_stat_user_tables WHERE relname='<TABLE>';
SELECT attname, n_distinct, null_frac, correlation
FROM pg_stats WHERE schemaname='<SCHEMA>' AND tablename='<TABLE>';
关键判断字段:MySQL 侧看 mysql.innodb_table_stats 的 n_rows(InnoDB 估算行数)、clustered_index_size(聚簇索引页数,反映真实物理规模)、last_update(统计信息最后一次更新时间,距今越远越可疑),以及 mysql.innodb_index_stats 中各索引的 n_diff_pfx%(前缀基数,反映选择性);table_rows/n_live_tup 与真实量级偏差(table_rows 为估算值,且未按上文关闭 information_schema_stats_expiry 或未 ANALYZE TABLE 时可能是最长 24 小时前的缓存值);n_mod_since_analyze 相对表规模的比例;last_analyze/last_autoanalyze 距今时间;n_distinct、null_frac、correlation 反映的分布与物理有序性;n_dead_tup 高会同时影响估算与扫描成本。
下一步:统计明显陈旧→在维护窗口执行 ANALYZE([变更],会消耗 CPU/IO 并可能改变计划,先留存原计划证据);死元组过多→检查 autovacuum 与“长事务”场景(锁与并发故障);分布倾斜→考虑扩展统计、直方图或改写 SQL;统计正常→“锁等待与资源竞争排查”。
1.3.5 锁等待与资源竞争排查
目的:证明 SQL 的耗时是花在执行上还是花在等待锁、IO、缓冲或后台任务上,避免把等待问题当成计划问题优化。
MySQL 8.0 [只读]
SELECT EVENT_NAME, COUNT_STAR, ROUND(SUM_TIMER_WAIT/1e12,3) AS total_s
FROM performance_schema.events_waits_summary_global_by_event_name
WHERE COUNT_STAR > 0
ORDER BY SUM_TIMER_WAIT DESC LIMIT 20;
SELECT * FROM sys.innodb_lock_waits ORDER BY wait_age_secs DESC;
- PostgreSQL 14+ [只读]
SELECT wait_event_type, wait_event, state, COUNT(*) AS sessions,
max(now()-query_start) AS max_age
FROM pg_stat_activity
WHERE state <> 'idle'
GROUP BY wait_event_type, wait_event, state
ORDER BY sessions DESC;
SELECT pid, pg_blocking_pids(pid) AS blockers, wait_event_type, wait_event, left(query, 120) AS q
FROM pg_stat_activity WHERE cardinality(pg_blocking_pids(pid)) > 0;
关键判断字段:等待类别分布(wait/io/*、wait/lock/*、Lock、LWLock、IO、IPC);wait_age_secs 与阻塞链;等待占总耗时的比例;同一 SQL 指纹在无竞争时段的耗时对照。
下一步:锁等待占主导→“锁等待”场景(锁与并发故障);IO 等待占主导→“I/O 性能异常”场景;缓冲/内存相关等待→“内存压力或 OOM”场景;无明显等待→回到“执行计划分析(EXPLAIN)”优化计划,并评估“数据量增长导致性能退化”的数据量因素。
1.4 Agent 诊断提示词
把下面整段复制给 STAROps 数字员工,替换全部占位符后提交。模板是自包含的:候选原因、需要 DBA 执行的只读语句都已写在模板内。
任务:定位"慢查询"场景(性能类故障)的根因,给出可执行处置建议,并保留完整证据链。
【输入补充】
目标 SQL 或接口:<VALUE>;相关 SLO:<VALUE>(如 P99 响应时间目标)
【前置检查补充】
0.2 需确认的日志:慢日志(slow log)。
0.7 慢日志阈值是否过高导致目标 SQL 未被记录(用 OpenAPI 读参数确认)。
指标 Key(MySQL,已核实可直接用于 DescribeDBInstancePerformance 的 Key 参数):
MySQL_QPSTPS —— 每秒 SQL 执行数与每秒事务数(个/秒)
MySQL_SelectScan —— 全表扫描次数(个)
MySQL_TempDiskTableCreates —— 磁盘上自动创建的临时表数量(个)
MySQL_MemCpuUsage —— CPU 使用率与内存使用率(%;Serverless 用 MySQL_RCU_MemCpuUsage)
【数据源(本场景取值)】状态与降级规则按契约执行
云监控 2.0 / 托管 Prometheus:QPS/TPS、活跃会话数、CPU 与 IO 使用率。
CMS2_WORKSPACE 路由:starops observe entity metric-data 或 metric_set query(PromQL)。
ALIYUN_RDS 路由:aliyun rds DescribeDBInstancePerformance 按 Key 拉序列。
SLS(<SLS_PROJECT> 下对应 Logstore):慢日志投递库中按 SQL 指纹聚合的耗时、执行次数与扫描行数。
未投递到 SLS 时改用 OpenAPI:慢日志 DescribeSlowLogs(统计)与
DescribeSlowLogRecords(明细)、错误日志 DescribeErrorLogs。
系统事件与告警:发版、参数组变更、批量导入、索引或统计信息维护。
CMS2_WORKSPACE 路由:starops observe alerts query + changes query +
acm_basic event system-query。
ALIYUN_RDS 路由:aliyun rds DescribeEvents 查历史事件。
云平台 OpenAPI:慢日志阈值等参数当前值、实例规格。
常用接口:DescribeDBInstanceAttribute(实例详情)、DescribeParameters(参数当前值)。
降级兜底:慢日志未开启或阈值过高时,目标 SQL 可能根本没被记录:
此时不得断言"没有慢查询",应标注慢日志覆盖不全并要求先调阈值(属 [变更])。
需 DBA 执行并粘贴:目标 SQL 的执行计划、索引命中与选择性、统计信息新鲜度。
【采集步骤】
A. Agent 自取(逐项回报数据源、取值、采集时间)
1) 从慢日志按 SQL 指纹聚合,取窗口内耗时 P95、执行次数与扫描行数排名前列的指纹。
2) 与基线比对,判断是新出现的指纹、既有指纹变慢,还是调用量上涨。
3) 从 ARMS 取该 SQL 所在接口的调用量与耗时,确认是数据库侧变慢还是调用放大(N+1)。
4) 查事件:窗口前后是否有发版、参数变更、数据导入。
B. 需 DBA 执行只读语句后粘贴原始输出(Agent 无权限;语句已给全,按引擎选用)
1) 执行计划(ANALYZE 会真实执行,写语句禁止直接跑;优先在只读副本执行):
MySQL:EXPLAIN FORMAT=TREE <SQL>; -- 面向 SELECT,不执行
EXPLAIN ANALYZE <SQL>; -- 8.0.18+,会真实执行
PostgreSQL:EXPLAIN (ANALYZE, BUFFERS, VERBOSE) <SQL>;
注意:EXPLAIN ANALYZE 和 PostgreSQL 的 EXPLAIN (ANALYZE, ...) 会真实执行 SQL,
必须在只读副本上执行,禁止在主库高负载时执行写语句的 ANALYZE。
若无只读副本或只读副本不可用,标注执行计划不可得,置信度不得高于中。
2) 索引命中与选择性:
MySQL:SHOW INDEX FROM <SCHEMA>.<TABLE>;
SELECT OBJECT_NAME, INDEX_NAME, COUNT_STAR FROM
performance_schema.table_io_waits_summary_by_index_usage
WHERE OBJECT_SCHEMA='<SCHEMA>' AND OBJECT_NAME='<TABLE>'
ORDER BY COUNT_STAR DESC;
PostgreSQL:SELECT indexrelname, idx_scan, idx_tup_read FROM pg_stat_user_indexes
WHERE relname='<TABLE>' ORDER BY idx_scan;
3) 统计信息新鲜度:
MySQL:SET SESSION information_schema_stats_expiry = 0; -- 默认 86400 秒缓存
SELECT table_rows, update_time FROM information_schema.tables
WHERE table_schema='<SCHEMA>' AND table_name='<TABLE>';
SELECT * FROM mysql.innodb_table_stats WHERE table_name='<TABLE>';
PostgreSQL:SELECT n_live_tup, n_dead_tup, last_analyze, last_autoanalyze
FROM pg_stat_user_tables WHERE relname='<TABLE>';
【候选原因与判定补充】
- 全表扫描
- 索引失效(类型转换、函数包裹、前导列缺失等)
- 不合理的 JOIN(顺序或算法不当)
- 数据量增长导致性能退化
执行计划类结论必须以 DBA 粘贴的计划为依据,Agent 不得由指标反推计划;
缺计划时置信度不得高于中,并列入数据缺口。
判断是单条 SQL 变慢还是整体变慢:后者改按 CPU、内存、I/O 与锁等待方向排查。
1.5 解决方案
先限流、缓存、减少返回数据或回滚问题发布。建索引、改 SQL、更新统计信息均为 [变更]:建索引前评估锁、额外空间、写放大、复制延迟和回滚;ANALYZE TABLE <TABLE> 与 PostgreSQL ANALYZE <SCHEMA>.<TABLE> 也会消耗 CPU/IO 并可能改变计划,应在维护窗口或小范围执行并保留原计划证据。不要因看到全表扫描就机械建索引。
1.6 验证与预防
以相同参数分布和业务流量验证延迟、扫描行、临时文件、锁等待和资源消耗,并观察计划稳定性及复制延迟。上线前做数据规模逼真的计划回归;维护 SQL 指纹基线、统计信息健康度和索引收益/写成本审计。
2. CPU 使用率异常
2.1 现象描述
数据库 CPU 相比自身历史基线持续抬升,队列和延迟同步增加;也可能 CPU 高但吞吐正常,或 CPU 不高却因单核热点、配额节流而慢。
2.2 常见原因
2.2.1 复杂查询或全表扫描
判断依据:少数 SQL 指纹贡献大部分执行时间,SUM_ROWS_EXAMINED/shared_blks_hit 高而返回行少;计划中出现大范围扫描、嵌套循环放大或复杂表达式计算。
验证方法:对照“慢查询”场景的“慢查询日志定位与提取”与“慢查询”场景的“执行计划分析(EXPLAIN)”的指纹与计划;在低峰或副本上复现单条 SQL 的资源消耗。
处置指向:按“慢查询”场景的方案优化计划与索引;短期用限流、缓存或降级减少调用量。
2.2.2 并发过高导致上下文切换
判断依据:活跃并发远超 vCPU 数,单条 SQL 耗时随并发上升而恶化,LWLock/自旋类等待增多,吞吐不再随并发增长甚至下降。
验证方法:对比不同并发水平下的“吞吐-延迟”曲线;观察 Threads_running 与每秒查询数的关系是否已过拐点。
处置指向:在应用与代理层设置并发上限与排队背压,收敛连接池;避免用提高 max_connections 解决并发过载。
2.2.3 排序/聚合操作
判断依据:Created_tmp_disk_tables、Sort_merge_passes、temp_files/temp_bytes、temp_blks_written 增长;计划中出现 Using filesort、Using temporary、Sort、HashAggregate 且数据量大。
验证方法:确认排序/分组列有无可用索引;核对每操作可用工作内存与并发数的乘积是否超出实例内存预算。
处置指向:用索引消除排序、减少分组基数、分页改造;工作内存参数调整属 [变更],须按“每操作 × 并发”建模,参见“内存压力或 OOM”场景。
2.2.4 编译与解析开销
判断依据:大量一次性/未参数化 SQL(指纹数量异常多、每个 calls 很小);MySQL 中 Com_stmt_prepare 与执行次数不匹配;PostgreSQL 中相同结构语句因字面量不同形成大量不同 queryid。
验证方法:统计指纹数量与调用分布;检查应用是否使用预编译语句与参数绑定;观察短连接是否每次重新准备语句。
处置指向:改用参数化/预编译语句并复用连接;减少动态 SQL 拼接;对高频语句评估服务端预处理与缓存策略。
2.3 排查步骤
2.3.1 CPU 使用率趋势分析
目的:先确认 CPU 抬升的形态(阶跃/缓升/周期性/毛刺)、起始时间点,以及是否伴随吞吐同步增长。
云控制台/OS 方法(厂商中立)[只读]:查看实例 CPU 使用率、可运行队列、突发实例的 CPU 积分与节流指标、规格变更与维护事件;有主机权限时用 top/vmstat 1 区分 user/sys/iowait/steal。
MySQL 8.0 [只读]
SHOW GLOBAL STATUS WHERE Variable_name IN
('Uptime','Queries','Questions','Com_select','Com_insert','Com_update','Com_delete',
'Threads_running','Threads_connected','Created_tmp_disk_tables','Select_scan','Sort_merge_passes');
- PostgreSQL 14+ [只读]
SELECT datname, xact_commit, xact_rollback, tup_returned, tup_fetched,
tup_inserted, tup_updated, tup_deleted, temp_files, temp_bytes, stats_reset
FROM pg_stat_database WHERE datname = '<DB>';
关键判断字段:两次采样差值算出的每秒事务/查询数;Threads_running 反映的真实并发;tup_returned/tup_fetched 比值反映扫描效率;Created_tmp_disk_tables、temp_bytes 反映排序/聚合落盘;CPU 抬升是否与业务量同比例(同比例多为容量问题,不同比例多为效率问题)。
下一步:负载同比例增长→容量评估与限流;吞吐不变而 CPU 升→“高 CPU 消耗 SQL 定位”;Threads_running 高但吞吐低→“并发连接数与活跃线程分析”;steal/积分节流→平台侧规格问题;iowait 高→“I/O 性能异常”场景。
2.3.2 高 CPU 消耗 SQL 定位
目的:找出对 CPU 时间贡献最大的 SQL 指纹与后台任务,而不是只看当前最慢的一条。
MySQL 8.0 [只读]
SELECT DIGEST_TEXT, COUNT_STAR,
ROUND(SUM_TIMER_WAIT/1e12,3) AS total_s,
SUM_ROWS_EXAMINED, SUM_ROWS_SENT,
SUM_CREATED_TMP_DISK_TABLES, SUM_SORT_MERGE_PASSES, SUM_NO_INDEX_USED
FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WAIT DESC LIMIT 20;
- PostgreSQL 14+ [只读]
SELECT queryid, calls, total_exec_time, mean_exec_time, rows,
shared_blks_hit, shared_blks_read, temp_blks_written, query
FROM pg_stat_statements
ORDER BY total_exec_time DESC LIMIT 20;
SELECT pid, backend_type, state, wait_event_type, wait_event,
now()-query_start AS age, left(query,120) AS q
FROM pg_stat_activity WHERE state='active' ORDER BY query_start LIMIT 20;
关键判断字段:总执行时间包含等待,需结合等待事件才能近似 CPU 时间;SUM_ROWS_EXAMINED、SUM_NO_INDEX_USED、SUM_SORT_MERGE_PASSES 指向计算型开销;shared_blks_hit 高而 read 低但耗时长通常是纯 CPU 型;backend_type 区分用户会话与后台进程(autovacuum、walwriter、checkpointer)。
下一步:集中在少数指纹→“慢查询”场景;集中在后台维护→调整维护窗口与节奏([变更]);排序/聚合型→“排序/聚合操作”与“内存压力或 OOM”场景;无 SQL 可解释→“系统进程与数据库进程区分”。
2.3.3 并发连接数与活跃线程分析
目的:判断 CPU 抬升是否由并发过高、上下文切换和锁竞争引起,而非单条 SQL 变慢。
MySQL 8.0 [只读]
SHOW GLOBAL STATUS WHERE Variable_name IN
('Threads_running','Threads_connected','Threads_created','Table_locks_waited','Innodb_row_lock_waits');
SELECT COUNT(*) AS running, PROCESSLIST_STATE
FROM performance_schema.threads
WHERE TYPE='FOREGROUND' AND PROCESSLIST_COMMAND <> 'Sleep'
GROUP BY PROCESSLIST_STATE ORDER BY running DESC;
- PostgreSQL 14+ [只读]
SELECT count(*) FILTER (WHERE state='active') AS active,
count(*) FILTER (WHERE state='idle') AS idle,
count(*) FILTER (WHERE wait_event_type='Lock') AS waiting_on_lock,
count(*) FILTER (WHERE wait_event_type='LWLock') AS waiting_lwlock
FROM pg_stat_activity;
SELECT name, setting FROM pg_settings
WHERE name IN ('max_connections','max_parallel_workers','max_parallel_workers_per_gather');
关键判断字段:活跃并发是否远超实例 vCPU 数(并发过高会把 CPU 花在调度与竞争上);Threads_created 增长快说明连接未复用;锁等待与 LWLock 等待数量;并行 worker 配置是否放大了单查询的 CPU 占用。
下一步:并发远超 vCPU→在应用/代理层限制并发并排队(优先应用侧);连接创建速率高→“连接数耗尽”场景(连接类故障);锁等待多→“锁等待”场景(锁与并发故障);并行度过高→评估调低并行参数([变更])。
2.3.4 系统进程与数据库进程区分
目的:确认 CPU 是被数据库主进程消耗,还是被备份代理、日志采集、监控探针、加密/压缩或平台后台任务占用。
OS/云控制台方法(厂商中立)[只读]:有主机权限时用 top -H、pidstat 1、ps -eo pid,pcpu,comm --sort=-pcpu | head 查看进程级占用;托管实例无主机权限时,用控制台的进程/会话诊断、备份任务时间表与平台事件对齐时间线。
MySQL 8.0 [只读]:区分前台会话与后台线程。
SELECT NAME, TYPE, PROCESSLIST_COMMAND, PROCESSLIST_STATE, COUNT(*) AS threads
FROM performance_schema.threads
GROUP BY NAME, TYPE, PROCESSLIST_COMMAND, PROCESSLIST_STATE
ORDER BY threads DESC LIMIT 30;
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
- PostgreSQL 14+ [只读]
SELECT backend_type, count(*) AS procs,
count(*) FILTER (WHERE state='active') AS active
FROM pg_stat_activity GROUP BY backend_type ORDER BY procs DESC;
SELECT pid, backend_type, query_start, left(query,100) AS q
FROM pg_stat_activity WHERE backend_type <> 'client backend';
关键判断字段:TYPE='BACKGROUND' 线程或 backend_type 非 client backend 的进程是否占据主要活跃度(autovacuum、checkpointer、walwriter、logical replication launcher);OS 侧非数据库进程(备份、日志代理、杀毒、监控)的 CPU 占用;sys 时间高通常指向系统调用/中断而非 SQL。
下一步:数据库后台任务为主→调整 autovacuum/检查点/备份窗口([变更]);非数据库进程为主→由平台或运维侧治理,不改数据库参数;确认为 SQL 型→回到“高 CPU 消耗 SQL 定位”;无法归因且平台受限→提交工单并附时间线证据。
2.4 Agent 诊断提示词
把下面整段复制给 STAROps 数字员工,替换全部占位符后提交。模板是自包含的:候选原因、需要 DBA 执行的只读语句都已写在模板内。
任务:定位"CPU 使用率异常"场景(性能类故障)的根因,给出可执行处置建议,并保留完整证据链。
【前置检查补充】
0.2 需确认的日志:慢日志与实例错误日志。
0.7 实例是否为突发规格;若是,需确认 CPU 积分与节流指标是否可得。
指标 Key(MySQL,已核实可直接用于 DescribeDBInstancePerformance 的 Key 参数):
MySQL_MemCpuUsage —— CPU 与内存使用率(%;Serverless 用 MySQL_RCU_MemCpuUsage)
MySQL_QPSTPS —— 每秒 SQL 执行数与每秒事务数(个/秒)
MySQL_ThreadStatus —— 活跃线程数与线程连接数(个)
MySQL_SelectScan —— 全表扫描次数(个)
【数据源(本场景取值)】状态与降级规则按契约执行
云监控 2.0 / 托管 Prometheus:CPU 使用率、活跃会话与线程数、QPS、连接数、(突发规格)CPU
积分与节流指标。
CMS2_WORKSPACE 路由:starops observe entity metric-data 或 metric_set query(PromQL)。
ALIYUN_RDS 路由:aliyun rds DescribeDBInstancePerformance 按 Key 拉序列。
SLS(<SLS_PROJECT> 下对应 Logstore):慢日志投递库中按指纹聚合的耗时总和;错误日志中的资
源类告警。
未投递到 SLS 时改用 OpenAPI:慢日志 DescribeSlowLogs(统计)与
DescribeSlowLogRecords(明细)、错误日志 DescribeErrorLogs。
系统事件与告警:规格变更、备份、平台维护、参数组变更。
CMS2_WORKSPACE 路由:starops observe alerts query + changes query +
acm_basic event system-query。
ALIYUN_RDS 路由:aliyun rds DescribeEvents 查历史事件。
云平台 OpenAPI:实例规格与 vCPU、参数组当前值。
常用接口:DescribeDBInstanceAttribute(实例详情)、DescribeParameters(参数当前值)。
降级兜底:突发规格的 CPU 积分与节流指标不一定暴露;缺失时不得排除节流,
应标注为未验证并要求托管侧确认。
需 DBA 执行并粘贴:按累计耗时排序的语句摘要、当前活跃线程数与等待事件分布。
【采集步骤】
A. Agent 自取(逐项回报数据源、取值、采集时间)
1) 取 CPU 曲线与 QPS、连接数、活跃会话叠加,区分持续走高与瞬时尖刺,并与基线 P95 比对。
2) 判断是否触达规格上限或突发额度被节流(CPU 积分类指标)。
3) 从慢日志按指纹聚合耗时总和,列出 CPU 贡献的候选语句。
4) 查事件:备份窗口、规格变更、参数组变更、平台维护。
B. 需 DBA 执行只读语句后粘贴原始输出(Agent 无权限;语句已给全,按引擎选用)
1) 高消耗语句排名:
MySQL:SELECT DIGEST_TEXT, COUNT_STAR, SUM_TIMER_WAIT, SUM_ROWS_EXAMINED
FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WAIT DESC LIMIT 10;
PostgreSQL:SELECT query, calls, total_exec_time, mean_exec_time, rows
FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 10;
-- 需已安装 pg_stat_statements 扩展
2) 并发与等待分布:
MySQL:SHOW GLOBAL STATUS WHERE Variable_name IN ('Threads_running',
'Threads_connected','Created_tmp_disk_tables','Select_scan');
PostgreSQL:SELECT state, wait_event_type, wait_event, count(*)
FROM pg_stat_activity GROUP BY 1,2,3 ORDER BY 4 DESC;
【候选原因与判定补充】
- 复杂查询或全表扫描
- 并发过高导致上下文切换
- 排序与聚合操作消耗 CPU
- 语句编译与解析开销(如未使用预编译、大量硬解析)
CPU 高但 QPS 未涨时优先查计划退化、统计信息陈旧与后台任务,不要先建议升配。
仅凭指标无法区分有效利用与低效放大,必须结合语句侧证据;缺该证据时明确写出。
2.5 解决方案
优先限流、回滚异常发布、优化高贡献 SQL、分散批任务;确认长期需求后扩容。参数、并行度、实例规格变更为 [变更],须评估重启/切换、成本、计划变化和回滚。不要以固定 CPU 百分比单独判定故障,CPU 接近规格上限但 SLO、队列和吞吐稳定时可能是有效利用。
2.6 验证与预防
验证业务 SLO、运行队列、吞吐/CPU 比和热点 SQL 贡献恢复历史区间;观察完整峰值周期。建立按工作负载分层的基线、发布前压测、查询预算、批任务窗口和扩容触发条件。
3. 内存压力或 OOM
3.1 现象描述
实例可用内存下降、交换/内存回收增多、进程被 OOM、连接断开或重启;查询大量落盘,延迟波动。托管平台可能仅暴露“可用内存”“缓存”“临时文件”等聚合指标。
3.2 常见原因
3.2.1 缓存配置不合理
判断依据:全局缓存过大挤压会话内存与操作系统余量(表现为 OOM 或 swap),或过小导致物理读与 IO 时延上升;参数与实例规格不匹配,或规格缩容后未同步调整。
验证方法:核算缓存 + 会话内存最坏用量 + 平台保留是否超过实例内存;对比缓存调整前后的物理读与 IO 时延。
处置指向:按规格重新建模缓存比例([变更],需确认是否重启),在预发压测验证;过度缩小内存会把问题转化为 IO 故障。
3.2.2 大查询导致内存溢出
判断依据:单条大排序/哈希/聚合/大结果集查询运行期间内存陡增、临时文件暴涨;work_mem 与并行 worker 叠加放大;批处理与在线业务重叠。
验证方法:用“内存分配与泄漏排查”定位高内存会话;在副本上复现该查询并观察临时文件与内存曲线。
处置指向:限制该类查询的并发与运行窗口、改写为分批/流式处理、按会话级设置更保守的工作内存;必要时对该会话降级或取消([高风险],按“连接数耗尽”场景“解决方案”的前置条件执行)。
3.2.3 连接数过多占用内存
判断依据:内存用量与连接数强相关;每连接固定开销(线程栈、会话缓冲、PostgreSQL 每后端进程基础内存)× 连接数已接近规格;连接池总量超容量。
验证方法:以“连接数 × 每连接内存估算”对照实例内存;观察连接数回落后内存是否同步回落。
处置指向:收敛连接池与副本数,引入连接代理复用;参见“连接数耗尽”场景(连接类故障)的全局连接预算方法。
3.2.4 临时表/排序占用
判断依据:Created_tmp_disk_tables、Sort_merge_passes、temp_files/temp_bytes、temp_blks_written 持续增长;计划中出现 Using temporary、Using filesort、外部排序/哈希溢写。
验证方法:定位产生临时对象的 SQL 指纹(“慢查询”场景的“慢查询日志定位与提取”、“CPU 使用率异常”场景的“高 CPU 消耗 SQL 定位”);确认临时空间落在哪类存储上及其容量。
处置指向:用索引消除排序、降低分组基数、分页与预聚合;控制并发;临时空间容量问题参见“磁盘空间不足”场景(存储与日志故障)。
3.3 排查步骤
3.3.1 内存使用趋势分析
目的:确认内存下降的形态与起点,并核算参数上限在最坏并发下的理论用量是否超过实例规格。
云控制台/OS 方法(厂商中立)[只读]:查看内存使用率、可用内存、swap、OOM/重启事件;有主机权限时用 free -m、vmstat 1、cat /proc/meminfo 观察回收与 swap 活动。
MySQL 8.0 [只读]
SHOW VARIABLES WHERE Variable_name IN
('innodb_buffer_pool_size','innodb_buffer_pool_instances','max_connections',
'sort_buffer_size','join_buffer_size','read_buffer_size','read_rnd_buffer_size',
'tmp_table_size','max_heap_table_size','table_open_cache','thread_stack');
SHOW GLOBAL STATUS WHERE Variable_name IN
('Threads_connected','Threads_running','Created_tmp_tables','Created_tmp_disk_tables');
- PostgreSQL 14+ [只读]
SELECT name, setting, unit, source, pending_restart
FROM pg_settings
WHERE name IN ('shared_buffers','work_mem','maintenance_work_mem','hash_mem_multiplier',
'max_connections','temp_buffers','effective_cache_size','huge_pages',
'autovacuum_max_workers','max_parallel_workers');
关键判断字段:全局缓存(innodb_buffer_pool_size/shared_buffers)与实例内存的比例;会话级缓冲 × 并发 × 每查询可能的多次分配(PostgreSQL 每个排序/哈希节点可各用一份 work_mem,并行 worker 会翻倍);pending_restart 是否表示参数未生效;内存下降与连接数/临时表增长的时间相关性。
下一步:连接数相关→“连接数耗尽”场景(连接类故障);缓存命中相关→“Buffer Pool / Shared Buffer 命中率检查”;疑似持续泄漏→“内存分配与泄漏排查”;已发生 OOM→“OOM 日志分析”。
3.3.2 Buffer Pool / Shared Buffer 命中率检查
目的:判断缓存是否被挤压或过小,理解内存与 IO 的取舍关系;命中率需与工作集、IO 时延一起解读,不套用固定目标值。
MySQL 8.0 [只读]
SHOW GLOBAL STATUS WHERE Variable_name IN
('Innodb_buffer_pool_read_requests','Innodb_buffer_pool_reads',
'Innodb_buffer_pool_pages_total','Innodb_buffer_pool_pages_free',
'Innodb_buffer_pool_pages_dirty','Innodb_buffer_pool_wait_free',
'Innodb_pages_read','Innodb_pages_written');
SELECT POOL_ID, POOL_SIZE, FREE_BUFFERS, DATABASE_PAGES, MODIFIED_DATABASE_PAGES
FROM information_schema.innodb_buffer_pool_stats;
- PostgreSQL 14+ [只读]
SELECT datname, blks_read, blks_hit,
blk_read_time, blk_write_time
FROM pg_stat_database WHERE datname='<DB>';
SELECT relname, heap_blks_read, heap_blks_hit, idx_blks_read, idx_blks_hit
FROM pg_statio_user_tables
ORDER BY (heap_blks_read + idx_blks_read) DESC LIMIT 20;
关键判断字段:用两个时间点差值计算物理读增量与命中比(累计值直接相除会被历史稀释);Innodb_buffer_pool_wait_free 非零说明缓冲区吃紧;FREE_BUFFERS、脏页比例;PostgreSQL 中高 blks_read 对象说明工作集超出缓存或被大扫描冲刷。
下一步:命中下降由大扫描冲刷引起→优化 SQL(“慢查询”场景)而非直接扩缓存;工作集确实超出内存→评估扩容或数据分层([变更]);缓存被会话内存挤压→“内存使用趋势分析”、“内存分配与泄漏排查”;伴随 IO 时延升高→“I/O 性能异常”场景。
3.3.3 内存分配与泄漏排查
目的:区分“并发峰值导致的瞬时高用量”与“不随负载回落的持续增长”,后者需要怀疑扩展/引擎缺陷或未释放的会话资源。
MySQL 8.0 [只读]
SELECT EVENT_NAME, CURRENT_COUNT_USED,
CURRENT_NUMBER_OF_BYTES_USED, HIGH_NUMBER_OF_BYTES_USED
FROM performance_schema.memory_summary_global_by_event_name
WHERE CURRENT_NUMBER_OF_BYTES_USED > 0
ORDER BY CURRENT_NUMBER_OF_BYTES_USED DESC LIMIT 20;
SELECT THREAD_ID, EVENT_NAME, CURRENT_NUMBER_OF_BYTES_USED
FROM performance_schema.memory_summary_by_thread_by_event_name
ORDER BY CURRENT_NUMBER_OF_BYTES_USED DESC LIMIT 20;
- PostgreSQL 14+ [只读]
SELECT datname, temp_files, temp_bytes FROM pg_stat_database WHERE datname='<DB>';
SELECT pid, backend_type, state, now()-backend_start AS conn_age,
now()-xact_start AS xact_age, wait_event_type, left(query,120) AS q
FROM pg_stat_activity
WHERE state <> 'idle' ORDER BY backend_start LIMIT 30;
SELECT name, setting FROM pg_settings WHERE name IN ('shared_preload_libraries','max_locks_per_transaction');
关键判断字段:内存类别的当前值与高水位差距;单线程占用是否异常集中;长连接的内存是否随连接年龄单调上升(典型泄漏形态);temp_bytes 是否随并发回落;是否加载了第三方扩展/插件。
注意:PostgreSQL 14 没有完整的全局内存归因视图,需结合云指标、进程级 RSS(若有权限)与计划分析;MySQL 部分内存 instrument 默认未启用,开启属 [变更]。
下一步:随并发涨落→限制并发与工作内存;单调持续增长→保留证据并升级云厂商/社区(怀疑缺陷),期间用滚动重启会话或计划内重启缓解([高风险],需评估中断影响);集中于某扩展→评估下线或升级该扩展。
3.3.4 OOM 日志分析
目的:确认是否真的发生 OOM、被终止的是哪个进程、触发时刻的并发与查询特征,防止误把普通重启当 OOM。
云控制台/OS 方法(厂商中立)[只读]:从平台日志服务读取数据库错误日志与实例事件;有主机权限时检查内核日志中的 OOM killer 记录(如 dmesg -T | grep -i -E 'oom|killed process'、journalctl -k);记录 UTC 时间点用于对齐监控曲线。
MySQL 8.0 [只读]
SHOW GLOBAL STATUS LIKE 'Uptime';
SELECT VARIABLE_NAME, VARIABLE_VALUE FROM performance_schema.global_status
WHERE VARIABLE_NAME IN ('Aborted_clients','Connection_errors_internal','Innodb_buffer_pool_resize_status');
- PostgreSQL 14+ [只读]
SELECT pg_postmaster_start_time() AS last_start,
now()-pg_postmaster_start_time() AS uptime;
SELECT datname, sessions_fatal, sessions_killed, sessions_abandoned, stats_reset
FROM pg_stat_database WHERE datname='<DB>';
关键判断字段:Uptime/last_start 是否与 OOM 时刻吻合;错误日志中的 Out of memory、server process was terminated by signal 9、terminating connection because of crash of another server process;OOM 时刻的连接数、活跃排序/哈希数量与批任务时间表;被杀进程是数据库主进程还是同主机的其他进程。
下一步:确认 OOM→按本场景“解决方案”做容量与并发建模,收敛工作内存与连接预算([变更]);非 OOM 重启→按平台事件排查(“连接超时/拒绝”场景的“实例运行状态确认”);反复 OOM 且无法归因→保留日志与曲线提工单,避免只调大内存参数掩盖问题。
3.4 Agent 诊断提示词
把下面整段复制给 STAROps 数字员工,替换全部占位符后提交。模板是自包含的:候选原因、需要 DBA 执行的只读语句都已写在模板内。
任务:定位"内存压力或 OOM"场景(性能类故障)的根因,给出可执行处置建议,并保留完整证据链。
【输入补充】
实例规格内存:<VALUE>;是否发生过 OOM 或自动重启:是 / 否
【前置检查补充】
0.2 需确认的日志:实例错误日志。
0.7 OOM 与重启是否体现在系统事件中;事件缺失时以错误日志与指标断点为准。
指标 Key(MySQL,已核实可直接用于 DescribeDBInstancePerformance 的 Key 参数):
MySQL_MemCpuUsage —— CPU 与内存使用率(%;Serverless 用 MySQL_RCU_MemCpuUsage)
MySQL_InnoDBBufferRatio —— 缓冲池读命中率、使用率、脏块百分比(%)
MySQL_TempDiskTableCreates —— 磁盘临时表数量(个)
MySQL_Sessions —— 当前活跃连接数与当前总连接数(个)
【数据源(本场景取值)】状态与降级规则按契约执行
云监控 2.0 / 托管 Prometheus:内存使用率、缓存命中相关指标、连接数、临时空间使用。
CMS2_WORKSPACE 路由:starops observe entity metric-data 或 metric_set query(PromQL)。
ALIYUN_RDS 路由:aliyun rds DescribeDBInstancePerformance 按 Key 拉序列。
SLS(<SLS_PROJECT> 下对应 Logstore):错误日志中的内存分配失败、OOM 记录、重启前后日志。
未投递到 SLS 时改用 OpenAPI:慢日志 DescribeSlowLogs(统计)与
DescribeSlowLogRecords(明细)、错误日志 DescribeErrorLogs。
系统事件与告警:实例重启、规格变更、参数组变更。
CMS2_WORKSPACE 路由:starops observe alerts query + changes query +
acm_basic event system-query。
ALIYUN_RDS 路由:aliyun rds DescribeEvents 查历史事件。
云平台 OpenAPI:规格内存、缓冲池与工作内存类参数当前值。
常用接口:DescribeDBInstanceAttribute(实例详情)、DescribeParameters(参数当前值)。
降级兜底:OOM 事件不一定进系统事件流;事件缺失时以错误日志记录与指标
断点推断,并把该判定标注为间接证据。
需 DBA 执行并粘贴:缓存命中情况、内存类参数当前值、临时表与排序落盘计数。
【采集步骤】
A. Agent 自取(逐项回报数据源、取值、采集时间)
1) 取内存使用率曲线并与重启或 OOM 事件对齐,确认是缓升、阶跃还是尖刺。
2) 调 OpenAPI 读规格内存与关键内存参数,做静态超配核算(缓冲池占比 + 每连接开销 ×
峰值连接)。
3) 查错误日志中的分配失败与 OOM 记录,取首次出现时间。
4) 从 ARMS 找大结果集或全量导出类接口的调用时间点。
B. 需 DBA 执行只读语句后粘贴原始输出(Agent 无权限;语句已给全,按引擎选用)
1) 缓存效果与内存参数(用于核算,不设固定命中率目标):
MySQL:SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';
SHOW VARIABLES WHERE Variable_name IN ('innodb_buffer_pool_size',
'sort_buffer_size','join_buffer_size','read_buffer_size',
'tmp_table_size','max_connections');
PostgreSQL:SELECT blks_hit, blks_read FROM pg_stat_database
WHERE datname = current_database();
SHOW shared_buffers; SHOW work_mem; SHOW maintenance_work_mem;
2) 临时空间与排序落盘:
MySQL:SHOW GLOBAL STATUS LIKE 'Created_tmp%';
PostgreSQL:SELECT temp_files, temp_bytes FROM pg_stat_database
WHERE datname = current_database();
【候选原因与判定补充】
- 缓存配置不合理(缓冲池占比过高或过低)
- 大查询导致内存溢出(大排序、大哈希、未分页导出)
- 连接数过多,每连接开销累积
- 临时表与排序占用超出预期
结论必须写出算式(参数值 × 并发数),区分静态超配与运行期峰值。
调整缓冲池、工作内存或连接数均属 [变更],需给出计算依据与回滚值。
3.5 解决方案
先限流、停止可取消的批任务、降低高内存查询并发;明确异常会话后再考虑终止。调整缓冲池、work_mem、连接数或实例规格均为 [变更],需按“每操作 × 并发”建模,在预发压测并确认重启要求;过度缩小内存会转化为 IO 故障。终止会话遵循“连接数耗尽”场景的“解决方案”的 [高风险] 前置条件。
3.6 验证与预防
验证无新增 OOM/重启,内存余量能覆盖峰值与故障切换,临时文件和 IO 未异常放大。建立连接与查询并发预算、内存参数评审、批任务错峰、OOM 事件告警和容量压测。
4. I/O 性能异常
4.1 现象描述
读写延迟上升、IOPS/吞吐达到规格边界、队列加深,查询和提交变慢;CPU 可能下降,因为会话在等待存储。
4.2 常见原因
4.2.1 大量随机写入
判断依据:写 IOPS 高但吞吐不高(小块随机写);脏页与刷盘量大;buffers_checkpoint/Innodb_buffer_pool_pages_flushed 增长快;更新分散在大量页上,或使用随机主键(如无序 UUID)导致页分裂。
验证方法:核对写入 SQL 的主键/索引分布与批量提交方式;观察单次事务修改行数与涉及页数。
处置指向:改为有序主键或批量顺序写、合并小事务、降低索引数量以减少写放大;短期错峰批任务。
4.2.2 日志刷盘瓶颈
判断依据:Innodb_os_log_fsyncs/Innodb_log_waits 高、提交延迟上升;PostgreSQL 中 WALWrite/WALSync 等待明显、buffers_backend_fsync 非零;高持久化设置(每次提交 fsync)叠加高频小事务。
验证方法:对比提交速率与日志写入量、fsync 次数;观察 synchronous_commit/innodb_flush_log_at_trx_commit/sync_binlog 当前取值。
处置指向:合并小事务、批量提交;日志缓冲与检查点参数调整属 [变更];持久化级别的任何放宽都必须由业务与合规明确接受 RPO 变化,禁止为性能私自关闭持久化。
4.2.3 磁盘规格不足
判断依据:IOPS/吞吐长期贴住规格上限并出现限流指标;突发额度耗尽后时延阶跃上升;容量型盘因容量小而性能上限低。
验证方法:对照云盘规格承诺与实测曲线;确认是持续贴顶还是仅峰值触顶;核算业务增长后的需求。
处置指向:提升容量/盘型/额度([变更],评估成本与是否需迁移窗口);同时做 SQL 与写入整形,避免只靠扩容。
4.2.4 数据文件碎片化
判断依据:MySQL information_schema.tables.data_free 较大、表重建后大小明显下降(读取该列前需先 SET SESSION information_schema_stats_expiry = 0 或先 ANALYZE TABLE,否则可能是最长 24 小时前的数据字典缓存值);PostgreSQL n_dead_tup 高、表/索引膨胀、顺序扫描成本高于同规模新表;pg_stats.correlation 接近 0 表示物理无序。
验证方法:在副本或采样上做膨胀评估,避免在生产做高代价全量分析;结合长事务与 autovacuum 情况判断成因。
处置指向:优先普通 VACUUM/在线重整能力与索引重建;VACUUM FULL、OPTIMIZE TABLE、表重建为 [高风险](强锁、额外空间、写放大、复制延迟),须在维护窗口并有完整备份与回滚计划;先解决阻碍清理的长事务(“长事务”场景(锁与并发故障))。
4.3 排查步骤
4.3.1 磁盘 I/O 指标分析(IOPS/延迟/吞吐量)
目的:先用设备层指标确认是否触达规格边界或突发额度耗尽,再看数据库内部视角。
云控制台/OS 方法(厂商中立)[只读]:查看云盘读写 IOPS、吞吐、平均/尾时延、队列深度、突发额度余量与限流指标;有主机权限时用 iostat -xz 1、vmstat 1 观察 await、%util、aqu-sz。
MySQL 8.0 [只读]
SHOW GLOBAL STATUS WHERE Variable_name IN
('Innodb_data_reads','Innodb_data_writes','Innodb_data_read','Innodb_data_written',
'Innodb_os_log_written','Innodb_log_waits','Innodb_buffer_pool_wait_free');
SELECT EVENT_NAME, COUNT_STAR,
ROUND(SUM_TIMER_WAIT/1e12,3) AS total_s
FROM performance_schema.events_waits_summary_global_by_event_name
WHERE EVENT_NAME LIKE 'wait/io/%' AND COUNT_STAR > 0
ORDER BY SUM_TIMER_WAIT DESC LIMIT 20;
- PostgreSQL 14+ [只读]
SHOW track_io_timing;
SELECT datname, blks_read, blks_hit, blk_read_time, blk_write_time,
temp_files, temp_bytes
FROM pg_stat_database WHERE datname='<DB>';
SELECT wait_event_type, wait_event, count(*) AS sessions
FROM pg_stat_activity WHERE wait_event_type = 'IO'
GROUP BY wait_event_type, wait_event ORDER BY sessions DESC;
关键判断字段:设备 await/云盘时延与规格承诺的关系;IOPS/吞吐是否贴住上限(贴住即限流);Innodb_log_waits 非零说明日志缓冲不足;blk_read_time/blk_write_time 需 track_io_timing=on(开启属 [变更],有一定开销);读、写、临时、日志 IO 各自占比。
下一步:设备贴限→提升规格/额度或整形写入([变更]);读放大为主→“慢 I/O 相关 SQL 定位”;日志写为主→“日志写入与数据写入分离分析”;临时 IO 为主→“内存压力或 OOM”场景;空间紧张→“磁盘空间不足”场景(存储与日志故障)。
4.3.2 慢 I/O 相关 SQL 定位
目的:把 IO 压力归因到具体 SQL 指纹与对象,避免只做规格扩容。
MySQL 8.0 [只读]
SELECT FILE_NAME, EVENT_NAME, COUNT_READ, SUM_NUMBER_OF_BYTES_READ,
COUNT_WRITE, SUM_NUMBER_OF_BYTES_WRITE,
ROUND(SUM_TIMER_READ/1e12,3) AS read_s, ROUND(SUM_TIMER_WRITE/1e12,3) AS write_s
FROM performance_schema.file_summary_by_instance
ORDER BY (SUM_TIMER_READ + SUM_TIMER_WRITE) DESC LIMIT 20;
SELECT OBJECT_SCHEMA, OBJECT_NAME, COUNT_READ, COUNT_WRITE, SUM_TIMER_WAIT
FROM performance_schema.table_io_waits_summary_by_table
ORDER BY SUM_TIMER_WAIT DESC LIMIT 20;
- PostgreSQL 14+ [只读]
-- PG14~16 列名如下;PG17 起 blk_read_time/blk_write_time 改名为 shared_blk_read_time/shared_blk_write_time
SELECT queryid, calls, shared_blks_read, shared_blks_written,
temp_blks_read, temp_blks_written, blk_read_time, blk_write_time, query
FROM pg_stat_statements
ORDER BY (shared_blks_read + temp_blks_written) DESC LIMIT 20;
SELECT relname, heap_blks_read, idx_blks_read, toast_blks_read
FROM pg_statio_user_tables
ORDER BY (heap_blks_read + idx_blks_read) DESC LIMIT 20;
关键判断字段:按对象/文件排序的读写字节与耗时;temp_blks_written 指向排序/哈希落盘;TOAST 读高说明大字段访问;同一对象在故障窗口与基线窗口的差值(用两点差值,不比较不同运行时长的实例)。
下一步:少数对象/指纹贡献主要 IO→“慢查询”场景优化计划与索引;临时 IO 为主→“内存压力或 OOM”场景的“临时表/排序占用”;写入集中在日志文件→“日志写入与数据写入分离分析”;分布均匀且贴设备上限→“磁盘类型与规格确认”。
4.3.3 日志写入与数据写入分离分析
目的:区分“数据页刷盘/检查点”与“事务日志顺序写”的压力来源,二者的优化手段完全不同。
MySQL 8.0 [只读]
SHOW GLOBAL STATUS WHERE Variable_name IN
('Innodb_os_log_written','Innodb_os_log_fsyncs','Innodb_log_writes','Innodb_log_waits',
'Innodb_buffer_pool_pages_dirty','Innodb_buffer_pool_pages_flushed','Innodb_data_fsyncs');
SHOW VARIABLES WHERE Variable_name IN
('innodb_flush_log_at_trx_commit','sync_binlog','innodb_io_capacity','innodb_io_capacity_max',
'innodb_flush_method','innodb_redo_log_capacity');
-- innodb_redo_log_capacity 为 8.0.30+;更早版本 redo 容量由
-- innodb_log_file_size × innodb_log_files_in_group 决定:
-- SHOW VARIABLES WHERE Variable_name IN ('innodb_log_file_size','innodb_log_files_in_group');
- PostgreSQL 14+ [只读]
-- PostgreSQL 14~16:checkpoint 相关列与 buffers_backend* 都在 pg_stat_bgwriter
SELECT checkpoints_timed, checkpoints_req, checkpoint_write_time, checkpoint_sync_time,
buffers_checkpoint, buffers_clean, maxwritten_clean, buffers_backend, buffers_backend_fsync
FROM pg_stat_bgwriter;
-- PostgreSQL 17 起:checkpoint 相关列迁到 pg_stat_checkpointer 并改名,
-- buffers_backend/buffers_backend_fsync 已移除(后端刷写量改由 pg_stat_io 观察),17/18 上请改用:
-- SELECT num_timed, num_requested, write_time, sync_time, buffers_written FROM pg_stat_checkpointer;
-- SELECT buffers_clean, maxwritten_clean FROM pg_stat_bgwriter;
SELECT name, setting, unit FROM pg_settings
WHERE name IN ('wal_buffers','wal_writer_delay','synchronous_commit','max_wal_size',
'checkpoint_timeout','checkpoint_completion_target','wal_compression');
关键判断字段:Innodb_os_log_written 增速代表 redo 顺序写量;Innodb_log_waits 非零代表日志缓冲不足;checkpoints_req 明显多于 checkpoints_timed 说明写入量迫使请求型检查点(IO 尖峰来源);buffers_backend/buffers_backend_fsync 高说明后端进程被迫自己刷盘;持久化参数(innodb_flush_log_at_trx_commit、sync_binlog、synchronous_commit)决定 fsync 频率。
版本分支:本文的“PostgreSQL 14+”不代表列名在各大版本不变。PG17 起 pg_stat_bgwriter 的 checkpoint 相关列迁移到 pg_stat_checkpointer 并改名(checkpoints_timed→num_timed、checkpoints_req→num_requested、checkpoint_write_time→write_time、checkpoint_sync_time→sync_time、buffers_checkpoint→buffers_written),buffers_backend/buffers_backend_fsync 被移除(后端刷写与 fsync 改由 pg_stat_io 观察);pg_stat_statements 的 blk_read_time/blk_write_time 在 PG17 改名为 shared_blk_read_time/shared_blk_write_time。在 17/18 上执行本文 SQL 前请按上述映射替换列名。
下一步:检查点密集→评估 max_wal_size/checkpoint_timeout/innodb_io_capacity([变更],须权衡恢复时间目标);日志顺序写贴设备上限→拆分批量写入或提升规格;日志量本身异常→“binlog/WAL 异常增长或保留”场景(存储与日志故障);不得以关闭持久化换性能。
4.3.4 磁盘类型与规格确认
目的:确认当前云盘类型、容量与 IOPS/吞吐上限是否匹配工作负载,并确认数据库侧的存储假设参数与实际硬件一致。
云控制台方法(厂商中立)[只读]:核对云盘类型(SSD/ESSD/高效云盘等)、容量、基准与突发 IOPS/吞吐上限、是否按容量线性给性能、突发额度模型、是否与其他实例共享;核对数据、日志、临时空间是否同盘。
MySQL 8.0 [只读]
SHOW VARIABLES WHERE Variable_name IN
('innodb_io_capacity','innodb_io_capacity_max','innodb_flush_neighbors',
'innodb_page_size','innodb_read_io_threads','innodb_write_io_threads','innodb_use_native_aio');
- PostgreSQL 14+ [只读]
SELECT name, setting, unit FROM pg_settings
WHERE name IN ('random_page_cost','seq_page_cost','effective_io_concurrency',
'maintenance_io_concurrency','effective_cache_size','block_size');
SELECT pg_size_pretty(sum(pg_database_size(datname))) AS all_db_size FROM pg_database;
关键判断字段:innodb_io_capacity/effective_io_concurrency/random_page_cost 是否与实际盘型相符(SSD 上沿用机械盘假设会让优化器与刷盘节奏失真);innodb_flush_neighbors 在 SSD 上通常不必要;数据库总大小与云盘容量、性能上限的关系。
下一步:参数与盘型不符→按 [变更] 流程校准并观察计划变化;容量决定性能且已贴顶→扩容或更换盘型([变更],评估成本与迁移窗口);数据/日志/临时同盘互相干扰→评估分盘或分层布局;规格合理仍瓶颈→回到“慢 I/O 相关 SQL 定位”做 SQL 侧治理。
4.4 Agent 诊断提示词
把下面整段复制给 STAROps 数字员工,替换全部占位符后提交。模板是自包含的:候选原因、需要 DBA 执行的只读语句都已写在模板内。
任务:定位"I/O 性能异常"场景(性能类故障)的根因,给出可执行处置建议,并保留完整证据链。
【输入补充】
磁盘类型与规格:<VALUE>(含标称 IOPS 与吞吐上限)
【前置检查补充】
0.2 需确认的日志:慢日志与实例错误日志。
0.7 磁盘标称 IOPS 与吞吐上限是否已确认;未确认则无法判断是否触顶。
指标 Key(MySQL,已核实可直接用于 DescribeDBInstancePerformance 的 Key 参数):
MySQL_IOPS —— 实例每秒 IO 请求数(个/秒)
MySQL_MBPS —— 实例读写吞吐(Byte/秒)
MySQL_InnoDBDataReadWriten —— 每秒数据读写量(KB)
MySQL_InnoDBLogWrites —— 每秒日志写请求、物理写与 fsync 完成次数(个/秒)
【数据源(本场景取值)】状态与降级规则按契约执行
云监控 2.0 / 托管 Prometheus:IOPS、吞吐、磁盘延迟、队列深度、磁盘使用率、(若暴露)突发额度。
CMS2_WORKSPACE 路由:starops observe entity metric-data 或 metric_set query(PromQL)。
ALIYUN_RDS 路由:aliyun rds DescribeDBInstancePerformance 按 Key 拉序列。
SLS(<SLS_PROJECT> 下对应 Logstore):错误日志中的 checkpoint 警告与 IO 等待相关记录;慢
日志中的高扫描量指纹。
未投递到 SLS 时改用 OpenAPI:慢日志 DescribeSlowLogs(统计)与
DescribeSlowLogRecords(明细)、错误日志 DescribeErrorLogs。
系统事件与告警:备份、批量导入、扩容、索引重建、规格变更。
CMS2_WORKSPACE 路由:starops observe alerts query + changes query +
acm_basic event system-query。
ALIYUN_RDS 路由:aliyun rds DescribeEvents 查历史事件。
云平台 OpenAPI:磁盘类型规格与标称上限、参数组当前值。
常用接口:DescribeDBInstanceAttribute(实例详情)、DescribeParameters(参数当前值)。
降级兜底:磁盘标称上限与突发额度需从实例规格获取;拿不到上限时只能
给出相对基线的偏离,不得断言触顶。
需 DBA 执行并粘贴:IO 计数与等待、redo 或 WAL 写入量、checkpoint 频率。
【采集步骤】
A. Agent 自取(逐项回报数据源、取值、采集时间)
1) 取 IOPS、吞吐、延迟、队列深度曲线,与标称上限和基线比对,确认是否触顶或额度耗尽。
2) 查事件:备份、批量导入、扩容、索引重建的执行窗口。
3) 查错误日志中的 checkpoint 警告与 IO 相关记录。
4) 从 ARMS 确认应用侧耗时抬升与 IO 抬升是否同步发生。
B. 需 DBA 执行只读语句后粘贴原始输出(Agent 无权限;语句已给全,按引擎选用)
1) 引擎侧 IO 计数:
MySQL:SHOW GLOBAL STATUS WHERE Variable_name IN ('Innodb_data_reads',
'Innodb_data_writes','Innodb_os_log_written',
'Innodb_buffer_pool_wait_free','Innodb_row_lock_waits');
PostgreSQL:SHOW track_io_timing; -- 未开启则无 blk_read_time(开启属 [变更])
SELECT blks_read, blks_hit, temp_bytes FROM pg_stat_database
WHERE datname = current_database();
2) 日志写与检查点:
MySQL:SHOW VARIABLES LIKE 'innodb_redo_log_capacity'; -- 8.0.30+
SHOW ENGINE INNODB STATUS; -- 取 LOG 段的写入与 checkpoint 位点
PostgreSQL:SELECT * FROM pg_stat_bgwriter;
-- PostgreSQL 17 起 checkpoint 相关列移至 pg_stat_checkpointer
SELECT pg_size_pretty(sum(size)) FROM pg_ls_waldir(); -- 需相应权限
【候选原因与判定补充】
- 大量随机写入
- 日志刷盘成为瓶颈
- 磁盘规格不足或突发额度耗尽
- 数据文件碎片化
触顶判定必须引用规格标称上限,不得用经验阈值。
区分数据库放大 IO(可优化)与底层存储受限(需扩容或转托管侧);
若同时磁盘将满,先按磁盘空间方向处置。
4.5 解决方案
错峰或暂停可取消的批任务,优化高 IO SQL,平滑写入,必要时提升存储规格/容量。检查点、刷脏、日志和存储规格调整是 [变更],需确认恢复时间目标、持久性、成本和回滚;不得以关闭持久化换性能。
4.6 验证与预防
验证 SLO、设备时延/队列、查询物理读、临时 IO 和日志写回归基线,并覆盖一次检查点周期。建立存储性能预算、突发额度告警、批任务编排和变更前后 IO 对比。
三、锁与并发故障
1. 锁等待
1.1 现象描述
SQL 长时间等待、请求超时、吞吐下降;等待会话增加,但 CPU 可能不高。应区分行锁、表锁、元数据锁、关系锁和轻量级内部等待。
1.2 常见原因
1.2.1 事务未及时提交
判断依据:会话处于 idle in transaction(PostgreSQL)或 MySQL 中存在 trx_state='RUNNING' 但无当前 SQL 的事务;事务年龄远大于业务预期;连接池归还了带未结束事务的连接。
验证方法:按“阻塞源(持锁会话)定位”找到根阻塞者并检查其状态与年龄;核对应用是否在异常路径漏掉提交/回滚。
处置指向:应用层用 try/finally 保证提交或回滚;设置与业务匹配的空闲事务超时([变更],需灰度);详见“长事务”场景。
1.2.2 长事务持有锁
判断依据:单个事务长时间持有排他锁并阻塞大量会话;伴随 undo 历史增长、死元组堆积或复制延迟。
验证方法:结合“锁类型与持有时间分析”的锁模式与“长事务”场景的“事务对系统的影响评估(undo 膨胀、主从延迟等)”的系统影响评估;确认事务是否仍在正常推进。
处置指向:优先等待或让应用主动结束事务;拆分长批处理为小事务;强制终止属 [高风险],需评估回滚时间与 IO 峰值。
1.2.3 批量更新范围过大
判断依据:单条 DML 的 trx_rows_locked/rows 极大;锁定范围覆盖大量记录或整段索引区间;批任务与在线业务时间重叠。
验证方法:查看阻塞事务的语句与影响行数;用 EXPLAIN 确认谓词扫描范围。
处置指向:按主键有序分批、每批提交、控制批大小与速率;为批任务安排低峰窗口并支持断点续跑。
1.2.4 缺少索引导致锁范围扩大
判断依据:UPDATE/DELETE 的谓词无可用索引,导致扫描并锁定远超目标的记录(MySQL 中还可能产生额外间隙锁);LOCK_DATA 显示的键范围远大于业务意图。
验证方法:对 DML 谓词做 EXPLAIN,核对访问路径与预计扫描行数;检查索引是否因类型转换而失效(“慢查询”场景的“索引失效”)。
处置指向:为 DML 谓词补充合适索引([变更],评估锁、空间、写放大与复制延迟);同时改写谓词以缩小锁范围。
1.3 排查步骤
1.3.1 锁等待队列查看
目的:先取得“谁在等、等多久、等什么对象”的全局快照,确定影响面与紧急度。
MySQL 8.0 [只读]
SELECT * FROM sys.innodb_lock_waits ORDER BY wait_age_secs DESC LIMIT 50;
SELECT REQUESTING_ENGINE_TRANSACTION_ID, BLOCKING_ENGINE_TRANSACTION_ID,
REQUESTING_THREAD_ID, BLOCKING_THREAD_ID
FROM performance_schema.data_lock_waits;
SHOW GLOBAL STATUS WHERE Variable_name IN
('Innodb_row_lock_current_waits','Innodb_row_lock_time_avg','Innodb_row_lock_time_max','Table_locks_waited');
- PostgreSQL 14+ [只读]
SELECT a.pid, a.usename, a.application_name, a.state,
a.wait_event_type, a.wait_event,
now()-a.query_start AS wait_age, now()-a.xact_start AS xact_age,
pg_blocking_pids(a.pid) AS blockers, left(a.query,120) AS q
FROM pg_stat_activity a
WHERE cardinality(pg_blocking_pids(a.pid)) > 0
ORDER BY a.xact_start LIMIT 50;
关键判断字段:等待会话数量与 wait_age_secs/wait_age 分布;Innodb_row_lock_current_waits 与 Innodb_row_lock_time_max;等待是否集中在单一对象/单一阻塞者(说明有明确根因)还是弥散(说明整体过载)。锁数据瞬时变化,应记录采集时间并做多次短采样。
下一步:存在明确阻塞者→“阻塞源(持锁会话)定位”;等待弥散且无长阻塞者→检查整体负载(性能类故障一章);出现循环依赖或数据库已自动回滚→“死锁”场景;等待对象为元数据/DDL→“锁类型与持有时间分析”。
1.3.2 阻塞源(持锁会话)定位
目的:沿等待链找到根阻塞者(自身不等待任何人),避免误杀中间的受害会话。
MySQL 8.0 [只读]
SELECT waiting_pid, waiting_query, blocking_pid, blocking_query,
wait_age_secs, locked_table, locked_index, locked_type
FROM sys.innodb_lock_waits ORDER BY wait_age_secs DESC;
SELECT trx_id, trx_mysql_thread_id, trx_state, trx_started,
trx_rows_locked, trx_rows_modified, trx_isolation_level, trx_query
FROM information_schema.innodb_trx ORDER BY trx_started LIMIT 20;
- PostgreSQL 14+ [只读]
WITH RECURSIVE chain AS (
SELECT pid, unnest(pg_blocking_pids(pid)) AS blocker, 1 AS depth
FROM pg_stat_activity WHERE cardinality(pg_blocking_pids(pid)) > 0
UNION ALL
SELECT c.blocker, unnest(pg_blocking_pids(c.blocker)), c.depth+1
FROM chain c
-- depth 必须用于收敛:等待成环(死锁前兆)时否则会无界递归
WHERE cardinality(pg_blocking_pids(c.blocker)) > 0 AND c.depth < 10
)
SELECT DISTINCT c.blocker AS root_candidate, a.usename, a.state,
now()-a.xact_start AS xact_age, left(a.query,120) AS q
FROM chain c JOIN pg_stat_activity a ON a.pid = c.blocker
WHERE cardinality(pg_blocking_pids(c.blocker)) = 0;
关键判断字段:根阻塞者的 trx_state/state(RUNNING 且有 SQL、还是空闲事务)、事务年龄、已修改行数、阻塞链扇出(被它挡住多少会话)、所属应用与客户端来源。
下一步:根阻塞者仍在正常推进→等待或限流新流量;根阻塞者为空闲事务→“长事务”场景并联系应用所有者;根阻塞者为 DDL→“锁类型与持有时间分析”;需要强制解除→按本场景“解决方案”的 [高风险] 前置条件评估。
1.3.3 锁类型与持有时间分析
目的:判断锁的粒度与模式(行锁/间隙锁/表锁/元数据锁/关系锁),因为不同锁类型的解法与影响面完全不同。
MySQL 8.0 [只读]
SELECT ENGINE_TRANSACTION_ID, THREAD_ID, OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME,
LOCK_TYPE, LOCK_MODE, LOCK_STATUS, LOCK_DATA
FROM performance_schema.data_locks
ORDER BY OBJECT_SCHEMA, OBJECT_NAME LIMIT 100;
SELECT OBJECT_TYPE, OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_STATUS, OWNER_THREAD_ID
FROM performance_schema.metadata_locks
WHERE LOCK_STATUS IN ('PENDING','GRANTED') ORDER BY LOCK_STATUS;
- PostgreSQL 14+ [只读]
SELECT l.pid, l.locktype, l.mode, l.granted,
COALESCE(l.relation::regclass::text, l.locktype) AS object,
now()-a.xact_start AS xact_age, a.state, left(a.query,100) AS q
FROM pg_locks l JOIN pg_stat_activity a ON a.pid = l.pid
WHERE NOT l.granted OR l.mode LIKE 'Access%Exclusive%'
ORDER BY l.granted, xact_age DESC NULLS LAST LIMIT 100;
关键判断字段:MySQL LOCK_TYPE(RECORD/TABLE)、LOCK_MODE(X/S/X,GAP/IX)、LOCK_STATUS(WAITING/GRANTED)与 LOCK_DATA 指向的键范围;metadata_locks 中 PENDING 的 DDL;PostgreSQL locktype(relation/transactionid/tuple/advisory)、mode(AccessExclusiveLock 会阻塞读)与 granted=false 的等待项。
下一步:间隙锁/范围锁过大→检查索引与谓词选择性(“慢查询”场景(性能类故障));元数据锁/AccessExclusiveLock 挂起→取消 DDL 或安排窗口;锁持有时间长→“长事务”场景;确认锁语义正常但并发高→本场景“解决方案”的批次与顺序治理。
1.3.4 相关 SQL 与事务追溯
目的:把锁现场还原为“哪段业务代码、哪个事务、哪些语句”,形成可修复的结论而不仅是止损。
MySQL 8.0 [只读]
SELECT t.THREAD_ID, t.PROCESSLIST_ID, t.PROCESSLIST_USER, t.PROCESSLIST_HOST,
t.PROCESSLIST_DB, t.PROCESSLIST_TIME, t.PROCESSLIST_STATE
FROM performance_schema.threads t WHERE t.PROCESSLIST_ID = <PID>;
SELECT EVENT_ID, SQL_TEXT, TIMER_WAIT, ROWS_AFFECTED, ROWS_EXAMINED, ERRORS
FROM performance_schema.events_statements_history
WHERE THREAD_ID = (SELECT THREAD_ID FROM performance_schema.threads WHERE PROCESSLIST_ID = <PID>)
ORDER BY EVENT_ID DESC LIMIT 20;
- PostgreSQL 14+ [只读]
SELECT pid, usename, application_name, client_addr, backend_start,
xact_start, query_start, state_change, state,
wait_event_type, wait_event, backend_xid, backend_xmin, query
FROM pg_stat_activity WHERE pid = <PID>;
SELECT queryid, calls, mean_exec_time, rows, query
FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 20;
关键判断字段:events_statements_history 展示的事务内语句序列(需相应 consumer 已启用);application_name、client_addr 指向的服务与代码路径;backend_xid/backend_xmin 反映事务可见性影响;语句序列中对象的访问顺序是死锁与热点分析的关键证据。
下一步:定位到代码路径→按本场景“解决方案”缩短事务、统一访问顺序、拆分批次;事务包含外部调用/人工等待→“长事务”场景;同一批对象被多路径反序访问→“死锁”场景;证据不足→在审批下短时增强日志采样并复现。
1.4 Agent 诊断提示词
把下面整段复制给 STAROps 数字员工,替换全部占位符后提交。模板是自包含的:候选原因、需要 DBA 执行的只读语句都已写在模板内。
任务:定位"锁等待"场景(锁与并发故障)的根因,给出可执行处置建议,并保留完整证据链。
【输入补充】
受影响对象:<TABLE>;是否伴随应用超时重试:是 / 否
【前置检查补充】
0.2 需确认的日志:实例错误日志(含锁等待超时记录)。
0.7 锁链路证据只能由 DBA 在阻塞持续期间采集;先确认有人可随时执行。
指标 Key(MySQL,已核实可直接用于 DescribeDBInstancePerformance 的 Key 参数):
MySQL_ROW_LOCK —— 行锁最大等待时间、平均等待时间(毫秒)与等待次数
MySQL_ThreadStatus —— 活跃线程数与线程连接数(个)
【数据源(本场景取值)】状态与降级规则按契约执行
云监控 2.0 / 托管 Prometheus:活跃会话数、QPS 下跌幅度、(若暴露)等待类会话数。
CMS2_WORKSPACE 路由:starops observe entity metric-data 或 metric_set query(PromQL)。
ALIYUN_RDS 路由:aliyun rds DescribeDBInstancePerformance 按 Key 拉序列。
SLS(<SLS_PROJECT> 下对应 Logstore):错误日志中的锁等待超时与语句超时记录,按指纹与时间聚合。
未投递到 SLS 时改用 OpenAPI:慢日志 DescribeSlowLogs(统计)与
DescribeSlowLogRecords(明细)、错误日志 DescribeErrorLogs。
系统事件与告警:DDL 发布、批量任务、发版。
CMS2_WORKSPACE 路由:starops observe alerts query + changes query +
acm_basic event system-query。
ALIYUN_RDS 路由:aliyun rds DescribeEvents 查历史事件。
云平台 OpenAPI:锁与超时相关参数当前值。
常用接口:DescribeDBInstanceAttribute(实例详情)、DescribeParameters(参数当前值)。
降级兜底:锁等待的对象与阻塞链只能在阻塞持续期间由 DBA 采集:
错过窗口就标注为不可得,并给出下次复现时的采集清单,不要事后用指标猜测。
需 DBA 执行并粘贴:等待队列与阻塞源、锁类型与持有时长、双方事务的 SQL 与开始时间。
【采集步骤】
A. Agent 自取(逐项回报数据源、取值、采集时间)
1) 取活跃会话与 QPS 曲线,定位阻塞开始与恢复的时间点。
2) 查错误日志的锁等待超时与语句超时计数,按语句指纹与时间分布聚合。
3) 从 ARMS 找被阻塞的接口与 SQL 指纹,估算影响面。
4) 查事件:窗口内是否有 DDL、批量任务或发版。
B. 需 DBA 执行只读语句后粘贴原始输出(Agent 无权限;语句已给全,按引擎选用)
1) 等待队列与阻塞源(必须在阻塞持续期间执行):
MySQL:SELECT * FROM sys.innodb_lock_waits;
SELECT * FROM performance_schema.data_lock_waits;
PostgreSQL:SELECT pid, pg_blocking_pids(pid) AS blocked_by, wait_event_type,
wait_event, xact_start, left(query,120) AS q
FROM pg_stat_activity
WHERE cardinality(pg_blocking_pids(pid)) > 0;
2) 锁类型、对象与持有时长:
MySQL:SELECT trx_id, trx_started, trx_state, trx_rows_locked, trx_query
FROM information_schema.innodb_trx ORDER BY trx_started;
SELECT * FROM performance_schema.metadata_locks; -- 元数据锁 / DDL 排队
PostgreSQL:SELECT locktype, relation::regclass, mode, granted, pid
FROM pg_locks WHERE NOT granted;
-- log_lock_waits 只记录超过 deadlock_timeout 的等待,日志空不等于无等待
【候选原因与判定补充】
- 事务未及时提交
- 长事务持有锁
- 批量更新范围过大
- 缺少索引导致锁范围扩大
阻塞源与等待者必须由 DBA 输出区分,Agent 不得按指标猜测谁在持锁。
阻塞源为长事务时改按长事务方向处置;终止会话属 [变更] 或 [高风险],只输出建议。
1.5 解决方案
优先让根事务正常结束、暂停新流量、拆小批次并统一对象访问顺序。KILL <PID>、pg_cancel_backend(<PID>)、pg_terminate_backend(<PID>) 是 [高风险]:先确认根阻塞者而非误杀等待者,评估回滚时间、数据一致性和应用重试;先取消语句,再在必要时终止会话。建索引须遵守“慢查询”场景的“解决方案”的风险要求。
1.6 验证与预防
确认阻塞链消失、等待时长和业务延迟恢复,且回滚完成、无复制积压。配置与 SLO 匹配的锁/语句/空闲事务超时;应用事务短小、固定访问顺序;对 DDL 使用变更平台和超时保护。
2. 死锁
2.1 现象描述
数据库检测到循环等待并主动回滚一个事务;MySQL 常报 Deadlock found when trying to get lock,PostgreSQL 报 deadlock detected。死锁是并发设计问题,不是简单“把超时调大”可解决。
2.2 常见原因
2.2.1 事务加锁顺序不一致
判断依据:死锁图显示两个事务以相反顺序请求同一组对象/记录;不同代码路径(如“先更新订单再更新库存”与“先更新库存再更新订单”)并发执行;批量更新未按稳定键排序。
验证方法:按“死锁涉及的事务与 SQL 还原”还原两侧事务的加锁序列;检查批量语句是否有确定性的 ORDER BY 或按主键分批。
处置指向:在设计与代码评审层面统一全局对象访问顺序;批量操作按主键有序分批;对可安全重试的事务实施有界指数退避。
2.2.2 并发更新同一批数据
判断依据:热点行/热点区间被高并发更新(计数器、库存、状态机、队列表);死锁与锁等待同时增长;同一指纹的调用量在故障窗口显著上升。
验证方法:统计热点对象的更新频率与冲突次数;观察并发度与死锁计数的相关性。
处置指向:降低热点冲突(分片计数、队列化串行处理、乐观并发控制加重试);缩短事务持有时间;必要时在应用层排队与限流。
2.2.3 索引缺失导致锁范围扩大
判断依据:DML 谓词无可用索引,扫描并锁定大量记录(MySQL 中还可能产生间隙锁),使原本不相交的事务产生交集;LOCK_DATA 显示锁定范围远超目标行。
验证方法:对涉及的 DML 做 EXPLAIN,核对访问路径与锁定范围;检查是否存在隐式类型转换导致索引失效。
处置指向:补充或修正索引使锁精确到目标行([变更],评估锁、空间、写放大与复制延迟);同时缩小谓词范围与批次大小。
2.3 排查步骤
2.3.1 死锁日志/错误信息提取
目的:取得完整死锁图原文(参与事务、锁、对象、受害者),这是唯一可靠的还原依据。
云控制台/日志方法(厂商中立)[只读]:从平台日志服务导出数据库错误日志中的死锁段落,记录 UTC 时间;MySQL 的 SHOW ENGINE INNODB STATUS 仅保留最近一次死锁,需及时保存。
MySQL 8.0 [只读]
SHOW ENGINE INNODB STATUS;
-- Innodb_deadlocks 不是上游 Oracle MySQL 的状态变量(属 MariaDB/Percona),在 MySQL 8.0 上查询返回空集;
-- 死锁计数改用 innodb_metrics 的 lock_deadlocks
SELECT NAME, COUNT, STATUS FROM information_schema.innodb_metrics WHERE NAME='lock_deadlocks';
SHOW VARIABLES WHERE Variable_name IN ('innodb_print_all_deadlocks','innodb_lock_wait_timeout','innodb_deadlock_detect');
- PostgreSQL 14+ [只读]
SELECT datname, deadlocks, stats_reset FROM pg_stat_database WHERE datname='<DB>';
SELECT name, setting FROM pg_settings
WHERE name IN ('deadlock_timeout','log_lock_waits','log_min_error_statement','lock_timeout');
关键判断字段:information_schema.innodb_metrics 中 lock_deadlocks 的 COUNT 增量与 pg_stat_database.deadlocks 的增量(偶发一次还是持续增长);死锁图中的事务编号、等待与持有的锁模式、涉及对象与索引、被回滚的受害事务;innodb_deadlock_detect 是否开启(关闭后表现为锁等待超时而非死锁)。
注意:lock_deadlocks 的 STATUS 若为 disabled,COUNT 不会累加,需先 SET GLOBAL innodb_monitor_enable='lock_deadlocks'(属 [变更]);启用后计数自启用或上次重置起算,因此不能与历史绝对值直接比较,只能看启用后的增量。作为替代或补充,可开启 innodb_print_all_deadlocks 把每次死锁完整写入错误日志(属 [变更],会增加日志量,应限时并设自动到期)。
注意:不要高频执行 SHOW ENGINE INNODB STATUS,其输出很大且在高负载实例上会加重压力;innodb_print_all_deadlocks、log_lock_waits 的开启属 [变更],应限时并设自动到期。log_lock_waits 只记录等待时间超过 deadlock_timeout 的锁等待(默认 1s),短于该值的等待不会留下日志,因此“日志里没有锁等待”不等于没有发生锁等待;需要更细粒度时应配合 pg_stat_activity/pg_locks 采样,而不是把 deadlock_timeout 无依据调小(调小会增加死锁检测开销)。
下一步:拿到死锁图→“死锁涉及的事务与 SQL 还原”;日志被截断或平台不暴露→按审批短时增强日志并在预发复现;死锁计数持续增长→按本场景“解决方案”优先做并发设计修复。
2.3.2 死锁涉及的事务与 SQL 还原
目的:把死锁图中的事务映射回具体 SQL 指纹、表/索引与业务代码路径,确认每个事务的加锁序列。
MySQL 8.0 [只读]
SELECT DIGEST_TEXT, COUNT_STAR, SUM_ROWS_AFFECTED, SUM_ROWS_EXAMINED,
SUM_ERRORS, SUM_LOCK_TIME, FIRST_SEEN, LAST_SEEN
FROM performance_schema.events_statements_summary_by_digest
WHERE DIGEST_TEXT LIKE '%<TABLE>%'
ORDER BY SUM_LOCK_TIME DESC LIMIT 20;
EXPLAIN FORMAT=JSON UPDATE <SCHEMA>.<TABLE> SET <COLUMN>=<VALUE> WHERE <COLUMN>=<VALUE>;
-- 亦可用传统 EXPLAIN,或分析等价 SELECT;FORMAT=TREE 对单表 UPDATE/DELETE 在 8.0 不可靠
EXPLAIN UPDATE <SCHEMA>.<TABLE> SET <COLUMN>=<VALUE> WHERE <COLUMN>=<VALUE>;
- PostgreSQL 14+ [只读]
SELECT queryid, calls, rows, mean_exec_time, query
FROM pg_stat_statements
WHERE query ILIKE '%<TABLE>%'
ORDER BY calls DESC LIMIT 20;
EXPLAIN (COSTS, VERBOSE)
UPDATE <SCHEMA>.<TABLE> SET <COLUMN>=<VALUE> WHERE <COLUMN>=<VALUE>;
关键判断字段:两个事务各自锁定的对象与索引、加锁先后顺序、谓词实际扫描/锁定范围、是否存在外键检查、触发器或唯一约束引入的隐式访问;SUM_LOCK_TIME 指向锁成本高的指纹。
注意:普通 EXPLAIN(含 FORMAT=JSON)不执行 DML;禁止在生产对 DML 直接加 ANALYZE(风险见“慢查询”场景的“执行计划分析(EXPLAIN)”的高风险提示),且 MySQL 8.0 的 EXPLAIN ANALYZE 本身只支持 SELECT、TABLE 与多表 UPDATE/DELETE。分析单表 UPDATE/DELETE 时不要用 FORMAT=TREE(8.0 下不可靠),改用 FORMAT=JSON、传统 EXPLAIN 或等价 SELECT。
下一步:两事务加锁顺序相反→“事务加锁顺序不一致”;锁定范围明显超出业务意图→“索引缺失导致锁范围扩大”;隐式锁来自约束/触发器→评估约束与触发器设计;顺序一致但仍死锁→“锁等待链路分析”。
2.3.3 锁等待链路分析
目的:还原循环等待的完整链路,并判断当前是否仍有同类等待环在形成(死锁往往是锁等待问题的极端表现)。
MySQL 8.0 [只读]
SELECT w.REQUESTING_ENGINE_TRANSACTION_ID AS req_trx,
w.BLOCKING_ENGINE_TRANSACTION_ID AS blk_trx,
lr.OBJECT_SCHEMA, lr.OBJECT_NAME, lr.INDEX_NAME,
lr.LOCK_TYPE, lr.LOCK_MODE, lr.LOCK_STATUS, lr.LOCK_DATA
FROM performance_schema.data_lock_waits w
JOIN performance_schema.data_locks lr
ON lr.ENGINE_LOCK_ID = w.REQUESTING_ENGINE_LOCK_ID;
SELECT * FROM sys.innodb_lock_waits ORDER BY wait_age_secs DESC LIMIT 50;
- PostgreSQL 14+ [只读]
SELECT a.pid, pg_blocking_pids(a.pid) AS blockers,
a.wait_event_type, a.wait_event, now()-a.xact_start AS xact_age,
l.locktype, l.mode, l.granted, l.relation::regclass AS object
FROM pg_stat_activity a
LEFT JOIN pg_locks l ON l.pid = a.pid AND NOT l.granted
WHERE cardinality(pg_blocking_pids(a.pid)) > 0
ORDER BY xact_age DESC LIMIT 50;
关键判断字段:等待边的方向(A 等 B 的哪个对象、B 等 A 的哪个对象)是否构成环;同一对象上并发排他请求的数量;LOCK_DATA 与 locktype/mode 指示的粒度是行、间隙还是关系级;同类等待是否仍在持续出现。
下一步:仍在形成等待环→先按“锁等待”场景止损限流;环涉及两张表的反序访问→统一访问顺序;环由范围锁引起→优化索引与批次;已无等待环但需修复历史死锁→“应用逻辑回溯”。
2.3.4 应用逻辑回溯
目的:确认业务代码中形成反序加锁的路径、事务边界与重试逻辑,给出代码级修复与安全重试策略。
应用侧方法(厂商中立)[只读]:按 application_name、客户端来源、SQL 指纹反查代码路径与发布版本;核对 ORM 的隐式事务边界、批量保存顺序、缓存回写与消息消费并发度;确认重试是否幂等且有界。
MySQL 8.0 [只读]
SELECT PROCESSLIST_ID, PROCESSLIST_USER, PROCESSLIST_HOST, PROCESSLIST_DB,
PROCESSLIST_STATE, PROCESSLIST_TIME
FROM performance_schema.threads WHERE TYPE='FOREGROUND'
ORDER BY PROCESSLIST_TIME DESC LIMIT 30;
-- events_statements_history_long 的 consumer 默认关闭(events_statements_history 默认开启),
-- 未启用时下面这条查询返回空集。先确认状态:
-- SELECT NAME, ENABLED FROM performance_schema.setup_consumers WHERE NAME='events_statements_history_long';
-- 需要时启用(属 [变更],占用额外内存、应限时并设自动到期):
-- UPDATE performance_schema.setup_consumers SET ENABLED='YES' WHERE NAME='events_statements_history_long';
SELECT EVENT_ID, SQL_TEXT, ERRORS, ROWS_AFFECTED
FROM performance_schema.events_statements_history_long
WHERE ERRORS > 0 ORDER BY EVENT_ID DESC LIMIT 30;
- PostgreSQL 14+ [只读]
SELECT application_name, client_addr, count(*) AS sessions,
count(*) FILTER (WHERE state='idle in transaction') AS idle_in_xact
FROM pg_stat_activity GROUP BY application_name, client_addr
ORDER BY sessions DESC LIMIT 30;
SELECT datname, xact_commit, xact_rollback, deadlocks
FROM pg_stat_database WHERE datname='<DB>';
关键判断字段:application_name/客户端来源对应的服务与版本;xact_rollback 相对 xact_commit 的比例(回滚多说明重试或失败频繁);idle in transaction 会话说明事务边界过宽;错误语句历史中是否有重复失败的同一指纹(读取 events_statements_history_long 前需确认其 consumer 已启用,默认关闭,启用属 [变更]);发布时间与死锁起始时间的关系。
下一步:确认反序路径→“事务加锁顺序不一致”并纳入代码评审;事务边界过宽→缩短事务、移出事务内的外部调用;重试不幂等→改造为幂等并使用有界指数退避;无法归因→在预发用并发测试复现并保留死锁图。
2.4 Agent 诊断提示词
把下面整段复制给 STAROps 数字员工,替换全部占位符后提交。模板是自包含的:候选原因、需要 DBA 执行的只读语句都已写在模板内。
任务:定位"死锁"场景(锁与并发故障)的根因,给出可执行处置建议,并保留完整证据链。
【输入补充】
发生频率:<VALUE>(次数 / 时间段);集中的接口或批处理:<VALUE>
【前置检查补充】
0.2 需确认的日志:实例错误日志。
0.7 innodb_print_all_deadlocks 是否开启(用 OpenAPI 读参数);未开启则死锁图可能不全。
指标 Key(MySQL,已核实可直接用于 DescribeDBInstancePerformance 的 Key 参数):
MySQL_ROW_LOCK —— 行锁等待时间与等待次数(间接侧证)
死锁次数没有对应的性能 Key:以错误日志与 innodb_metrics 的 lock_deadlocks 为准。
【数据源(本场景取值)】状态与降级规则按契约执行
云监控 2.0 / 托管 Prometheus:(若暴露)死锁计数指标。
CMS2_WORKSPACE 路由:starops observe entity metric-data 或 metric_set query(PromQL)。
ALIYUN_RDS 路由:aliyun rds DescribeDBInstancePerformance 按 Key 拉序列。
SLS(<SLS_PROJECT> 下对应 Logstore):错误日志中的死锁记录:PostgreSQL 的 deadlock
detected 与 DETAIL、MySQL 死锁条目。
未投递到 SLS 时改用 OpenAPI:慢日志 DescribeSlowLogs(统计)与
DescribeSlowLogRecords(明细)、错误日志 DescribeErrorLogs。
系统事件与告警:发版、批量任务上线时间。
CMS2_WORKSPACE 路由:starops observe alerts query + changes query +
acm_basic event system-query。
ALIYUN_RDS 路由:aliyun rds DescribeEvents 查历史事件。
云平台 OpenAPI:innodb_print_all_deadlocks、deadlock_timeout 等参数当前值。
常用接口:DescribeDBInstanceAttribute(实例详情)、DescribeParameters(参数当前值)。
降级兜底:innodb_print_all_deadlocks 未开启时日志只保留最近一次死锁:
此时频率结论标注为下限值,不得当作完整计数。
需 DBA 执行并粘贴:最近死锁图、死锁累计计数、两侧事务的 SQL 与索引定义。
【采集步骤】
A. Agent 自取(逐项回报数据源、取值、采集时间)
1) 从错误日志提取死锁记录,按时间、接口与对象聚合频率。
2) 从 ARMS 取受影响接口的错误率与重试次数,评估业务影响。
3) 查参数:innodb_print_all_deadlocks 是否开启(未开启则日志可能不全,开启属 [变更])。
4) 查事件:死锁起始时间是否与发版或批任务对齐。
B. 需 DBA 执行只读语句后粘贴原始输出(Agent 无权限;语句已给全,按引擎选用)
1) 死锁图与计数:
MySQL:SHOW ENGINE INNODB STATUS; -- 取 LATEST DETECTED DEADLOCK 段
SELECT name, count FROM information_schema.innodb_metrics
WHERE name = 'lock_deadlocks';
-- 状态变量 Innodb_deadlocks 仅 MariaDB 与 Percona 提供,官方 MySQL 没有
PostgreSQL:从错误日志导出 deadlock detected 及其 DETAIL 段(含双方进程与语句)
2) 加锁顺序还原:
提供两侧事务的完整语句序列,并补 SHOW CREATE TABLE <TABLE>;(MySQL)
或 \d+ <TABLE>(PostgreSQL psql)以确认索引与约束
【候选原因与判定补充】
- 事务加锁顺序不一致
- 并发更新同一批数据
- 索引缺失导致锁范围扩大
死锁被自动回滚是正常保护机制,评估重点是频率与业务影响,不是把数量降到零。
建议须落到应用改造(统一加锁顺序、缩短事务、幂等重试),仅调参数通常不解决根因。
2.5 解决方案
统一锁顺序,缩短事务并按主键稳定排序分批;补充必要索引;应用只对可安全重试的事务做有限次指数退避。修改索引/约束为 [变更],需评估锁、空间和复制。不要关闭死锁检测或仅增大超时来掩盖根因——关闭检测会把死锁变成长时间锁等待,影响面更大。
2.6 验证与预防
用并发测试复现原场景并确认死锁计数不再增长、重试无重复副作用。代码评审纳入事务顺序和幂等性;按 SQL 指纹监控死锁频率,并保留数据库日志中的死锁图。
3. 长事务
3.1 现象描述
事务持续时间远超业务基线,可能阻塞 DDL/更新、占用连接、扩大 undo/WAL、阻碍垃圾回收并增加故障恢复时间;PostgreSQL 还可能出现 idle in transaction。
3.2 常见原因
3.2.1 应用未提交/回滚
判断依据:会话处于 idle in transaction 或 MySQL 中事务无当前 SQL;等待事件指向客户端;连接池归还了带未结束事务的连接;异常分支缺少收尾逻辑。
验证方法:按“事务内 SQL 逐条分析”确认事务在等客户端;核对应用异常路径与 ORM 的事务边界;检查连接池归还时是否回滚。
处置指向:代码层用 try/finally 强制提交或回滚;设置 idle_in_transaction_session_timeout 等与业务匹配的超时([变更],需灰度);连接归还前重置事务状态。
3.2.2 批量操作未拆分
判断依据:单个事务修改行数极大、运行时间与数据量成正比;ETL/清理/迁移任务一次性提交;undo/WAL 与锁等待随任务进度同步增长。
验证方法:查看事务的 trx_rows_modified/影响行数与任务日志进度;核对任务的批大小与提交频率配置。
处置指向:按主键有序分批、每批提交并支持断点续跑;控制批大小与速率;把批任务安排到低峰窗口并与备份/维护错峰。
3.2.3 事务内包含外部调用或人工等待
判断依据:事务打开后长时间无 SQL,等待事件指向客户端;事务跨越 HTTP/RPC 调用、消息发送、文件处理或人工审批;应用侧已超时但数据库事务仍存在。
验证方法:结合“事务内 SQL 逐条分析”的等待事件与应用链路追踪,定位事务边界内的外部调用。
处置指向:把外部调用移出事务边界,采用“先本地事务后异步补偿”或 Saga 模式;设置分层的语句与事务超时;应用超时后必须显式回滚,不能只丢弃连接。
3.3 排查步骤
3.3.1 活跃事务列表查看
目的:取得当前所有未结束事务的清单与状态,区分空闲事务与仍在推进的事务。
MySQL 8.0 [只读]
SELECT trx_id, trx_mysql_thread_id, trx_state, trx_started, trx_requested_lock_id,
trx_rows_locked, trx_rows_modified, trx_isolation_level, trx_query
FROM information_schema.innodb_trx ORDER BY trx_started LIMIT 50;
SELECT trx_state, COUNT(*) AS trx_count FROM information_schema.innodb_trx GROUP BY trx_state;
- PostgreSQL 14+ [只读]
SELECT pid, usename, application_name, client_addr, state,
xact_start, query_start, state_change,
backend_xid, backend_xmin, wait_event_type, wait_event, left(query,120) AS q
FROM pg_stat_activity
WHERE xact_start IS NOT NULL AND pid <> pg_backend_pid()
ORDER BY xact_start LIMIT 50;
SELECT count(*) FILTER (WHERE state='idle in transaction') AS idle_in_xact,
count(*) FILTER (WHERE state='idle in transaction (aborted)') AS idle_aborted
FROM pg_stat_activity;
关键判断字段:trx_started/xact_start 最早的事务;trx_state(RUNNING/LOCK WAIT)与 PostgreSQL state(active/idle in transaction);trx_rows_modified/backend_xid 是否表示已有实际写入;应用与客户端来源。“长”以业务基线判断,不使用统一分钟阈值。
下一步:空闲事务→“事务内 SQL 逐条分析”并联系应用所有者;仍在推进的批处理→“事务执行时长排序”估算完成时间;阻塞他人→“锁等待”场景;已有大量修改→“事务对系统的影响评估(undo 膨胀、主从延迟等)”先估算回滚成本。
3.3.2 事务执行时长排序
目的:按事务年龄排序,量化最老事务造成的“保留窗口”,并为处置排优先级。
MySQL 8.0 [只读]
SELECT trx_id, trx_mysql_thread_id, trx_state,
TIMESTAMPDIFF(SECOND, trx_started, NOW()) AS xact_age_s,
trx_rows_locked, trx_rows_modified, LEFT(trx_query, 120) AS q
FROM information_schema.innodb_trx
ORDER BY trx_started ASC LIMIT 20;
- PostgreSQL 14+ [只读]
SELECT pid, state,
now()-xact_start AS xact_age,
now()-query_start AS query_age,
now()-state_change AS in_state,
application_name, left(query,120) AS q
FROM pg_stat_activity
WHERE xact_start IS NOT NULL
ORDER BY xact_start ASC LIMIT 20;
SELECT max(now()-xact_start) AS oldest_xact_age
FROM pg_stat_activity WHERE xact_start IS NOT NULL;
关键判断字段:最老事务年龄与业务基线/SLO 的比值;query_age 与 xact_age 的差值(差值大说明事务在空闲等待);in_state 停留时长;是否有一批事务同时变老(指向共同的外部依赖或批任务)。
下一步:仍在可接受范围→设置告警并观察;显著超基线→“事务对系统的影响评估(undo 膨胀、主从延迟等)”评估影响后按本场景“解决方案”处置;一批事务同时变老→检查上游依赖、外部调用超时与连接池归还逻辑。
3.3.3 事务内 SQL 逐条分析
目的:还原事务内已执行的语句序列,判断事务是卡在外部等待、已完成大部分工作,还是可安全取消。
MySQL 8.0 [只读]
SELECT t.THREAD_ID, t.PROCESSLIST_ID, t.PROCESSLIST_STATE, t.PROCESSLIST_TIME
FROM performance_schema.threads t WHERE t.PROCESSLIST_ID = <PID>;
SELECT EVENT_ID, SQL_TEXT, TIMER_WAIT, LOCK_TIME, ROWS_AFFECTED, ROWS_EXAMINED, ERRORS
FROM performance_schema.events_statements_history
WHERE THREAD_ID = (SELECT THREAD_ID FROM performance_schema.threads WHERE PROCESSLIST_ID = <PID>)
ORDER BY EVENT_ID DESC LIMIT 30;
- PostgreSQL 14+ [只读]
SELECT pid, state, xact_start, query_start, state_change,
wait_event_type, wait_event, backend_xid, backend_xmin, query
FROM pg_stat_activity WHERE pid = <PID>;
SELECT locktype, mode, granted, relation::regclass AS object
FROM pg_locks WHERE pid = <PID> ORDER BY granted;
关键判断字段:语句序列中的写操作数量与影响行数(决定回滚成本);是否处于 wait_event_type='Client'(等应用发下一条语句,典型空闲事务);已持有的锁清单与模式;ERRORS 或 idle in transaction (aborted) 表明事务已进入失败态,只需回滚。
注意:语句文本可能含敏感参数,现场记录使用脱敏摘要;events_statements_history 需相应 consumer 已启用。
下一步:等待客户端且无写入→可较安全地取消(仍需通知所有者);已大量写入→先按“事务对系统的影响评估(undo 膨胀、主从延迟等)”估算回滚成本;处于失败态→请应用回滚;仍在推进→等待完成或按本场景“解决方案”拆批治理。
3.3.4 事务对系统的影响评估(undo 膨胀、主从延迟等)
目的:量化长事务对版本保留、清理能力、日志空间与复制的影响,作为“继续等待还是强制终止”的决策依据。
MySQL 8.0 [只读]
SELECT NAME, COUNT, STATUS FROM information_schema.innodb_metrics
WHERE NAME IN ('trx_rseg_history_len','lock_row_lock_current_waits');
SHOW GLOBAL STATUS WHERE Variable_name IN
('Innodb_os_log_written','Innodb_buffer_pool_pages_dirty','Innodb_row_lock_current_waits');
-- SHOW REPLICA STATUS 为 8.0.22+;更早小版本用 SHOW SLAVE STATUS
SHOW REPLICA STATUS FOR CHANNEL '<CHANNEL>';
- PostgreSQL 14+ [只读]
SELECT datname, age(datfrozenxid) AS xid_age FROM pg_database ORDER BY 2 DESC;
SELECT relname, n_live_tup, n_dead_tup, last_autovacuum, last_autoanalyze
FROM pg_stat_user_tables ORDER BY n_dead_tup DESC LIMIT 20;
SELECT slot_name, active, wal_status,
pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) AS retained_bytes,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained
FROM pg_replication_slots
-- 必须按数值排序:pg_size_pretty 是文本,字典序会把 9 MB 排在 10 GB 之前;restart_lsn 可为 NULL
ORDER BY pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) DESC NULLS LAST;
-- wal_status 的 unreserved/lost 仅在 max_slot_wal_keep_size 非负时才可能出现;该参数默认 -1,此时只会是 reserved/extended
SELECT application_name, state, replay_lsn,
pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS byte_lag
FROM pg_stat_replication;
关键判断字段:trx_rseg_history_len 的增长趋势(undo 历史长度);n_dead_tup 与 last_autovacuum(清理是否被阻塞);age(datfrozenxid) 反映的事务 ID 年龄风险;binlog/WAL 增长与槽保留字节;复制 byte_lag 是否同步扩大。
下一步:版本保留/undo 持续增长→尽快让根事务结束;日志逼近容量→同时执行“磁盘空间不足”场景(存储与日志故障)与“binlog/WAL 异常增长或保留”场景;清理被阻塞→结束长事务后确认 autovacuum 追平;复制延迟扩大→“主从/流复制延迟”场景。
3.4 Agent 诊断提示词
把下面整段复制给 STAROps 数字员工,替换全部占位符后提交。模板是自包含的:候选原因、需要 DBA 执行的只读语句都已写在模板内。
任务:定位"长事务"场景(锁与并发故障)的根因,给出可执行处置建议,并保留完整证据链。
【输入补充】
最长事务时长:<VALUE>;是否已影响清理或复制:是 / 否
【前置检查补充】
0.2 需确认的日志:实例错误日志。
0.7 两个事务超时参数的当前值是否可读;活跃事务列表必须由 DBA 提供。
指标 Key(MySQL,已核实可直接用于 DescribeDBInstancePerformance 的 Key 参数):
MySQL_ROW_LOCK —— 行锁等待时间与等待次数(毫秒 / 个)
MySQL_ReplicationDelay —— 备库复制延迟(秒)
MySQL_DetailedSpaceUsage —— 总空间、数据、日志、临时、系统空间(MB)
【数据源(本场景取值)】状态与降级规则按契约执行
云监控 2.0 / 托管 Prometheus:活跃会话数、复制延迟、磁盘使用率与其增速。
CMS2_WORKSPACE 路由:starops observe entity metric-data 或 metric_set query(PromQL)。
ALIYUN_RDS 路由:aliyun rds DescribeDBInstancePerformance 按 Key 拉序列。
SLS(<SLS_PROJECT> 下对应 Logstore):错误日志中的事务中空闲超时、语句取消或会话终止记录。
未投递到 SLS 时改用 OpenAPI:慢日志 DescribeSlowLogs(统计)与
DescribeSlowLogRecords(明细)、错误日志 DescribeErrorLogs。
系统事件与告警:批量任务、发版时间表。
CMS2_WORKSPACE 路由:starops observe alerts query + changes query +
acm_basic event system-query。
ALIYUN_RDS 路由:aliyun rds DescribeEvents 查历史事件。
云平台 OpenAPI:idle_in_transaction_session_timeout、statement_timeout 等参数当前值。
常用接口:DescribeDBInstanceAttribute(实例详情)、DescribeParameters(参数当前值)。
降级兜底:活跃事务列表无法从平台侧取得:DBA 未配合时,长事务的存在与
时长标注为不可得,只能用连带现象(延迟、空间增速)做间接推断并说明。
需 DBA 执行并粘贴:按时长排序的活跃事务、事务内已执行语句、清理与复制受阻证据。
【采集步骤】
A. Agent 自取(逐项回报数据源、取值、采集时间)
1) 取复制延迟、磁盘使用率与活跃会话曲线,判断长事务的连带影响是否已出现。
2) 查参数:两个超时参数是否设置,未设置说明长事务缺少兜底。
3) 从 ARMS 找事务型接口的长耗时样本与其中的外部调用等待。
4) 查事件与批任务时间表,定位可疑批处理。
B. 需 DBA 执行只读语句后粘贴原始输出(Agent 无权限;语句已给全,按引擎选用)
1) 活跃事务与时长排序:
MySQL:SELECT trx_id, trx_started,
TIMESTAMPDIFF(SECOND, trx_started, NOW()) AS age_s,
trx_state, trx_rows_locked, trx_query
FROM information_schema.innodb_trx ORDER BY trx_started;
PostgreSQL:SELECT pid, usename, application_name, state, xact_start,
now() - xact_start AS age, left(query,120) AS q
FROM pg_stat_activity WHERE xact_start IS NOT NULL
ORDER BY xact_start;
2) 连带影响(清理受阻、槽保留、两阶段事务残留):
PostgreSQL:SELECT backend_xmin FROM pg_stat_activity
WHERE backend_xmin IS NOT NULL ORDER BY age(backend_xmin) DESC LIMIT 5;
SELECT * FROM pg_prepared_xacts;
SELECT slot_name, active, wal_status, restart_lsn
FROM pg_replication_slots;
MySQL:SELECT * FROM information_schema.innodb_metrics
WHERE name LIKE 'trx_rseg%' OR name LIKE '%undo%';
【候选原因与判定补充】
- 应用未提交或未回滚
- 批量操作未拆分
- 事务内包含外部调用或人工等待
把后果写成链路:持锁到阻塞、阻塞清理到膨胀、保留日志到空间风险,
指明当前处在哪一环。
终止长事务属 [变更] 甚至 [高风险],必须先确认事务内容、回滚代价与业务确认人。
3.5 解决方案
优先让应用提交/回滚,暂停制造新长事务的任务。终止会话是 [高风险]:大事务回滚可能比继续完成更久并制造 IO 峰值;必须评估日志空间、回滚进度、锁影响和应用幂等性。长期应拆批、缩短事务边界,并设置与业务匹配的事务/空闲事务超时;改超时是 [变更],需灰度。
3.6 验证与预防
确认最老事务年龄、undo/WAL 增速、锁等待和清理能力恢复;持续观察回滚完成。监控事务年龄分位数和 idle in transaction,在代码层强制 try/finally 提交/回滚,批任务支持断点和小事务。
4. 主从/流复制延迟
4.1 现象描述
只读节点数据陈旧、读后写不一致,复制延迟增长或回放停止。单一“秒级延迟”指标可能失真,应分解发送、接收、落盘、回放和应用位点。
4.2 常见原因
4.2.1 大事务或批量写入
判断依据:单事务修改行数极大或 Binlog_cache_disk_use 非零;延迟阶跃式上升并在事务提交后集中回放;批任务、DDL、数据迁移与延迟起点吻合。
验证方法:按“主库写入压力分析”定位最大事务与日志生成速率;核对批任务时间表与发布记录。
处置指向:拆分为小事务并按主键有序分批、限速执行、错峰安排;大 DDL 前估算日志量与延迟影响。
4.2.2 从库规格不足
判断依据:从库 CPU/IO/内存饱和而主库正常;回放长期落后但无错误;从库同时承担大量只读查询。
验证方法:对比主从资源曲线与规格;检查从库上的只读查询负载与回放争用。
处置指向:提升从库规格或增加只读节点分担查询([变更]);把重查询移到专用只读实例;必要时临时把关键读路由回主库。
4.2.3 单线程回放瓶颈
判断依据:MySQL 仅个别 applier worker 在推进、并行 worker 数过小或提交顺序约束限制并行;写入集中在单表/单主键区间;PostgreSQL 单一回放进程且 replay_backlog 持续增长。
验证方法:按“从库回放速度分析”查看 worker 状态与参数;分析写入在表/键上的分布是否高度集中。
处置指向:评估并行复制参数与分组提交([变更],须满足一致性要求);从数据模型上分散热点;降低单表写入集中度。
4.2.4 网络带宽或抖动
判断依据:在途字节数大而回放差距小;网络流出带宽贴住上限;RTT/丢包/重传上升;跨地域链路事件与延迟起点吻合。
验证方法:按“网络延迟排查”对照带宽、RTT、重传与心跳连续性。
处置指向:启用传输/日志压缩、限流非关键写入、提升带宽规格([变更]);跨地域复制按 RPO 要求重新设计拓扑。
4.3 排查步骤
4.3.1 复制状态与延迟量查看
目的:先确认复制通道是否健康、有无错误,并用位点/字节差而不是只看秒级延迟来量化落后程度。
MySQL 8.0 [只读]
-- SHOW REPLICA STATUS 为 8.0.22+;更早小版本用 SHOW SLAVE STATUS
SHOW REPLICA STATUS FOR CHANNEL '<CHANNEL>';
SELECT CHANNEL_NAME, SERVICE_STATE, LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE, LAST_ERROR_TIMESTAMP
FROM performance_schema.replication_applier_status_by_worker;
SELECT CHANNEL_NAME, SERVICE_STATE, LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE
FROM performance_schema.replication_connection_status;
- PostgreSQL 14+ [只读]
SELECT application_name, client_addr, state, sync_state,
sent_lsn, write_lsn, flush_lsn, replay_lsn,
pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS byte_lag,
write_lag, flush_lag, replay_lag
FROM pg_stat_replication;
-- 以下在备库执行。注意:pg_stat_wal_receiver 在 walreceiver 未运行时返回 0 行,
-- 若把回放信息与它写在同一条查询里,接收中断时回放信息会一起消失,故拆成两条。
SELECT status, latest_end_lsn, latest_end_time, sender_host, sender_port
FROM pg_stat_wal_receiver;
SELECT pg_last_xact_replay_timestamp() AS last_replay_ts,
now()-pg_last_xact_replay_timestamp() AS replay_delay;
关键判断字段:MySQL Replica_IO_Running/Replica_SQL_Running、Seconds_Behind_Source(空闲期可能失真)、Retrieved_Gtid_Set 与 Executed_Gtid_Set 的差、Last_Error*;PostgreSQL 分阶段 LSN(sent→write→flush→replay)与 byte_lag、*_lag 时间列、sync_state。
版本注记:SHOW REPLICA STATUS、Replica_IO_Running、Replica_SQL_Running、Seconds_Behind_Source 均为 MySQL 8.0.22+ 的新名称;8.0.22 之前请用旧名 SHOW SLAVE STATUS、Slave_IO_Running、Slave_SQL_Running、Seconds_Behind_Master(旧名在 8.0.22+ 仍可用但已弃用)。PostgreSQL 侧 pg_stat_wal_receiver 在 walreceiver 未运行时返回 0 行,空结果本身就是“接收已停止”的证据,不要据此认为回放信息缺失。
下一步:接收停止→“网络延迟排查”与“网络连通性故障”场景(连接类故障);回放停止且有错误→修复数据/DDL 冲突([变更/高风险],须保证一致性);持续推进但落后→“主库写入压力分析”、“从库回放速度分析”;指标为 NULL/空闲→结合角色与写入量判断。
4.3.2 主库写入压力分析
目的:判断延迟是否由主库日志生成速率超过从库消化能力引起,并定位产生大量日志的写入源。
MySQL 8.0 [只读]
-- SHOW MASTER STATUS 在 8.2.0 弃用、8.4.0 移除;小版本为 8.4+ 时改用 SHOW BINARY LOG STATUS
SHOW MASTER STATUS;
SHOW BINARY LOGS;
SHOW GLOBAL STATUS WHERE Variable_name IN
('Com_insert','Com_update','Com_delete','Innodb_rows_inserted','Innodb_rows_updated',
'Innodb_rows_deleted','Innodb_os_log_written','Binlog_cache_use','Binlog_cache_disk_use');
SELECT trx_id, trx_started, trx_rows_modified, LEFT(trx_query,120) AS q
FROM information_schema.innodb_trx ORDER BY trx_rows_modified DESC LIMIT 10;
- PostgreSQL 14+ [只读]
SELECT pg_current_wal_lsn() AS lsn, now() AS sampled_at;
SELECT datname, xact_commit, tup_inserted, tup_updated, tup_deleted
FROM pg_stat_database WHERE datname='<DB>';
SELECT queryid, calls, rows, shared_blks_dirtied, shared_blks_written, query
FROM pg_stat_statements ORDER BY shared_blks_dirtied DESC LIMIT 20;
关键判断字段:用两次采样的 binlog 文件大小或 pg_current_wal_lsn() 差值算出日志生成速率(字节/秒);Binlog_cache_disk_use 非零说明大事务超出缓存;单事务修改行数最大的事务;写入速率是否与延迟增长同步。
下一步:日志速率突增且与批任务/发布吻合→限流、拆批、错峰(应用侧优先);存在超大事务→“长事务”场景;主库写入正常→“从库回放速度分析”;日志总量本身异常→“binlog/WAL 异常增长或保留”场景(存储与日志故障)。
4.3.3 从库回放速度分析
目的:判断从库是否为消化瓶颈:并行度不足、单表热点、规格不足,或从库上的长查询阻碍回放。
MySQL 8.0 [只读]
SELECT CHANNEL_NAME, WORKER_ID, SERVICE_STATE,
LAST_APPLIED_TRANSACTION, APPLYING_TRANSACTION,
APPLYING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP,
LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE
FROM performance_schema.replication_applier_status_by_worker;
-- replica_parallel_workers / replica_parallel_type / replica_preserve_commit_order 为 8.0.26+ 名称;
-- 8.0.26 之前用旧名 slave_parallel_workers / slave_parallel_type / slave_preserve_commit_order
SHOW VARIABLES WHERE Variable_name IN
('replica_parallel_workers','replica_parallel_type','replica_preserve_commit_order');
SELECT COUNT(*) AS long_reads FROM information_schema.processlist
WHERE COMMAND='Query' AND TIME > 60;
- PostgreSQL 14+ [只读]
-- 以下在备库执行
SELECT pg_is_in_recovery() AS in_recovery,
pg_last_wal_receive_lsn() AS received,
pg_last_wal_replay_lsn() AS replayed,
pg_wal_lsn_diff(pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn()) AS replay_backlog,
pg_last_xact_replay_timestamp() AS last_replay_ts;
SELECT name, setting FROM pg_settings
WHERE name IN ('hot_standby_feedback','max_standby_streaming_delay','recovery_min_apply_delay','wal_receiver_timeout');
SELECT pid, now()-query_start AS age, wait_event_type, wait_event, left(query,100) AS q
FROM pg_stat_activity WHERE state='active' ORDER BY query_start LIMIT 20;
关键判断字段:MySQL 是否只有个别 worker 在推进(单线程热点)、APPLYING_TRANSACTION 是否长期不变、并行复制参数;PostgreSQL received 与 replayed 的差(replay_backlog 大说明已落盘但回放慢)、max_standby_streaming_delay 与备库长查询的冲突、从库 CPU/IO 是否饱和。
注意:跳过事务、放宽错误处理、recovery_min_apply_delay 等设置会影响数据一致性,任何调整属 [变更/高风险]。
下一步:从库资源饱和→扩容或下移读流量([变更]);单线程/热点表限制并行→评估并行复制参数与表设计;备库长查询冲突→治理只读查询或调整冲突策略;接收侧异常→“网络延迟排查”。
4.3.4 网络延迟排查
目的:确认主从之间链路的带宽、时延与稳定性是否足以承载日志速率,排除跨可用区/跨地域链路问题。
OS/云控制台方法(厂商中立)[只读]:查看实例网络流出带宽是否贴住规格上限、跨可用区/跨地域链路时延与丢包、专线/对等连接状态;有主机权限时用 ping/mtr 观察 RTT 与丢包,用 ss -ti 观察重传。
# [只读] 观察主从之间的 RTT、丢包与 TCP 重传
mtr -r -c 20 <HOST>
ss -ti state established "( dport = :<PORT> )" | head -40
- MySQL 8.0 [只读]
-- HOST/PORT 属于 replication_connection_configuration,replication_connection_status 没有这两列,
-- 需按 CHANNEL_NAME 关联两表
SELECT c.CHANNEL_NAME, c.HOST, c.PORT,
s.SERVICE_STATE, s.SOURCE_UUID,
s.LAST_HEARTBEAT_TIMESTAMP, s.COUNT_RECEIVED_HEARTBEATS
FROM performance_schema.replication_connection_configuration c
JOIN performance_schema.replication_connection_status s USING (CHANNEL_NAME);
-- replica_net_timeout 为 8.0.26+(旧名 slave_net_timeout);binlog_transaction_compression 为 8.0.20+
SHOW VARIABLES WHERE Variable_name IN ('replica_net_timeout','binlog_transaction_compression');
- PostgreSQL 14+ [只读]
SELECT application_name, client_addr, state, sync_state,
write_lag, flush_lag, replay_lag,
pg_wal_lsn_diff(sent_lsn, write_lsn) AS in_flight_bytes
FROM pg_stat_replication;
SELECT name, setting FROM pg_settings
WHERE name IN ('wal_receiver_timeout','wal_sender_timeout','wal_compression','tcp_keepalives_idle');
关键判断字段:RTT 与重传率相对基线的变化;网络流出带宽是否贴住实例上限(贴顶即限流);MySQL 心跳是否连续、LAST_HEARTBEAT_TIMESTAMP 是否停滞;PostgreSQL sent_lsn 与 write_lsn 的在途字节数大而回放差距小,说明链路是瓶颈。
下一步:带宽贴顶→限流写入、启用日志/传输压缩([变更],需评估 CPU 开销)或提升规格;链路抖动/丢包→网络负责人排查 MTU、NAT、拥塞(“网络连通性故障”场景(连接类故障));心跳停滞→检查认证、防火墙与超时参数;网络正常→回到“主库写入压力分析”、“从库回放速度分析”。
4.4 Agent 诊断提示词
把下面整段复制给 STAROps 数字员工,替换全部占位符后提交。模板是自包含的:候选原因、需要 DBA 执行的只读语句都已写在模板内。
任务:定位"主从/流复制延迟"场景(锁与并发故障)的根因,给出可执行处置建议,并保留完整证据链。
【输入补充】
拓扑:<VALUE>(主备、一主多从、跨地域);只读流量是否走从库:是 / 否
【前置检查补充】
0.2 需确认的日志:实例错误日志。
0.7 复制延迟指标是否覆盖所有备库与只读实例;缺失的节点单独列出。
CMS2_WORKSPACE 路由下用 starops observe entity search 枚举同一主库下的只读实例。
指标 Key(MySQL,已核实可直接用于 DescribeDBInstancePerformance 的 Key 参数):
MySQL_ReplicationDelay —— 备库复制延迟(秒)
slavestat —— 只读实例延迟(秒)
MySQL_ReplicationThread —— IO 与 SQL 复制线程状态(1 正常,0 线程丢失)
MySQL_QPSTPS —— 主库每秒执行与事务数,用于判断写入压力(个/秒)
【数据源(本场景取值)】状态与降级规则按契约执行
云监控 2.0 / 托管 Prometheus:复制延迟(秒与字节)、主库写入量、备库 CPU 与 IO、网络流量。
CMS2_WORKSPACE 路由:starops observe entity metric-data 或 metric_set query(PromQL)。
ALIYUN_RDS 路由:aliyun rds DescribeDBInstancePerformance 按 Key 拉序列。
SLS(<SLS_PROJECT> 下对应 Logstore):错误日志中的复制中断、回放错误、心跳超时记录。
未投递到 SLS 时改用 OpenAPI:慢日志 DescribeSlowLogs(统计)与
DescribeSlowLogRecords(明细)、错误日志 DescribeErrorLogs。
系统事件与告警:主备切换、维护、规格变更。
CMS2_WORKSPACE 路由:starops observe alerts query + changes query +
acm_basic event system-query。
ALIYUN_RDS 路由:aliyun rds DescribeEvents 查历史事件。
云平台 OpenAPI:只读实例清单与延迟、端点权重、复制相关参数当前值。
常用接口:DescribeDBInstanceAttribute(实例详情)、DescribeParameters(参数当前值)。
UModel 拓扑:哪些应用在读从库或只读端点,用于界定摘除端点的影响面。
降级兜底:跨地域或自建备库可能不在同一监控视图内:缺失节点逐个列出
并标注不可得,不要用已覆盖节点的延迟代表全局。
需 DBA 执行并粘贴:复制线程与位点状态、并行回放参数、备库长查询冲突情况。
【采集步骤】
A. Agent 自取(逐项回报数据源、取值、采集时间)
1) 取复制延迟曲线与主库写入量、备库 CPU 与 IO 叠加,初判是接收慢、回放慢还是资源不足。
2) 查事件:切换、维护、规格变更的时间点。
3) 查错误日志中的复制中断与回放错误。
4) 从 OpenAPI 取只读实例延迟与端点权重,结合 UModel 列出正在读从库的应用。
B. 需 DBA 执行只读语句后粘贴原始输出(Agent 无权限;语句已给全,按引擎选用)
1) 复制状态与延迟量:
MySQL(备库):SHOW REPLICA STATUS; -- 8.0.22+;更早版本用 SHOW SLAVE STATUS
关注 Replica_IO_Running、Replica_SQL_Running、Seconds_Behind_Source、
Retrieved_Gtid_Set 与 Executed_Gtid_Set 的差值、Last_Error
PostgreSQL(主库):SELECT application_name, state, sent_lsn, write_lsn,
flush_lsn, replay_lsn, write_lag, flush_lag, replay_lag FROM pg_stat_replication;
PostgreSQL(备库):SELECT pg_is_in_recovery(), pg_last_xact_replay_timestamp(),
now() - pg_last_xact_replay_timestamp() AS replay_delay;
2) 回放能力与冲突:
MySQL:SHOW VARIABLES WHERE Variable_name IN ('replica_parallel_workers',
'replica_parallel_type','replica_preserve_commit_order');
-- 8.0.26+ 为新名,更早版本用 slave_* 旧名
PostgreSQL(备库):SELECT count(*) FROM pg_stat_activity WHERE state='active';
SHOW hot_standby_feedback; SHOW max_standby_streaming_delay;
【候选原因与判定补充】
- 大事务或批量写入
- 从库规格不足
- 单线程回放成为瓶颈
- 网络带宽不足或链路抖动
延迟期间从库读的一致性风险必须显式说明;摘除只读端点或调权重属 [变更]。
若延迟由复制槽或消费停滞引起,改按 binlog/WAL 保留方向处置消费侧。
4.5 解决方案
暂停非关键批写、拆小事务、修复复制错误、提升从库资源;按业务一致性要求将关键读临时路由主库。改并行复制、同步级别、故障切换或重建副本为 [变更/高风险],必须确认 RPO/RTO、数据完整性、容量和回切方案。不得仅清除错误或跳过事务继续复制而不验证数据一致性。
4.6 验证与预防
确认位点持续推进、字节/时间延迟回归业务 SLO,主从抽样或校验工具无差异,读路由恢复前完成一致性验证。监控复制各阶段、日志生成速率和槽保留;大变更前估算日志量,定期演练故障切换与重建。
四、存储与日志故障
1. 磁盘空间不足
1.1 现象描述
可用空间快速下降,写入失败、实例进入只读/保护状态、日志或临时文件无法扩展,备份/DDL 失败。云平台可能在达到保护线前自动扩容或限制操作。
1.2 常见原因
1.2.1 业务数据自然增长
判断依据:数据与索引空间随业务量平稳增长,无异常阶跃;表行数与业务指标同步;缺少分区与归档设计。
验证方法:对照业务量指标与表增长速率;检查是否存在历史数据保留策略。
处置指向:建立分区/归档/保留策略与容量规划;按增长外推提前扩容,避免每次都在告警时被动处理。
1.2.2 日志文件未清理
判断依据:binlog/WAL 文件数量或文本日志目录持续增大;SHOW BINARY LOGS 累积很多文件;pg_ls_waldir() 文件数远超配置预期;归档失败或过期策略未生效。
验证方法:按“日志文件过大”场景的“日志清理策略检查”与“binlog/WAL 异常增长或保留”场景的“binlog/WAL 生成与清理状态检查”检查保留与清理策略、归档状态、复制槽保留。
处置指向:修复归档/复制消费者并使用数据库支持的机制清理;严禁手工删除 MySQL redo/binlog/undo 文件或 PostgreSQL pg_wal 文件。
1.2.3 临时文件/排序文件堆积
判断依据:Created_tmp_disk_tables、temp_files/temp_bytes 在故障窗口激增;空间随大查询运行涨落;临时空间与数据同盘导致互相挤压。
验证方法:定位产生临时对象的 SQL 指纹(“慢查询”场景的“慢查询日志定位与提取”、“日志文件过大”场景的“日志生成速率分析”);确认临时目录位置与容量。
处置指向:优化排序/分组/连接以消除落盘、限制并发、控制单查询工作内存;必要时把临时空间与数据分离([变更])。
1.2.4 无归档与保留策略
判断依据:表中存在远超业务需要的历史数据;无分区、无冷热分层、无归档任务;备份与日志保留期限未与合规要求对齐。
验证方法:核对数据保留要求与实际最早数据时间;检查是否存在已停用但未清理的表与索引。
处置指向:制定并落地保留/归档策略与分区方案([变更],需合规确认);注意删除数据未必立即归还文件系统空间,需配合重整或分区裁剪。
1.3 排查步骤
1.3.1 磁盘使用率趋势分析
目的:确认剩余空间、增长形态(阶跃/持续/周期)与自动扩容上限,估算“还剩多久”。
云控制台/OS 方法(厂商中立)[只读]:查看实例存储使用率曲线、自动扩容配置与上限、配额与保护线策略、最近的 DDL/备份/导入事件;有主机权限时用 df -h、du -sh <PATH>/* 查看文件系统与目录占用。
MySQL 8.0 [只读]
-- data_length/data_free 取自数据字典缓存,information_schema_stats_expiry 默认 86400 秒;
-- 需要实时值(尤其是要做两点差值)时先在本会话关闭缓存,有额外开销
SET SESSION information_schema_stats_expiry = 0;
SELECT ROUND(SUM(data_length+index_length)/1024/1024/1024,2) AS total_gb,
ROUND(SUM(data_free)/1024/1024/1024,2) AS reusable_gb
FROM information_schema.tables;
-- 空间盘点优先用 innodb_tablespaces 的 FILE_SIZE/ALLOCATED_SIZE(字节,来自 InnoDB 自身元数据)
SELECT NAME, FILE_SIZE, ALLOCATED_SIZE, STATE, SPACE_TYPE
FROM information_schema.innodb_tablespaces
ORDER BY FILE_SIZE DESC LIMIT 20;
-- information_schema.files 仅供参考:字节值为近似(TOTAL_EXTENTS 不计文件末尾的部分区),
-- 8.0.21 起查询需 PROCESS 权限,且不包含 redo 与 binlog
SELECT FILE_NAME, TABLESPACE_NAME,
ROUND(TOTAL_EXTENTS*EXTENT_SIZE/1024/1024,2) AS approx_size_mb
FROM information_schema.files LIMIT 20;
- PostgreSQL 14+ [只读]
SELECT datname, pg_size_pretty(pg_database_size(datname)) AS size
FROM pg_database ORDER BY pg_database_size(datname) DESC;
SELECT pg_size_pretty(sum(pg_database_size(datname))) AS all_db_size FROM pg_database;
关键判断字段:数据库对象总量与文件系统占用的差额(差额通常是日志、临时文件、备份与未回收空间);reusable_gb/data_free 表示可复用但未归还的空间;剩余时间按近期增长速率与已计划的变更估算,而不是套用固定百分比阈值。
注意:information_schema.tables 的 data_length/data_free 等动态列受数据字典缓存影响(information_schema_stats_expiry 默认 86400 秒),做差值前必须先 SET SESSION information_schema_stats_expiry = 0 或先 ANALYZE TABLE([变更])。information_schema.files 的字节值仅为近似(TOTAL_EXTENTS 不计文件末尾的部分区),8.0.21 起查询该表需 PROCESS 权限,且不包含 redo 与 binlog;因此空间盘点应改用 information_schema.innodb_tablespaces 的 FILE_SIZE(文件表观大小)与 ALLOCATED_SIZE(实际分配大小),并关注 STATE;redo/binlog 量另按“日志文件过大”场景与“binlog/WAL 异常增长或保留”场景统计。
下一步:日志占主导→“日志文件过大”场景、“binlog/WAL 异常增长或保留”场景;数据占主导→“各类型文件空间占用拆解(数据/日志/临时/索引)”、“大表与大文件识别”;突发阶跃→关联 DDL、批导入、长事务与复制槽;接近保护线→先按本场景“解决方案”扩容止损。
1.3.2 各类型文件空间占用拆解(数据/日志/临时/索引)
目的:把总占用拆成数据、索引、事务日志、文本日志、临时文件、备份等类别,避免对错误的对象做治理。
云控制台/OS 方法(厂商中立)[只读]:查看控制台的空间使用拆解(数据空间/日志空间/临时空间/备份空间);有主机权限时按目录统计(数据目录、日志目录、pg_wal、临时目录)。
MySQL 8.0 [只读]
-- data_length/index_length/data_free 来自数据字典缓存,需要实时值时先关闭本会话缓存(有额外开销)
SET SESSION information_schema_stats_expiry = 0;
SELECT table_schema,
ROUND(SUM(data_length)/1024/1024,2) AS data_mb,
ROUND(SUM(index_length)/1024/1024,2) AS index_mb,
ROUND(SUM(data_free)/1024/1024,2) AS free_mb
FROM information_schema.tables
GROUP BY table_schema ORDER BY (SUM(data_length)+SUM(index_length)) DESC;
SHOW BINARY LOGS;
SHOW GLOBAL STATUS WHERE Variable_name IN ('Created_tmp_disk_tables','Innodb_os_log_written');
-- innodb_redo_log_capacity 为 8.0.30+;更早版本看 innodb_log_file_size × innodb_log_files_in_group
SHOW VARIABLES WHERE Variable_name IN ('innodb_redo_log_capacity','tmpdir');
-- innodb_undo_tablespaces 自 8.0.14 起已弃用且不可配置,不要再当作 undo 容量配置项查看;
-- undo 表空间数量看状态变量,实际文件大小与状态看 innodb_tablespaces(STATE 可为 active/inactive/empty)
SHOW STATUS LIKE 'Innodb_undo_tablespaces%';
SELECT NAME, FILE_SIZE, ALLOCATED_SIZE, STATE, SPACE_TYPE
FROM information_schema.innodb_tablespaces
WHERE SPACE_TYPE = 'Undo' ORDER BY FILE_SIZE DESC;
SHOW VARIABLES WHERE Variable_name IN ('innodb_undo_log_truncate','innodb_max_undo_log_size');
- PostgreSQL 14+ [只读]
SELECT schemaname,
pg_size_pretty(sum(pg_relation_size(relid))) AS heap,
pg_size_pretty(sum(pg_indexes_size(relid))) AS indexes,
pg_size_pretty(sum(pg_total_relation_size(relid))) AS total
FROM pg_stat_user_tables GROUP BY schemaname
ORDER BY sum(pg_total_relation_size(relid)) DESC;
SELECT count(*) AS wal_files, pg_size_pretty(sum(size)) AS wal_size FROM pg_ls_waldir();
SELECT datname, temp_files, pg_size_pretty(temp_bytes) AS temp_bytes
FROM pg_stat_database WHERE datname='<DB>';
关键判断字段:索引占比是否异常高于数据(冗余索引);binlog/WAL 文件数量与总大小;temp_files/temp_bytes 与 Created_tmp_disk_tables 指示的临时空间;redo 容量看 innodb_redo_log_capacity(8.0.30+)或更早版本的 innodb_log_file_size × innodb_log_files_in_group;undo 看 Innodb_undo_tablespaces_* 状态变量与 innodb_tablespaces 中 undo 表空间的 FILE_SIZE/ALLOCATED_SIZE/STATE,能否回缩由 innodb_undo_log_truncate 与 innodb_max_undo_log_size 决定(innodb_undo_tablespaces 自 8.0.14 起弃用且不可配置,不能作为容量判据);free_mb/data_free 表示的碎片空间(受数据字典缓存影响,见上文前提)。
注意:pg_ls_waldir() 需相应权限(通常 pg_monitor);托管实例可能不暴露文件层,此时以控制台拆解为准。
下一步:数据/索引为主→“大表与大文件识别”;WAL/binlog 为主→“binlog/WAL 异常增长或保留”场景;文本日志为主→“日志文件过大”场景;临时文件为主→“内存压力或 OOM”场景(性能类故障)与本章“临时文件/排序文件堆积”。
1.3.3 大表与大文件识别
目的:定位贡献最大的表、索引与大对象,为归档、分区、清理或重建排定顺序。
MySQL 8.0 [只读]
-- table_rows/data_length/data_free 取自数据字典缓存(information_schema_stats_expiry 默认 86400 秒);
-- 需要实时值时先关闭本会话缓存(有额外开销),或先对目标表 ANALYZE TABLE([变更])
SET SESSION information_schema_stats_expiry = 0;
SELECT table_schema, table_name, engine, table_rows,
ROUND(data_length/1024/1024,2) AS data_mb,
ROUND(index_length/1024/1024,2) AS index_mb,
ROUND(data_free/1024/1024,2) AS free_mb
FROM information_schema.tables
WHERE table_type='BASE TABLE'
ORDER BY (data_length+index_length) DESC LIMIT 20;
- PostgreSQL 14+ [只读]
SELECT schemaname, relname,
pg_size_pretty(pg_total_relation_size(relid)) AS total,
pg_size_pretty(pg_relation_size(relid)) AS heap,
pg_size_pretty(pg_indexes_size(relid)) AS indexes,
n_live_tup, n_dead_tup, last_autovacuum
FROM pg_stat_user_tables
ORDER BY pg_total_relation_size(relid) DESC LIMIT 20;
SELECT indexrelname, pg_size_pretty(pg_relation_size(indexrelid)) AS idx_size, idx_scan
FROM pg_stat_user_indexes ORDER BY pg_relation_size(indexrelid) DESC LIMIT 20;
关键判断字段:TOP 表的总大小、数据/索引比例、table_rows/n_live_tup 与业务预期是否相符;n_dead_tup 与 last_autovacuum 指示的膨胀;idx_scan=0 的大索引是候选下线对象(需足够观察周期);行数与死元组均为估算值。
下一步:可归档的历史数据→按合规保留策略归档/分区([变更]);膨胀明显→先解决长事务(“长事务”场景(锁与并发故障))再评估重整;冗余大索引→纳入索引审计后再下线;需量化增速→“空间增长速率评估”。
1.3.4 空间增长速率评估
目的:用两个时间点的差值量化增长速率,估算耗尽时间,并为扩容规模与治理优先级提供依据。
云控制台方法(厂商中立)[只读]:导出存储使用率时间序列,分别对数据空间、日志空间、备份空间做速率与趋势外推;核对自动扩容上限与配额是否足以覆盖预测增长。
MySQL 8.0 [只读]
-- 间隔固定时间执行两次并比较差值;避免高频执行以减少开销
-- 前提(必须):information_schema.tables 的动态列来自数据字典缓存,information_schema_stats_expiry
-- 默认 86400 秒,不关闭缓存时两次采样可能完全相同、差值恒为 0。
-- 每个采样会话都要先执行下面这行(绕过缓存直读存储引擎、有额外开销),
-- 或在两次采样前分别对目标表 ANALYZE TABLE(属 [变更])。
SET SESSION information_schema_stats_expiry = 0;
SELECT NOW() AS sampled_at,
ROUND(SUM(data_length+index_length)/1024/1024,2) AS size_mb
FROM information_schema.tables;
-- 日志类增速不要用 information_schema.tables 推算,改用下面两者的差值
SHOW BINARY LOGS;
SHOW GLOBAL STATUS LIKE 'Innodb_os_log_written';
- PostgreSQL 14+ [只读]
-- 间隔固定时间执行两次并比较差值
SELECT now() AS sampled_at,
pg_database_size('<DB>') AS db_bytes,
pg_current_wal_lsn() AS wal_lsn;
SELECT count(*) AS wal_files, sum(size) AS wal_bytes FROM pg_ls_waldir();
关键判断字段:单位时间的数据字节增量、WAL/binlog 字节增量(用 pg_wal_lsn_diff 或文件大小差)、临时文件峰值;预计耗尽时间 = 剩余空间 ÷ 当前净增速率,并计入已计划的 DDL、导入、备份与保留策略。
注意:MySQL 8.0 用 information_schema.tables 做两点差值算数据增长速率默认不成立——table_rows/data_length/data_free/update_time 来自数据字典缓存,information_schema_stats_expiry 默认 86400 秒,缓存未过期时两次采样可能完全相同、差值恒为 0。必须在每个采样会话先 SET SESSION information_schema_stats_expiry = 0(绕过缓存直读存储引擎,有额外开销),或在采样前对目标表执行 ANALYZE TABLE([变更])。日志类增速不要依赖这些列,应改用 SHOW BINARY LOGS 的文件大小差值或 Innodb_os_log_written 等状态变量差值;PostgreSQL 侧用 pg_current_wal_lsn() 的 pg_wal_lsn_diff 差值。
下一步:耗尽时间紧迫→立即按本场景“解决方案”扩容并暂停高增长任务;日志增速为主因→“binlog/WAL 异常增长或保留”场景;数据增速为主因→归档/分区治理;速率异常且无业务解释→检查“日志文件未清理”、“临时文件/排序文件堆积”与复制槽保留。
1.4 Agent 诊断提示词
把下面整段复制给 STAROps 数字员工,替换全部占位符后提交。模板是自包含的:候选原因、需要 DBA 执行的只读语句都已写在模板内。
任务:定位"磁盘空间不足"场景(存储与日志故障)的根因,给出可执行处置建议,并保留完整证据链。
【输入补充】
当前使用率与剩余空间:<VALUE>;是否已触发实例只读:是 / 否
【前置检查补充】
0.2 需确认的日志:实例错误日志。
0.7 平台是否提供空间分项统计;不提供时表级与文件级占用只能由 DBA 提供。
指标 Key(MySQL,已核实可直接用于 DescribeDBInstancePerformance 的 Key 参数):
MySQL_DetailedSpaceUsage —— 总空间使用、数据空间、日志空间、临时空间、系统空间(MB)
MySQL_IOPS —— 每秒 IO 请求数,用于判断清理或扩容动作带来的 IO 抖动(个/秒)
【数据源(本场景取值)】状态与降级规则按契约执行
云监控 2.0 / 托管 Prometheus:磁盘使用率与增速、(若平台暴露)数据/日志/临时空间分项。
CMS2_WORKSPACE 路由:starops observe entity metric-data 或 metric_set query(PromQL)。
ALIYUN_RDS 路由:aliyun rds DescribeDBInstancePerformance 按 Key 拉序列。
SLS(<SLS_PROJECT> 下对应 Logstore):错误日志中的空间告警、写入失败、只读锁定记录。
未投递到 SLS 时改用 OpenAPI:慢日志 DescribeSlowLogs(统计)与
DescribeSlowLogRecords(明细)、错误日志 DescribeErrorLogs。
系统事件与告警:自动扩容记录、空间告警、锁定只读事件。
CMS2_WORKSPACE 路由:starops observe alerts query + changes query +
acm_basic event system-query。
ALIYUN_RDS 路由:aliyun rds DescribeEvents 查历史事件。
云平台 OpenAPI:磁盘规格与上限、是否支持在线扩容、空间分项统计接口。
常用接口:DescribeDBInstanceAttribute(实例详情)、DescribeParameters(参数当前值)。
降级兜底:平台若不提供空间分项,只能得到总量曲线:此时占用构成标注为
不可得,必须由 DBA 提供表级与文件级明细后才能判定主因。
需 DBA 执行并粘贴:大表与大对象占用、死元组与清理滞后、日志与临时空间占用。
【采集步骤】
A. Agent 自取(逐项回报数据源、取值、采集时间)
1) 取磁盘使用率与增速曲线,按近 7 天斜率外推耗尽时间。
2) 调 OpenAPI 取磁盘规格上限、扩容能力与平台提供的空间分项统计。
3) 查事件:自动扩容记录、空间告警、是否已触发实例只读。
4) 从错误日志取空间相关记录,定位增长阶跃的时间点。
B. 需 DBA 执行只读语句后粘贴原始输出(Agent 无权限;语句已给全,按引擎选用)
1) 大对象占用排名:
MySQL:SET SESSION information_schema_stats_expiry = 0; -- 否则可能取到缓存值
SELECT table_schema, table_name,
ROUND((data_length+index_length)/1024/1024) AS mb
FROM information_schema.tables ORDER BY mb DESC LIMIT 20; -- 估算值
SELECT name, file_size, allocated_size, state
FROM information_schema.innodb_tablespaces ORDER BY file_size DESC LIMIT 20;
PostgreSQL:SELECT relname, pg_size_pretty(pg_total_relation_size(relid)) AS sz
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC LIMIT 20;
2) 膨胀与清理滞后、日志与临时空间:
PostgreSQL:SELECT relname, n_live_tup, n_dead_tup, last_autovacuum
FROM pg_stat_user_tables ORDER BY n_dead_tup DESC LIMIT 20;
SELECT pg_size_pretty(sum(size)) FROM pg_ls_waldir();
MySQL:SHOW BINARY LOGS; -- binlog 总量
SELECT * FROM information_schema.innodb_tablespaces
WHERE name LIKE '%undo%' OR name LIKE '%temp%';
【候选原因与判定补充】
- 业务数据自然增长
- 日志文件未清理
- 临时文件与排序文件堆积
- 缺少归档与保留策略
止血顺序固定:先清可安全回收项,再扩容,最后治根因;
因空间满转只读时优先恢复可写。
清理与扩容分别标注 [变更] 或 [高风险],删数据与收缩表空间属 [高风险]。
1.5 解决方案
最快且最可逆的止损通常是扩容并暂停高增长任务;随后按合规策略归档/删除数据。删除数据未必立即归还文件系统空间。VACUUM FULL <SCHEMA>.<TABLE> 是 [高风险]:需要强锁、额外临时空间并重写表,仅在容量充足、维护窗口、完整备份和回滚计划下执行;优先普通 VACUUM、在线重整能力或逻辑迁移。MySQL 表重建/OPTIMIZE TABLE 同样需评估锁、空间、IO 和复制延迟。
严禁手工删除 MySQL redo/binlog/undo 文件或 PostgreSQL pg_wal 文件。 这可能导致实例无法启动、复制断裂或不可恢复的数据损坏。
1.6 验证与预防
确认写入恢复、剩余空间可覆盖预计增长、备份和维护峰值,且自动扩容上限/配额有效。按数据、索引、日志、临时空间分别监控增长速率和预计耗尽时间;建立分区/归档/保留策略及大 DDL 空间评审。
2. 日志文件过大
2.1 现象描述
错误日志、慢查询日志、审计日志或 PostgreSQL 文本日志增长异常,挤占存储、增加日志采集费用或影响 IO;日志量大不等同于 binlog/WAL 保留,后者见“binlog/WAL 异常增长或保留”场景。
2.2 常见原因
2.2.1 日志级别或开关配置不当
判断依据:general_log、log_statement='all'、log_min_duration_statement=0、log_connections/log_disconnections 或过低的 long_query_time 被临时开启后未关闭;日志量与某次排障时间点吻合。
验证方法:核对参数当前值与 source(是否为动态设置)、变更记录与开启人。
处置指向:按 [变更] 流程恢复基线配置,并为临时诊断开关设置自动到期与责任人;保留已采集样本作为证据。
2.2.2 错误/慢查询风暴
判断依据:同一错误或同一慢 SQL 指纹在短时间内海量重复;伴随连接失败、死锁或超时激增;日志量峰值与故障窗口完全重合。
验证方法:按“日志生成速率分析”做指纹去重统计并定位 TOP 消息;关联对应故障场景。
处置指向:先修复根因(连接、认证、慢查询、锁),日志量随之回落;对重复消息启用采样/去重,不要用关闭日志来“止损”。
2.2.3 日志轮转与保留策略缺失
判断依据:单个日志文件持续增长无轮转;保留天数未设置或过长;归档/上传失败导致本地堆积;多个采集通道重复保存同一份日志。
验证方法:按“日志清理策略检查”检查轮转参数、归档状态与采集代理;核对合规要求的最短保留期。
处置指向:启用合理轮转、压缩与保留([变更],先导出证据再缩短保留);统一采集通道避免重复计费;建立轮转失败与上传失败告警。
2.3 排查步骤
2.3.1 日志文件类型与大小确认(redo/undo/binlog/WAL/error log)
目的:先分清是哪一类日志在膨胀——事务日志(redo/undo/binlog/WAL)与诊断日志(error/slow/general/audit)的治理方式完全不同。
云控制台方法(厂商中立)[只读]:在日志服务中查看各类日志的大小、条数、保留周期与采集规则;托管实例通常不允许直接读取或轮转文件。
MySQL 8.0 [只读]
-- innodb_redo_log_capacity 为 8.0.30+;更早版本 redo 容量由 innodb_log_file_size × innodb_log_files_in_group 决定。
-- innodb_undo_tablespaces 自 8.0.14 起已弃用且不可配置,不再作为 undo 容量配置项,改用下面的状态变量与视图。
SHOW VARIABLES WHERE Variable_name IN
('log_error','log_error_verbosity','slow_query_log','slow_query_log_file','long_query_time',
'log_output','general_log','general_log_file','log_queries_not_using_indexes',
'innodb_redo_log_capacity','innodb_undo_log_truncate','innodb_max_undo_log_size',
'log_bin','binlog_expire_logs_seconds');
SHOW STATUS LIKE 'Innodb_undo_tablespaces%';
SELECT NAME, FILE_SIZE, ALLOCATED_SIZE, STATE, SPACE_TYPE
FROM information_schema.innodb_tablespaces
WHERE SPACE_TYPE = 'Undo' ORDER BY FILE_SIZE DESC;
SHOW BINARY LOGS;
SELECT NAME, COUNT FROM information_schema.innodb_metrics WHERE NAME IN ('trx_rseg_history_len');
- PostgreSQL 14+ [只读]
SELECT name, setting, unit, source FROM pg_settings
WHERE name IN ('logging_collector','log_destination','log_directory','log_filename',
'log_min_messages','log_min_error_statement','log_statement',
'log_min_duration_statement','log_lock_waits','log_checkpoints','log_connections');
SELECT count(*) AS wal_files, pg_size_pretty(sum(size)) AS wal_size FROM pg_ls_waldir();
关键判断字段:诊断开关是否被临时打开后忘记关闭(general_log、log_statement='all'、log_min_duration_statement=0、log_connections);log_error_verbosity/log_min_messages 级别;binlog/WAL 文件数量与大小;redo 容量看 innodb_redo_log_capacity(8.0.30+,更早版本看 innodb_log_file_size × innodb_log_files_in_group);undo 看 Innodb_undo_tablespaces_* 状态变量与 innodb_tablespaces 中 undo 表空间的 FILE_SIZE/ALLOCATED_SIZE/STATE,以及 innodb_undo_log_truncate/innodb_max_undo_log_size 是否允许截断回缩(innodb_undo_tablespaces 自 8.0.14 起弃用且不可配置);trx_rseg_history_len 反映的 undo 历史长度。
下一步:诊断日志为主→“日志生成速率分析”、“日志清理策略检查”;事务日志为主→“binlog/WAL 异常增长或保留”场景;redo/undo 压力大→“长事务”场景(锁与并发故障)与“I/O 性能异常”场景的“日志写入与数据写入分离分析”;空间已告警→“磁盘空间不足”场景先扩容止损。
2.3.2 日志生成速率分析
目的:量化单位时间的日志产生量,并把它归因到连接失败、慢 SQL、锁等待、检查点或错误风暴等具体事件。
云控制台方法(厂商中立)[只读]:用日志服务的写入量/条数曲线定位起始时间点与峰值形态;对同一错误做去重统计,找出高频消息模板。
MySQL 8.0 [只读]
SHOW GLOBAL STATUS WHERE Variable_name IN
('Slow_queries','Aborted_connects','Aborted_clients','Connection_errors_max_connections');
-- 死锁计数用 innodb_metrics:Innodb_deadlocks 属 MariaDB/Percona,MySQL 8.0 无此状态变量(查询返回空集);
-- STATUS 为 disabled 时需先 SET GLOBAL innodb_monitor_enable='lock_deadlocks'(属 [变更]),计数自启用或重置起算
SELECT NAME, COUNT, STATUS FROM information_schema.innodb_metrics WHERE NAME='lock_deadlocks';
SELECT DIGEST_TEXT, COUNT_STAR, SUM_ERRORS, SUM_WARNINGS,
ROUND(SUM_TIMER_WAIT/1e12,3) AS total_s
FROM performance_schema.events_statements_summary_by_digest
ORDER BY (SUM_ERRORS+SUM_WARNINGS) DESC LIMIT 20;
- PostgreSQL 14+ [只读]
SELECT datname, sessions, sessions_abandoned, sessions_fatal, sessions_killed,
deadlocks, temp_files, temp_bytes, stats_reset
FROM pg_stat_database WHERE datname='<DB>';
-- PG14~16:checkpoint 计数在 pg_stat_bgwriter;PG17 起改为
-- SELECT num_timed, num_requested FROM pg_stat_checkpointer;
SELECT checkpoints_timed, checkpoints_req FROM pg_stat_bgwriter;
关键判断字段:Slow_queries、Aborted_connects、deadlocks、sessions_fatal 的增量与日志量峰值的时间相关性;高频错误/告警指纹;checkpoints_req 偏多时 log_checkpoints 会产生更多记录;诊断阈值(long_query_time、log_min_duration_statement)是否过低导致近似全量记录。
下一步:连接/认证风暴→“连接数耗尽”场景(连接类故障)或“认证失败”场景;慢 SQL 过多→“慢查询”场景(性能类故障);死锁多→“死锁”场景(锁与并发故障);阈值不合理→“日志清理策略检查”与本场景“解决方案”调整([变更])。
2.3.3 日志清理策略检查
目的:确认轮转、压缩、保留与上传机制正常,并保证缩短保留不破坏审计合规与在查事件的证据链。
云控制台方法(厂商中立)[只读]:核对日志服务的保留天数、轮转规则、压缩与归档目标、采集代理状态与失败告警;确认审计日志保留满足合规要求;确认应用与数据库没有重复采集同一份日志。
MySQL 8.0 [只读]
SHOW VARIABLES WHERE Variable_name IN
('binlog_expire_logs_seconds','max_binlog_size','log_output','general_log','slow_query_log');
SHOW BINARY LOGS;
- PostgreSQL 14+ [只读]
SELECT name, setting, unit FROM pg_settings
WHERE name IN ('log_rotation_age','log_rotation_size','log_truncate_on_rotation',
'logging_collector','archive_mode','archive_command');
SELECT archived_count, failed_count, last_archived_wal, last_failed_wal, last_failed_time
FROM pg_stat_archiver;
关键判断字段:log_rotation_age/log_rotation_size 是否有效、log_truncate_on_rotation 与文件名模板是否配合;binlog_expire_logs_seconds/max_binlog_size 是否生效;pg_stat_archiver.failed_count 与 last_failed_time(归档失败会让日志无法回收);采集代理是否堆积未上传文件。
下一步:轮转未生效→按 [变更] 修正配置;归档失败→修复归档目标(同时见“binlog/WAL 异常增长或保留”场景的“binlog/WAL 生成与清理状态检查”);采集堆积→修复代理并清理已上传文件;不要直接删除活动日志文件,使用平台或数据库支持的轮转/清理机制。
2.4 Agent 诊断提示词
把下面整段复制给 STAROps 数字员工,替换全部占位符后提交。模板是自包含的:候选原因、需要 DBA 执行的只读语句都已写在模板内。
任务:定位"日志文件过大"场景(存储与日志故障)的根因,给出可执行处置建议,并保留完整证据链。
【输入补充】
占用最大的日志类型:<VALUE>;平台是否托管轮转:是 / 否
【前置检查补充】
0.2 需确认的日志:慢日志、错误日志与审计日志等各类投递库。
0.7 日志是否由平台托管轮转与留存,留存策略当前值是否可读。
指标 Key(MySQL,已核实可直接用于 DescribeDBInstancePerformance 的 Key 参数):
MySQL_DetailedSpaceUsage —— 日志空间分项与总空间(MB)
【数据源(本场景取值)】状态与降级规则按契约执行
云监控 2.0 / 托管 Prometheus:磁盘使用率与日志空间分项、SLS 写入量与索引量。
CMS2_WORKSPACE 路由:starops observe entity metric-data 或 metric_set query(PromQL)。
ALIYUN_RDS 路由:aliyun rds DescribeDBInstancePerformance 按 Key 拉序列。
SLS(<SLS_PROJECT> 下对应 Logstore):各投递库的写入速率与内容分布:重复错误、慢日志暴增、
审计量。
未投递到 SLS 时改用 OpenAPI:慢日志 DescribeSlowLogs(统计)与
DescribeSlowLogRecords(明细)、错误日志 DescribeErrorLogs。
系统事件与告警:参数组变更(日志开关与阈值)、审计开关变更。
CMS2_WORKSPACE 路由:starops observe alerts query + changes query +
acm_basic event system-query。
ALIYUN_RDS 路由:aliyun rds DescribeEvents 查历史事件。
云平台 OpenAPI:日志相关参数当前值、日志备份与留存策略、审计配置。
常用接口:DescribeDBInstanceAttribute(实例详情)、DescribeParameters(参数当前值)。
降级兜底:审计日志与 SQL 洞察若未开启,日志构成只能靠 DBA 侧文件清单:
缺失时标注为不可得,不要用磁盘总量反推日志类型占比。
需 DBA 执行并粘贴:各类日志体积、日志开关与阈值当前值、轮转与保留设置。
【采集步骤】
A. Agent 自取(逐项回报数据源、取值、采集时间)
1) 取各投递库写入速率曲线,定位速率突增时间点与主导日志类型。
2) 查参数:慢日志阈值、general 与审计开关、PostgreSQL 的 log_statement 与
log_min_duration_statement 当前值,排除调试配置遗留。
3) 查磁盘空间分项与留存策略,确认是生成过多还是清理不及时。
4) 分析日志内容分布,判断是否为错误风暴或慢查询暴增导致的放大。
B. 需 DBA 执行只读语句后粘贴原始输出(Agent 无权限;语句已给全,按引擎选用)
1) 日志体积与开关:
MySQL:SHOW BINARY LOGS;
SHOW VARIABLES WHERE Variable_name IN ('binlog_expire_logs_seconds',
'slow_query_log','slow_query_log_file','long_query_time',
'general_log','log_error');
-- expire_logs_days 已在 MySQL 8.2.0 移除,不要再配置
PostgreSQL:SHOW log_min_duration_statement; SHOW log_statement;
SHOW logging_collector; SHOW log_rotation_age; SHOW log_rotation_size;
SELECT pg_size_pretty(sum(size)) FROM pg_ls_waldir();
2) 若日志目录可读,提供各类日志文件的大小与最后写入时间清单。
【候选原因与判定补充】
- 日志级别或开关配置不当(调试参数遗留)
- 错误或慢查询风暴导致日志放大
- 日志轮转与保留策略缺失
先判定是配置问题(开关与轮转)还是负载问题(错误或慢查询风暴),
前者改配置,后者治业务。
清理 binlog 或 WAL 属 [变更] 或 [高风险],须先确认无消费者与备份恢复点依赖。
2.5 解决方案
先修复错误源,启用合理轮转、压缩、保留和采样;敏感 SQL 日志按合规要求脱敏。修改日志级别、慢日志阈值或审计策略为 [变更],需确保不破坏审计合规和调查证据;先导出证据再缩短保留。不要直接删除活动日志文件,使用云平台或数据库支持的轮转机制。
2.6 验证与预防
确认日志增长速率、重复错误、采集费用和 IO 恢复基线,且轮转与上传成功。对临时诊断配置设置自动到期;监控日志摄入量与轮转失败;定期测试审计日志可检索性和保留合规。
3. binlog/WAL 异常增长或保留
3.1 现象描述
MySQL binary log 或 PostgreSQL WAL 占用持续增长,导致空间告警、备份/复制异常;redo 与 undo 也可能增长或造成恢复/清理压力。日志增长可能是正常写入增加,也可能因副本、复制槽、长事务或归档失败无法回收。
3.2 常见原因
3.2.1 写入量激增或大事务
判断依据:日志生成速率阶跃上升且与批任务、导入、DDL、发布时间吻合;Binlog_cache_disk_use 非零;单事务修改行数极大;binlog_row_image=FULL 或宽表更新放大日志体积。
验证方法:按“日志空间占用趋势分析”用两点差值计算速率;定位最大事务与高写入 SQL 指纹。
处置指向:拆分事务、限速批量写、错峰执行;评估行镜像与日志压缩设置([变更],需确认复制与 CDC 兼容性)。
3.2.2 复制槽/副本消费停滞
判断依据:PostgreSQL 槽 active=false 或 restart_lsn 长期不推进、wal_status 变为 extended/unreserved/lost(unreserved/lost 仅在 max_slot_wal_keep_size 非负时才会出现);MySQL 副本停止或报错但 binlog 仍需保留;CDC 任务下线未清理注册。
验证方法:按“主从同步对日志的依赖分析”核对每个消费者的位点、活跃状态与归属。
处置指向:优先修复或重建消费者使位点推进;确认永久废弃后按本场景“解决方案”的 [高风险] 流程删除槽或清理 binlog;为每个槽/通道登记所有者与到期策略。
3.2.3 保留策略或归档失败
判断依据:pg_stat_archiver.failed_count 持续增长、last_failed_wal 停在同一文件;MySQL binlog_expire_logs_seconds 过长或未生效;PITR/备份保留窗口要求保留大量日志;wal_keep_size 设置过大。
验证方法:按“binlog/WAL 生成与清理状态检查”检查归档状态与保留参数;核对备份与 PITR 策略实际需要的窗口。
处置指向:修复归档目标(权限、容量、网络);按 RPO/RTO 与合规重新设定保留窗口([变更]);禁止手工删除 redo/binlog/undo 与 pg_wal 文件,只能使用数据库或平台支持的机制。
3.3 排查步骤
3.3.1 binlog/WAL 生成与清理状态检查
目的:确认日志配置、当前位点、文件清单、过期与归档策略是否生效,区分“生成太多”与“回收不掉”。
MySQL 8.0 [只读]
SHOW BINARY LOGS;
-- SHOW MASTER STATUS 在 8.2.0 弃用、8.4.0 移除;小版本为 8.4+ 时改用 SHOW BINARY LOG STATUS
SHOW MASTER STATUS;
-- binlog_transaction_compression 为 8.0.20+;innodb_redo_log_capacity 为 8.0.30+
-- (更早版本 redo 容量由 innodb_log_file_size × innodb_log_files_in_group 决定)
SHOW VARIABLES WHERE Variable_name IN
('log_bin','binlog_format','binlog_row_image','max_binlog_size',
'binlog_expire_logs_seconds','binlog_transaction_compression','innodb_redo_log_capacity');
- PostgreSQL 14+ [只读]
SELECT pg_current_wal_lsn() AS current_lsn, pg_walfile_name(pg_current_wal_lsn()) AS current_file;
SELECT name, setting, unit, source FROM pg_settings
WHERE name IN ('wal_level','max_wal_size','min_wal_size','wal_keep_size',
'archive_mode','archive_command','archive_timeout','wal_compression');
SELECT archived_count, failed_count, last_archived_wal, last_archived_time,
last_failed_wal, last_failed_time
FROM pg_stat_archiver;
SELECT count(*) AS wal_files, pg_size_pretty(sum(size)) AS wal_size FROM pg_ls_waldir();
关键判断字段:binlog_expire_logs_seconds 是否生效、最旧 binlog 文件的时间;failed_count/last_failed_wal 表示归档失败(归档失败时 WAL 无法回收);wal_keep_size 与 max_wal_size(后者是检查点软目标,不是磁盘硬上限);binlog_row_image=FULL 会显著放大日志量。
下一步:归档失败→修复归档目标并确认 failed_count 停止增长;文件数远超配置预期→“主从同步对日志的依赖分析”;生成速率异常→“日志空间占用趋势分析”与“主从/流复制延迟”场景的“主库写入压力分析”;redo/undo 压力→“长事务”场景(锁与并发故障)与“I/O 性能异常”场景的“日志写入与数据写入分离分析”。
3.3.2 主从同步对日志的依赖分析
目的:确认所有消费者(副本、CDC、备份/PITR、逻辑订阅)的最旧安全位点,避免清理掉仍被需要的日志。
MySQL 8.0 [只读]
-- SHOW REPLICA STATUS 为 8.0.22+;更早小版本用 SHOW SLAVE STATUS
SHOW REPLICA STATUS FOR CHANNEL '<CHANNEL>';
SELECT CHANNEL_NAME, SERVICE_STATE, LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE
FROM performance_schema.replication_connection_status;
SELECT CHANNEL_NAME, SERVICE_STATE, LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE
FROM performance_schema.replication_applier_status_by_worker;
SHOW PROCESSLIST;
- PostgreSQL 14+ [只读]
SELECT slot_name, slot_type, database, active, active_pid,
restart_lsn, confirmed_flush_lsn, wal_status,
pg_size_pretty(safe_wal_size) AS safe_wal_size,
pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) AS retained_bytes,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained
FROM pg_replication_slots
-- 不能按 pg_size_pretty 的文本结果排序(字典序会把 9 MB 排在 10 GB 之前);restart_lsn 可为 NULL
ORDER BY pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) DESC NULLS LAST;
-- 下面两列均受 max_slot_wal_keep_size 约束:该参数默认 -1 时 safe_wal_size 恒为 NULL,wal_status 也不会出现 unreserved/lost
SHOW max_slot_wal_keep_size;
SELECT application_name, client_addr, state, sent_lsn, flush_lsn, replay_lsn,
pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS byte_lag
FROM pg_stat_replication;
关键判断字段:MySQL 中通过 SHOW PROCESSLIST 的 Binlog Dump 线程确认仍在拉取的消费者及其位点、副本是否停止或报错;PostgreSQL 槽的 active、wal_status(reserved/extended/unreserved/lost)、restart_lsn 与保留字节、safe_wal_size 余量(这两项都取决于 max_slot_wal_keep_size:该参数默认 -1 时 safe_wal_size 恒为 NULL、wal_status 也只会是 reserved/extended,要把余量和 lost 当判据须先将其设为非负值,属 [变更]);byte_lag 是否持续扩大。
注意:槽 active=false 不代表无用;必须确认消费者归属、RPO 要求与重建成本后才能处置。
下一步:消费者停止但仍需要→修复或重建后推进位点(“主从/流复制延迟”场景(锁与并发故障));确认废弃→按本场景“解决方案”的 [高风险] 流程清理;wal_status='lost'→该消费者已无法续传,需重建并复盘监控缺口;空间紧迫→先扩容再处置。
3.3.3 日志空间占用趋势分析
目的:量化日志生成与回收的平衡关系,判断是持续超产、单次尖峰还是回收受阻,并估算耗尽时间。
MySQL 8.0 [只读]
-- 间隔固定时间执行两次并比较差值
SELECT NOW() AS sampled_at;
SHOW BINARY LOGS;
SHOW GLOBAL STATUS WHERE Variable_name IN
('Innodb_os_log_written','Binlog_cache_use','Binlog_cache_disk_use');
SELECT trx_id, trx_started, trx_rows_modified, LEFT(trx_query,120) AS q
FROM information_schema.innodb_trx ORDER BY trx_started LIMIT 20;
- PostgreSQL 14+ [只读]
-- 间隔固定时间执行两次,用 LSN 差值计算生成速率
SELECT now() AS sampled_at, pg_current_wal_lsn() AS lsn;
SELECT pid, now()-xact_start AS xact_age, state, backend_xmin, left(query,120) AS q
FROM pg_stat_activity WHERE xact_start IS NOT NULL ORDER BY xact_start LIMIT 20;
SELECT datname, age(datfrozenxid) AS xid_age FROM pg_database ORDER BY 2 DESC;
关键判断字段:单位时间生成字节数与回收字节数的差值;Binlog_cache_disk_use 非零指向大事务;最老事务年龄与 backend_xmin(长事务会拖延清理);age(datfrozenxid) 反映的事务 ID 年龄;日志空间剩余量 ÷ 净增速率得到预计耗尽时间。
下一步:生成远大于回收且消费者正常→限流/拆批并评估保留策略([变更]);长事务拖延清理→“长事务”场景(锁与并发故障);回收受阻于槽或归档→“binlog/WAL 生成与清理状态检查”、“主从同步对日志的依赖分析”;耗尽时间紧迫→先扩容并停止高日志任务。
3.4 Agent 诊断提示词
把下面整段复制给 STAROps 数字员工,替换全部占位符后提交。模板是自包含的:候选原因、需要 DBA 执行的只读语句都已写在模板内。
任务:定位"binlog/WAL 异常增长或保留"场景(存储与日志故障)的根因,给出可执行处置建议,并保留完整证据链。
【输入补充】
日志目录当前总量:<VALUE>;是否存在 CDC 或逻辑订阅:是 / 否
【前置检查补充】
0.2 需确认的日志:实例错误日志。
0.7 下游消费者(只读实例、CDC、逻辑订阅)能否通过 OpenAPI 或 UModel 完整枚举;
不完整则不得判定可清理。
CMS2_WORKSPACE 路由下用 starops observe entity topo / entity neighbor 枚举下游依赖。
指标 Key(MySQL,已核实可直接用于 DescribeDBInstancePerformance 的 Key 参数):
MySQL_DetailedSpaceUsage —— 日志空间分项(MB)
MySQL_ReplicationDelay —— 备库复制延迟(秒),用于判断消费是否停滞
版本分支提示(MySQL 8.0 vs 8.4):
SHOW MASTER STATUS 在 MySQL 8.4 已移除,改用 SHOW BINARY LOG STATUS。
SHOW SLAVE STATUS 在 MySQL 8.4 已移除,改用 SHOW REPLICA STATUS。
expire_logs_days 在 MySQL 8.2.0 已移除,改用 binlog_expire_logs_seconds。
执行前先用 SELECT VERSION() 确认小版本,选用对应语法。
【数据源(本场景取值)】状态与降级规则按契约执行
云监控 2.0 / 托管 Prometheus:磁盘使用率与日志空间分项、复制延迟、(若暴露)归档相关指标。
CMS2_WORKSPACE 路由:starops observe entity metric-data 或 metric_set query(PromQL)。
ALIYUN_RDS 路由:aliyun rds DescribeDBInstancePerformance 按 Key 拉序列。
SLS(<SLS_PROJECT> 下对应 Logstore):错误日志中的归档失败、槽保留告警、复制中断记录。
未投递到 SLS 时改用 OpenAPI:慢日志 DescribeSlowLogs(统计)与
DescribeSlowLogRecords(明细)、错误日志 DescribeErrorLogs。
系统事件与告警:复制中断、订阅下线、备份任务、切换。
CMS2_WORKSPACE 路由:starops observe alerts query + changes query +
acm_basic event system-query。
ALIYUN_RDS 路由:aliyun rds DescribeEvents 查历史事件。
云平台 OpenAPI:日志保留策略与备份设置、只读实例与订阅任务清单、保留与归档参数当前值。
常用接口:DescribeDBInstanceAttribute(实例详情)、DescribeParameters(参数当前值)。
UModel 拓扑:正在消费该实例日志的下游:只读实例、CDC 任务、逻辑订阅。
降级兜底:下游消费者清单若无法从 OpenAPI 与 UModel 完整枚举,一律视为
存在未知消费者:清理类建议只能停留在 [高风险] 待确认,不得给出可清理结论。
需 DBA 执行并粘贴:日志生成与清理状态、复制槽与位点、归档状态。
【采集步骤】
A. Agent 自取(逐项回报数据源、取值、采集时间)
1) 取日志空间与磁盘使用率曲线,按增速外推耗尽时间。
2) 调 OpenAPI 取保留策略、备份配置、只读实例与订阅任务清单;结合 UModel 列出全部下游消费者。
3) 查事件与错误日志:归档失败、复制中断、订阅下线的时间点。
4) 取复制延迟曲线,判断消费停滞是否与日志堆积同步开始。
B. 需 DBA 执行只读语句后粘贴原始输出(Agent 无权限;语句已给全,按引擎选用)
1) 日志生成与清理状态:
MySQL:SHOW BINARY LOGS; -- 文件清单与总量
SHOW BINARY LOG STATUS; -- 8.4+;8.0 用 SHOW MASTER STATUS(8.4 已移除)
SHOW VARIABLES LIKE 'binlog_expire_logs_seconds';
PostgreSQL:SELECT pg_current_wal_lsn();
SELECT pg_size_pretty(sum(size)) FROM pg_ls_waldir();
SHOW archive_mode; SELECT * FROM pg_stat_archiver;
2) 消费者与保留余量:
MySQL:SHOW PROCESSLIST; -- 找 Binlog Dump 线程,确认仍在拉取的消费者与位点
PostgreSQL:SHOW max_slot_wal_keep_size; -- 默认 -1,此时下面 safe_wal_size 恒为 NULL
SELECT slot_name, slot_type, active, active_pid, restart_lsn,
wal_status, pg_size_pretty(safe_wal_size) AS safe_wal_size,
pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) AS retained_bytes
FROM pg_replication_slots
ORDER BY pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)
DESC NULLS LAST;
【候选原因与判定补充】
- 写入量激增或大事务
- 复制槽或副本消费停滞
- 保留策略不当或归档失败
删除复制槽或清理 binlog 属 [高风险]:必须用 UModel、OpenAPI 与 DBA 输出
共同证明无任何消费者、备份点与合规留存依赖。
注意 wal_status 的 unreserved 与 lost 仅在 max_slot_wal_keep_size 非负时才可能出现。
3.5 解决方案
先扩容或暂停日志高增长任务,修复复制/归档消费者,再按恢复策略清理。
PURGE BINARY LOGS TO '<BINLOG_FILE>' 是 [高风险]:执行前必须确认所有副本/CDC/备份的最旧所需位点、PITR 保留窗口、目标文件边界和可恢复备份,并导出 SHOW BINARY LOGS 与复制状态;误清理会使消费者无法续传。
SELECT pg_drop_replication_slot('<SLOT>') 是 [高风险]:仅在业务所有者确认消费者永久废弃或可全量重建、记录槽位点并具备重建容量后执行。活动槽不能简单删除;逻辑槽删除会丢失尚未消费的变更。
调整 binlog/WAL 保留、归档、redo 容量或检查点参数均为 [变更],需满足 RPO/RTO、备份和复制要求,并验证重启/切换条件。
禁止手工删除 MySQL redo、binlog、undo 文件;禁止手工删除 PostgreSQL pg_wal 文件。 只能使用数据库支持的清理机制或云平台流程。
3.6 验证与预防
确认日志生成与回收达到动态平衡、剩余空间可覆盖写入峰值和最长允许中断,所有副本/CDC/归档连续且 PITR 窗口满足策略。为每个复制槽/通道登记所有者、SLO 和到期策略;监控日志生成速率、最旧消费位点、归档失败和预计耗尽时间;定期做恢复演练。
延展阅读
术语表
| 术语 | 含义 |
|---|---|
| SLO | 服务级别目标,用于判断性能/可用性是否异常,而非依赖通用固定阈值 |
| RPO / RTO | 可接受的数据丢失量 / 可接受的恢复时长 |
| 连接池 | 复用数据库连接并限制并发的客户端组件;池总量必须纳入实例连接预算 |
| Performance Schema | MySQL 的运行时监控体系,提供语句、等待、锁和内存等视图 |
| pg_stat_statements | PostgreSQL SQL 指纹累计统计扩展,需预加载和授权 |
| MVCC | 多版本并发控制;长事务会延长旧版本保留 |
| 元数据锁 | 保护对象定义的锁;DDL 常因业务事务而等待 |
| 死锁 | 多事务形成循环等待;数据库通常回滚其中一个事务解环 |
| redo | MySQL InnoDB 用于崩溃恢复的重做日志,不是可手工清理的普通文件 |
| undo | MySQL 用于事务回滚和 MVCC 的撤销信息,不得手工删除 |
| binlog | MySQL 逻辑变更日志,用于复制、CDC 和时间点恢复 |
| WAL | PostgreSQL 预写日志,用于崩溃恢复、复制和归档 |
| LSN | PostgreSQL 日志序列号,用于衡量发送、落盘和回放位点 |
| 复制槽 | PostgreSQL 为消费者保留 WAL/变更的位置状态;废弃槽可导致 WAL 无限保留 |
| 检查点 | 将恢复起点向前推进并协调脏页写出的机制;过密可能产生 IO 峰值 |
| PITR | 基于基础备份和日志进行时间点恢复 |
版本基线与边界
| 项目 | 基线 |
|---|---|
| MySQL | 8.0,默认 InnoDB;优先使用 Performance Schema、sys 库和复制状态表 |
| PostgreSQL | 14 及以上;优先使用 pg_stat_*、pg_locks、pg_settings 等系统视图 |
| 云环境 | 厂商中立;部分参数、日志、文件系统和超级用户权限由云平台托管 |
| 判断原则 | 不使用“CPU 超过 80%”“缓存命中率必须 99%”等无依据固定阈值;以业务 SLO、实例规格、工作负载类型和历史基线判断 |
版本差异会影响字段和可用功能。执行前应核对目标小版本文档,并在只读副本、预发或回放环境验证 SQL。
另需注意基线自身的生命周期:MySQL 8.0 已于 2026-04-21 进入 Sustaining Support,PostgreSQL 14 的社区支持在 2026-11-12 终止。停留在这两个基线意味着不再获得常规缺陷与安全修复,排查中怀疑命中已知缺陷时应优先确认升级路径(MySQL 8.4 LTS、PostgreSQL 15 及以上),并注意升级会同时引入下表列出的语法与参数变更。
本文出现的以下名称受版本约束,跨小版本/大版本使用前必须对照替换:
| 名称 | 版本约束与替代 |
|---|---|
| SHOW REPLICA STATUS、Replica_IO_Running、Replica_SQL_Running、Seconds_Behind_Source | MySQL 8.0.22+;更早小版本用 SHOW SLAVE STATUS、Slave_IO_Running、Slave_SQL_Running、Seconds_Behind_Master |
| replica_parallel_workers、replica_parallel_type、replica_preserve_commit_order、replica_net_timeout | MySQL 8.0.26+;更早版本用对应 slave_* 旧名 |
| binlog_transaction_compression | MySQL 8.0.20+ |
| innodb_redo_log_capacity | MySQL 8.0.30+;更早版本 redo 容量由 innodb_log_file_size × innodb_log_files_in_group 决定 |
| performance_schema.tls_channel_status | MySQL 8.0.21+;have_ssl 自 8.0.26 起弃用,不再作为 TLS 判据 |
| innodb_undo_tablespaces | MySQL 8.0.14 起弃用且不可配置;undo 盘点改用 Innodb_undo_tablespaces% 状态变量与 information_schema.innodb_tablespaces(含 STATE),配合 innodb_undo_log_truncate、innodb_max_undo_log_size |
| pg_hba_file_rules.rule_number、.file_name | PostgreSQL 16+ 才有;PG14 用 line_number 排序 |
| pg_stat_bgwriter 的 checkpoint 相关列 | PG17 起迁至 pg_stat_checkpointer 并改名(num_timed/num_requested/write_time/sync_time/buffers_written),buffers_backend、buffers_backend_fsync 被移除 |
| pg_stat_statements.blk_read_time、.blk_write_time | PG17 起改名为 shared_blk_read_time、shared_blk_write_time |
| SHOW MASTER STATUS | MySQL 8.2.0 起弃用、8.4.0 起移除;8.4+ 改用 SHOW BINARY LOG STATUS。同批被移除的还有 SHOW SLAVE STATUS、SHOW SLAVE HOSTS,需分别改用 SHOW REPLICA STATUS、SHOW REPLICAS。托管实例小版本可能已是 8.4 LTS,照抄 8.0 语句会直接报语法错误 |
| pg_replication_slots.safe_wal_size、.wal_status | 两列的可用性取决于 max_slot_wal_keep_size:该参数默认为 -1,此时 safe_wal_size 恒为 NULL,wal_status 也只会出现 reserved/extended,不会出现 unreserved/lost。要把“槽还剩多少余量”当判据,必须先把该参数设为非负值(属 [变更]) |
通用诊断原则
先定影响,再定层次:区分单用户/单可用区/全实例,读/写,偶发/持续;按客户端→DNS→路由/ACL→代理/负载均衡→数据库监听→认证→SQL/事务→存储逐层缩小范围。
先读后改、一次一变:优先只读查询;为诊断 SQL 设置合理超时;记录变更前值、审批、回滚条件和负责人。
时间对齐:应用、数据库、云监控与审计日志统一到 UTC 或明确时区;围绕故障前后窗口对比历史基线和正常实例。
相关不等于因果:CPU、锁、慢 SQL、IO 等可能互为结果;用时间线、等待事件和可复现实验证伪假设。
不把探测当结论:ping 失败可能只是 ICMP 被禁,不等于 TCP 不通;telnet/nc 成功仅表示 TCP 握手成功,不代表 TLS、数据库认证、授权或 SQL 可用。
避免观测放大故障:不要在高负载主库执行无过滤的大表扫描、全量 SHOW ENGINE INNODB STATUS 高频采样或广域日志抓取。
托管边界优先:无法访问主机、参数只读、日志被截断或缺少超级用户权限时,使用云控制台等价指标/诊断功能并提交工单,不尝试绕过平台限制。
官方参考资料
MySQL 8.0
PostgreSQL 14+
官方文档链接以指定主版本为基线。生产操作前还应核对目标云服务的参数限制、维护行为、备份/PITR、复制实现和当前小版本发布说明。




