资讯动态

AWR中Failed Logon Delay飙升?定位与处理实战

发布时间:2026/10/21 23:45:10 来源:尧图企业网站定制
上周帮朋友看一份19c的AWR报告加载出来之后我盯着屏幕看了好几秒Top 5等待事件里第二个位置赫然写着Failed Logon Delay。这个名字在等待事件里真不算常见大多数时候它只是偶尔露个脸占零点几秒没想到这次成了第二名。干DBA这些年Failed Logon Delay 排进前五都不多见排到第二说明系统的失败登录已经不是零星误操作而是有东西正在反复撞数据库的认证大门。我在群里把这个截图发出去第一反应是“是不是有人拿着旧密码疯狂重试”第二反应是“如果直接把FAILED_LOGON_DELAY调成 0报告是不是就好看了”。但这两件事恰恰都是坑。这个事件背后的原理、定位方法和处理方式值得好好捋一遍。下文就按我实际排障的思路展开不绕弯子直接说怎么从AWR里看到它、怎么定位、怎么处理。1. AWR里的“隐形人”为什么会突然刷到第二位1.1 这个事件到底在等什么先解决一个基础问题Failed Logon Delay 到底是什么等待事件简单说当客户端向数据库提交登录认证请求后如果用户名、口令校验失败数据库并不会立刻把“ORA-01017: invalid username/password; logon denied”返回给客户端而是先在内部“睡”一小段时间睡完再返回错误。这个睡眠动作在等待事件里就是Failed Logon Delay。睡眠时长由初始化参数FAILED_LOGON_DELAY控制默认值是 1 秒取值范围是 0 到 3600 秒单位是秒。为什么设计成等待事件而不是直接闷头 sleep 一下因为做成等待事件AWR、ASH、GV$SESSION 都能观测到DBA 才能知道“数据库花了多少时间在处理失败登录”。如果没有这个事件失败登录虽然也在拖慢数据库但你根本没法量化问题会隐藏得更深。这里有个容易混淆的点这种睡眠不是正常的业务等待而是安全机制主动制造出来的延迟。一个客户端输错密码数据库在这里白等 1 秒一万个客户端输错密码数据库就在这里白等一万秒DB Time 自然被顶高。1.2 Top 2 意味着 DB Time 被 sleep 填掉了一大块AWR 报告里的 Top 等待事件是按“总等待时间”排序的。Failed Logon Delay能排到第二意味着它累计等待的时间非常可观。做个粗略计算1 秒等待 × 1 万次失败登录就是 10000 秒约 2.78 小时5 万次失败就是 13.9 小时要是到了 18 万次就是整整 50 小时。在动辄看 60 分钟、120 分钟 AWR 快照的场景里一个等待事件累计几十小时排名自然靠前。所以看到这个事件排到 Top 2第一反应应该是失败登录的次数已经多到不正常的量级。正常OLTP系统即便有连接池反复建立会话通常也是成功的登录占大多数。失败登录如果到了几万次必然存在某个固定的“错误源”要么是应用配置里的密码不对要么是外部攻击在扫账户。它不会是自己跑出来的。1.3 与 FAILED_LOGIN_ATTEMPTS 别搞混很多刚接触这个事件的人会把FAILED_LOGON_DELAY和用户 PROFILE 里的FAILED_LOGIN_ATTEMPTS混为一谈这两个完全是不同维度的东西。项目FAILED_LOGON_DELAYFAILED_LOGIN_ATTEMPTS类别初始化参数用户PROFILE限制作用登录失败后延迟多少秒再返回错误连续失败多少次后锁定账号默认1秒0-3600秒无限制/由PROFILE决定效果每次失败都要等达到阈值后报 ORA-28000实际环境里两者往往会同时出现。攻击者反复试密码一方面每个失败都触发 1 秒延迟把 DB Time 顶高另一方面失败次数达到 PROFILE 阈值又会把账号锁掉造成业务账户连接失败。DBA 在排查时不要只盯着“账号被锁”这个表象要继续往前查失败来源。2. 底层原理数据库为什么故意给你“慢半拍”2.1 这是反暴力破解的“门锁阻尼器”把数据库登录比作门锁就很好理解一个人站在门口反复试钥匙如果门锁每次都立刻告诉他对不对他就能以极快的速度穷举所有钥匙。数据库也一样如果每次认证失败都立刻返回错误攻击者就能一秒试几百次密码普通口令根本撑不住。FAILED_LOGON_DELAY就是给门锁加了一个阻尼器每次密码错误必须等待 1 秒才能再试。这样暴力破解速度被硬生生压到每秒最多 1 次攻击成本成倍上升。有意思的是这个等待不仅对“密码错误”生效对“用户名不存在”同样生效。目的很明确防止攻击者通过响应时间差异来判断某个用户是否存在。如果“用户不存在”响应快、“密码错误”响应慢那就等于把账户字典免费送给了攻击者。统一延迟才能把这个信息抹平。2.2 为什么 CPU 不高DB Time 却暴涨这类故障最迷惑人的地方在于从系统层面看CPU 不高I/O 也不高数据库好像很闲但 AWR 报告里 DB Time 就是很高大量时间花在Failed Logon Delay上。原因是认证失败后的睡眠是前台会话的等待事件会计入 DB Time。DB Time 的构成就是“前台会话 CPU 时间 前台会话非空闲等待时间”。sleep 虽然不是真正的计算资源消耗但它是非空闲等待照样往 DB Time 里记。这就像高速公路上一百辆车堵在收费口高速本身的承载能力没问题但所有车都在“等待”总等待时间一样会爆炸。这个等待事件把数据库的认证环节放大成了一个显眼的瓶颈但瓶颈的根源不在数据库的 CPU 或 I/O而是在认证请求本身。2.3 19c 下相关参数的配置与注意点在 19c 环境里查看参数很简单SHOW PARAMETER FAILED_LOGON_DELAY;默认输出基本是 1。如果确认要调整可以执行ALTER SYSTEM SET FAILED_LOGON_DELAY 0 SCOPE BOTH;这句会把全局延迟关闭重启也保持。恢复默认则执行ALTER SYSTEM SET FAILED_LOGON_DELAY 1 SCOPE BOTH;但这里有几个坑第一在 CDB/PDB 架构下一定要先确认当前容器。你以为在改 CDB 根实际可能只影响某个 PDB或者反过来。稳妥做法是先ALTER SESSION SET CONTAINER 到目标容器再执行ALTER SYSTEM。第二如果是 RAC所有节点均需要确认参数一致。单个节点改另一个节点还是旧值排障时会被误导。第三这个参数单位是整数秒没有 0.5 秒这种中间档。要么保持 1要么直接为 0不存在“稍微调低一点”的空间。3. 定位“凶手”从等待事件反查失败登录现场3.1 先抓现场谁正卡在 Failed Logon Delay 里因为每次失败登录只等待 1 秒抓现场要快最好连续采样。首先可以直接查当前会话SELECT inst_id, sid, serial#, username, machine, program, module, event, seconds_in_wait, wait_time FROM gv$session WHERE event Failed Logon Delay AND type ! BACKGROUND;这条 SQL 能看到正在等待的会话包括用户名、客户端机器名、程序名。如果结果为空不代表没有只是 1 秒窗口太短没赶上。我习惯在 Linux 上跑一个小循环连续抓 60 次每 1 秒抓一次for i in $(seq 1 60); do sqlplus -s / as sysdba SQL set pagesize 0 feedback off timing off select to_char(sysdate,HH24:MI:SS)|| | ||inst_id|| | ||sid|| | ||username|| | ||machine|| | ||program|| | ||event from gv$session where eventFailed Logon Delay and type ! BACKGROUND; exit SQL sleep 1 done这个脚本在生产上跑 1 分钟压力不大但能得到一个快照集能看出失败登录是否有固定周期、是否来自同一台应用节点。如果看到的全是同一个中间件服务器、同一个程序名基本可以锁定方向。3.2 从审计记录按来源聚合抓现场只能抓到“现在”要统计“过去几小时谁失败了”最好的路径是审计日志。如果环境已经开启了登录审计可以直接查统一审计视图SELECT DB_USERNAME, USERHOST, CLIENT_PROGRAM_NAME, COUNT(*) AS FAIL_COUNT FROM UNIFIED_AUDIT_TRAIL WHERE ACTION_NAME LOGON AND RETURN_CODE ! 0 AND EVENT_TIMESTAMP SYSDATE - 1 GROUP BY DB_USERNAME, USERHOST, CLIENT_PROGRAM_NAME ORDER BY FAIL_COUNT DESC;这个查询会把过去一天登录失败次数按数据库用户、客户端主机、程序名聚合结果会非常直观通常有一个 DB_USERNAME 占据绝大多数来源主机就一两台。如果环境之前没开审计那过去的数据已经找不回来了。这时候可以先补一个最简单的登录失败审计策略等下一次故障复现时采集AUDIT LOGON WHENEVER NOT SUCCESSFUL;注意这个动作本身会增加少量审计负担生产环境要评估后执行。但相对于问题排查的收益这点开销是值得的。3.3 AWR和ASH为什么常常帮不上忙有人会问AWR 里都排第二了直接查DBA_HIST_ACTIVE_SESS_HISTORY不就能定位吗实际经验是经常定位不到。Failed Logon Delay的等待时间正好是 1 秒而 ASH 的采样周期也是 1 秒左右。一个会话只在数据库里闪了一下就结束了采样线程大概率没采到它。我从很多次实操里看到的情况是ASH 中这个事件的历史样本稀疏得可怜甚至一片空白。AWR 的优势是“累计统计”它把 1 小时内的等待时间全部加起来了所以能排到 Top但 AWR 只告诉你“发生了什么”不告诉你“谁做的”。要定位到具体主机、具体用户、具体程序靠的是审计和现场采样不能只依赖 AWR。3.4 从失败频率特征快速判断是应用Bug还是攻击排查时不要盲目试先看频率分布。这是我总结的一个判断表格失败特征倾向结论固定时间间隔出现数量稳定应用调度/连接池重试单个应用账号高频失败配置中的密码不正确或已过期单个IP尝试大量不同用户名暴力破解/账户扫描集中在凌晨或低峰期批处理任务或定时攻击失败后伴随账号锁定报警已触发 PROFILE 锁定机制这个表不绝对但能帮你在第一时间确定方向。如果看到“固定间隔 单个账号”八成是应用配置问题如果看到“单 IP 多用户名”赶紧先封 IP 再谈其他。4. 优化与治理不要一上来就把 FAILED_LOGON_DELAY 设成 04.1 为什么直接关掉是自欺欺人面对 Top 2 的等待事件最手痒的想法就是ALTER SYSTEM SET FAILED_LOGON_DELAY 0然后 AWR 立马清爽。但这是典型的“把仪表盘遮住当故障不存在”。关掉延迟后等待事件确实没了DB Time 也会瞬间降下来。但背后的失败登录请求还在每一次登录失败依然要消耗数据库认证的 CPU 和内存。如果攻击者正在扫密码关掉延迟等于把数据库的安全防线主动拆掉暴力破解速度直接飙升。等待事件只是报警器报警器拆掉不等于火灭掉了。DBA 当然可以让报告漂亮但不能替业务承担后续的安全事故责任。4.2 什么情况下可以临时调整调完怎么恢复我并不是说FAILED_LOGON_DELAY永远不能碰。如果已经定位到根因并且应用修复需要时间为了避免失败登录把整个库的 DB Time 全线占满可以在安全团队认可的前提下临时把参数降到 0等应用侧修复后再改回来-- 临时关闭重启失效 ALTER SYSTEM SET FAILED_LOGON_DELAY 0 SCOPE MEMORY; -- 应用恢复后重启保持生效 ALTER SYSTEM SET FAILED_LOGON_DELAY 1 SCOPE BOTH;SCOPE MEMORY表示只改当前运行实例重启后恢复原来的值。这样临时止血不会留下永久隐患。但记住止血之后必须继续找根因否则故障会反复出现。4.3 从根上消除失败登录压力处理这类问题的正确顺序是先找到失败来源再解释来源为什么存在最后做对应整改。如果是应用密码不一致比如配置中心已经轮换密码但部分应用节点没同步那就把所有节点的连接配置统一刷新并限制中间件连接池的启动重试频率。如果是连接池配置问题比如连接池测试连接时使用了错误凭据导致每隔一段时间就用旧密码探测一次那要修正配置并让连接池缓存过期。如果是外部暴力破解那就不是DBA单方面能解决的需要网络安全团队配合做来源IP封禁同时数据库侧启用账号锁定策略ALTER PROFILE app_user LIMIT FAILED_LOGIN_ATTEMPTS 5 PASSWORD_LOCK_TIME 10;这个 PROFILE 表示同一个账号连续失败 5 次后锁定 10 天能有效挡住大部分随机尝试。注意服务账号要单独评估别锁了真正要用的系统账号。4.4 一份可以抄走的预防清单经历了这次故障后我给自己的巡检单里加了下面几项每周检查 AWR 的 Top 5 等待事件只要出现 Failed Logon Delay立即立项排查。生产环境开启登录失败审计日志保留周期至少 7 天。所有数据库账号纳入统一凭据管理密码轮换时先发配置中心再重启应用连接池。中间件连接池配置“重试退避 熔断”不要每 5 秒、10 秒密集重试。关键服务账号单独设置 PROFILE平衡安全策略与业务连续性。外部来源访问数据库统一经过防火墙白名单非必要不直接暴露数据库端口。5. 一次Failed Logon Delay排第二的实战复盘5.1 现象是第一眼的“错觉”某天上午朋友发来一份 19c RAC 两节点的 AWR我打开后先看Top 5 Timed Events第二名的等待时间高达 17 小时。再往下看DB CPU只有几小时逻辑读和物理读都不高。直观感受是数据库负载明明很轻为什么 DB Time 这么高再看事件名Failed Logon Delay我心里已经有数了这不是数据库性能问题是有人在反复认证失败。剩下的工作就是找出那个人。5.2 顺着审计一路挖到应用配置我先在 RAC 两个节点上分别跑了一分钟采样脚本抓到若干个正在等待该事件的会话。它们的共同特征是MACHINE指向一台中间件服务器PROGRAM是 JDBC Thin ClientUSERNAME始终是同一个服务账号。接着查统一审计运行了 3.2 小节里的聚合 SQL结果非常明确过去两天这个服务账号的登录失败次数占全部失败次数的 94%来源主机就是那台中间件服务器并且失败行为呈固定周期大约每 15 秒一批批次里会连续出现几十次失败。应用团队复查后发现该服务账号的密码已经在配置中心做过轮换但有两台应用节点一直保留旧配置连接池里的密码没刷新。于是每次连接池定时重建连接时都会拿旧密码去数据库认证失败后就等 1 秒再继续下一批。几十个连接 × 1 秒等待每 15 秒循环一次两个节点产生大量 DB Time。5.3 修复与验证应用团队刷新了这两台节点的连接池配置并清掉了旧的缓存连接重启连接池后新的连接全部使用新密码认证失败量很快降到 0。下一份 AWR 报告里Failed Logon Delay直接从 Top 5 消失DB Time 恢复正常水平。整个过程中我没有改FAILED_LOGON_DELAY的值因为根因不在这个参数上。就算当时设为 0也只是让报告好看应用节点一样会在每个调度周期用错误密码去撞认证接口等到密码轮换周期变长、失败次数累积到锁定阈值最终还是会爆发账号锁定故障。5.4 复盘后留下的几条经验这次排障给我最大的提醒是等待事件排名不会说谎但解读排名的人容易想歪。Failed Logon Delay排到 Top 2看起来像“数据库认证环节被拖垮”实际上更可能是“上游某个应用的凭据悄悄变了”。DBA 的职责不是默认数据库配置有问题而是顺着等待事件找到背后那个“错误请求”。另外一定要重视审计。如果没有登录失败审计这次排查就只能靠抓现场碰运气效率低很多。开启审计、定期保留日志这类功夫在平时关键时刻能救命。我在实际处理里碰到Failed Logon Delay排到 Top 2第一反应一定是去翻审计和来源而不是急着调参数。数据库每一个等待事件都是在替上游的错误背锅把“背锅的锅”删掉锅本身还在。希望这篇思路能让你下次看到它时少走弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑