ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

YashanDB数据库7类高频故障排查实战清单

YashanDB数据库7类高频故障排查实战清单 做DBA这行最怕的不是半夜被电话叫醒而是电话那头业务已经瘫了你却连问题都定位不到。国产数据库这几年在各行各业落地得越来越多YashanDB就是其中绕不开的一个名字。这套数据库在SQL兼容性、性能表现上确实不错但数据库这个东西无论什么牌子故障总归是运维路上绕不过去的坎。今天我把实际运维中碰到最多的7类YashanDB数据库故障逐一拆开把故障现象、根因分析、处理步骤、避坑经验都摆出来。不管你是刚接手这套库的运维新人还是正在做数据库国产化替代评估的架构师这份清单都能让你少走不少弯路。1. 故障清单概览与排查方法论1.1 为什么重点关注这7类故障我梳理的这7种故障不是从文档里抄出来的理论场景而是基于真实运维环境中故障工单的频次统计。实例起不来、连接打满、慢SQL拖垮业务、内存被打爆、磁盘写满、日志归档失败、锁等待死锁这几类问题加在一起差不多占了数据库故障总量的八成以上。你会发现这些故障之间有很强的关联性。比如慢SQL堆积会导致连接数打满连接数打满又可能引发内存压力增大内存不足触发OOM后实例重启重启过程中日志切换失败又可能导致实例hang住。所以处理数据库故障不能只盯着单点现象一定要有全局视角。本文的排查方法论是先保业务可用再采集现场信息最后定位根因修复。这个顺序不能乱丢了现场后面想复盘就难了。1.2 故障排查的通用思路在处理任何YashanDB故障之前我建议你先在心里过一遍这几件事第一确认影响范围。是单条SQL慢还是整个实例不可用是单节点问题还是集群整体故障影响范围的判断直接决定了你的响应级别。第二先看告警日志和系统日志。无论什么故障第一步永远是看日志而不是急着重启或者kill会话。YashanDB的告警日志alert日志会记录实例启动关闭、参数变更、错误堆栈等信息操作系统层面还需要配合dmesg、sar、top等工具交叉验证。第三采集现场信息。把关键视图的数据、日志片段、参数配置都留存下来。很多时候故障是间歇性的没有现场信息等故障过去了再排查效率会非常低。第四制定处理方案并评估风险。任何操作前都要想清楚这个命令会不会影响正在跑的业务kill一个会话会不会导致事务回滚和数据不一致评估完再动手。这套流程说起来简单但每次故障都严格走完这些步骤的人并不多。很多事故就是因为在信息不完整的情况下贸然操作把小问题变成了大事故。2. 实例启动失败与连接异常2.1 故障一实例无法启动故障现象执行启动命令后实例长时间卡在STARTING状态或者直接报错退出。应用侧表现为数据库连不上监控面板上实例状态为离线。原因分析从实际排查经验看实例起不来的原因通常集中在以下几类参数文件配置错误。比如内存参数设置超过了物理内存上限或者某些路径参数指向了不存在的目录。端口被占用。YashanDB实例监听端口被其他进程占用导致启动时无法绑定端口。数据文件或日志文件权限不正确。数据库进程OS用户没有对应文件的读写权限启动时打开文件失败。共享内存或信号量等操作系统资源不足导致实例初始化失败。上次异常关机导致数据文件状态不一致启动时需要做实例恢复但恢复过程中又碰到了其他问题。处理步骤按照下面这个顺序来排查基本能覆盖绝大多数场景。第一步检查进程和端口状态。先确认是不是已经有实例进程在运行用ps -ef | grep yasdb查看进程是否存在用netstat -anp | grep 监听端口确认端口是否被占用。我遇到过好几次所谓的起不来其实是之前残留的进程还占着端口把残留进程清理掉实例就能正常起来了。第二步查看告警日志。这是定位启动失败最核心的一步。日志里通常会明确告诉你失败的原因比如invalid value for parameter、 cannot open file等关键描述。找到报错行后上下文还会附带具体的参数名或文件名。第三步检查数据文件权限。用ls -l查看数据文件、控制文件、日志文件的属主和权限位确认数据库OS用户对这些文件有读写权限。常见的问题是DBA用root解压或拷贝了数据文件导致属主变成了root数据库进程起不来。第四步检查操作系统资源限制。查看共享内存和信号量设置。如果之前调过操作系统内核参数重启后参数失效也会导致启动失败。注意实例启动失败时不要反复暴力尝试启动。连续几次强制拉起可能会加剧数据文件损坏的风险。每次尝试启动前先确认上一次失败的原因已经排查清楚再触发下一次启动。2.2 故障二连接数打满新连接进不来故障现象应用报too many connections或者连接超时数据库服务器CPU和内存可能都不高但新连接就是建立不起来。监控上能看到当前会话数长期维持在峰值附近。原因分析连接数打满很多时候根因不在数据库本身而在应用侧的连接管理策略应用连接池配置不合理。比如最小连接数设置过大或者连接池的最大连接数超过了数据库上限。慢SQL占住连接不释放。每个会话都在执行慢查询事务迟迟不结束连接自然释放不了。应用存在连接泄漏。代码里获取连接后没有正确归还到连接池连接被一点点耗尽。短连接风暴。应用频繁创建和销毁连接数据库端大量TIME_WAIT状态的连接堆积。处理步骤连接数打满属于紧急故障处理优先级要高先恢复业务再排查根因。第一步登录数据库查询当前会话数量以及各会话的状态。用类似select status, count(*) from v$session group by status;的语句快速判断是活跃会话多还是空闲会话堆积。这里的关键是区分活跃和空闲如果大部分是空闲会话处理空间就很大。第二步定位空闲会话并清理。对于长期处于INACTIVE状态的会话如果确认应用侧已经不再使用可以将其kill掉释放连接资源。kill会话的操作要谨慎最好先和业务方确认避免杀掉正在执行关键事务的会话。第三步评估是否需要临时调大最大连接数。如果业务确实需要更大的并发连接数可以在参数层面调高上限。但要注意每个连接都会消耗内存和进程资源盲目调大可能引发内存不足的问题必须结合服务器物理内存情况综合评估。第四步推动应用侧整改。把连接池的最大连接数、最小连接数、空闲超时时间等参数调到一个合理范围修复连接泄漏的代码逻辑。这一步才是根治连接数打满的关键。3. 性能瓶颈与资源耗尽类故障3.1 故障三慢SQL拖垮整个数据库故障现象业务接口响应时间明显变长数据库CPU使用率飙升监控中出现大量磁盘读AWR或性能报告里TOP SQL的耗时数据异常突出。用户感知就是系统卡死了。原因分析慢SQL的根因比较复杂从实际案例看有这几类高频原因统计信息过期优化器选错了执行计划。表的数据量已经翻了好几倍统计信息还停留在很久之前优化器可能选择了全表扫描而非索引扫描。索引缺失或者索引失效。查询条件中的列没有合适的索引或者因为隐式类型转换、函数包裹等原因已有索引无法被使用。SQL写法问题比如在查询条件中使用函数、OR条件、否定条件等容易导致索引失效的写法。数据量本身增长过快排序、分组、临时表操作需要的资源超出了合理范围。处理步骤定位慢SQL我用的是由外到内的方法。第一步先抓慢SQL。YashanDB支持慢查询日志可以设置一个阈值比如执行时间超过5秒的SQL记录到日志中。也可以通过动态性能视图查询当前正在执行的耗时SQL找到那些运行时间长、逻辑读高的会话。第二步分析SQL执行计划。用EXPLAIN关键字查看执行计划这里重点看几个问题是否走了索引是否有全表扫描有没有临时表排序预估行数和实际行数偏差大不大执行计划就像SQL的导航路线优化器规划了一条路线你要检查这条路线是不是绕了远路。第三步更新统计信息。如果执行计划中预估的行数与实际行数差距太大大概率是统计信息过期了执行DBMS_STATS类似的统计信息收集操作后再看执行计划是否变化。第四步针对性优化。这可能涉及几个方向调整SQL写法避免在索引列上使用函数创建合适的复合索引或者改写SQL逻辑把大查询拆成小查询。优化完成后必须回到第一步验证SQL执行时间是否真的降下来了。注意优化SQL时不要一上来就加索引。索引不是免费的每个索引都会增加写入开销。先看执行计划确认SQL确实走了全表扫描再考虑索引方案避免为了优化而优化。3.2 故障四内存不足引发OOM故障现象数据库进程突然消失实例自动重启业务出现短暂中断。查看系统日志能看到Out Of Memory Killer的击杀记录。监控面板显示内存使用率接近100%。原因分析内存问题在YashanDB这类内存友好的数据库上尤其常见根源主要有这几类内存参数配置过大。共享内存或者缓冲区设置超过了物理内存的合理比例留给操作系统的余量太少一旦业务高峰来临内存瞬间被打爆。并发连接数过多导致会话私有的内存区域膨胀。单条SQL消耗过多内存比如超大排序操作、大量并发的Hash Join。操作系统overcommit策略限制导致内存分配失败。处理步骤OOM的处理要分两层第一层是紧急恢复第二层是参数调优。紧急恢复阶段确认数据库进程是否已被OOM Killer杀掉。如果进程已经没了重启实例让它恢复服务这是第一要务。重启前可以留一下dmesg -T | grep -i oom的输出确认是不是OOM导致的进程被杀。恢复服务后进入调优阶段重点检查内存相关参数。YashanDB中有不少内存参数需要关注比如数据缓冲区、共享池、排序区大小等。调优思路是给操作系统预留足够的余量一般建议数据库可用内存不要超过物理内存的80%。还要关注并发连接数的限制。连接数过大每个会话都会分配私有内存积少成多也会很可观。限制最大连接数同时让应用侧控制连接池的配置双管齐下。操作系统层面可以在合理范围内调整overcommit策略。这个调整需要谨慎评估建议在测试环境验证后再应用到生产。4. 存储与日志类故障4.1 故障五磁盘空间耗尽数据库无法写入故障现象应用写入报错提示磁盘空间不足数据库可能直接进入只读状态。数据文件的自动扩展也失败了因为底层磁盘没有剩余空间。原因分析磁盘空间耗尽的根因一般来说就三类数据文件增长超出预期。业务量增长较快自增表空间的数据文件不断扩展把磁盘打满。归档日志堆积。归档日志开启后如果归档清理策略没配置好日志不断累积把磁盘空间耗尽。临时文件和临时表空间膨胀。跑了一批大查询或大事务临时表空间暴涨。备份文件等运维产物占用。数据库备份、巡检脚本产生的临时文件被遗忘在磁盘上日积月累也很可观。处理步骤磁盘空间耗尽属于存储类紧急故障处理原则是先释放空间再考虑扩容。第一步确认磁盘空间使用情况。用df -h查看各挂载点的使用率定位是哪个目录的磁盘满了。大概率是数据目录、归档目录或者备份目录。第二步找到最容易被清理的空间。优先检查归档日志目录如果归档日志已经备份过可以清理掉过期归档其次检查临时文件和备份文件。这样可以在最短时间内释放出可用空间。第三步处理表空间扩展问题。如果是因为数据文件自动扩展失败导致的写入报错在释放空间后表空间会恢复自动扩展能力。腾出空间后再评估是否需要将数据文件迁移到更大的磁盘。第四步系统性整改。配置合理的日志清理策略限制归档日志保留时间监控表空间使用率提前扩容备份任务要设置保留策略防止备份文件无限堆积。重要提示无论空间多紧张都不要直接删除在线日志redo log文件。在线日志是数据库崩溃恢复的关键删除在线日志可能导致数据库无法恢复。清理空间时优先考虑归档日志、备份文件、临时文件这些相对安全的对象。4.2 故障六日志归档失败导致实例挂起故障现象数据库中大量事务无法提交新的写入操作全部卡住整个实例hang住。告警日志中频繁出现归档失败的报错日志切换操作一直不成功。原因分析归档失败的本质很简单就是日志写不进归档目录但引发的后果很严重。数据库在日志切换时如果归档目标不可写或者空间不足会阻塞新的日志生成进而阻塞所有写事务。具体原因可能包括归档目录磁盘空间不足日志文件写不进去。归档目录权限问题数据库进程没有写权限。归档进程异常或配置的归档目标路径失效。如果归档目标是远程存储网络故障也会导致归档失败。处理步骤归档失败导致的挂起是数据库故障中紧急程度最高的一种必须优先处理。第一步检查归档目录的空间和状态。看磁盘空间看目录是否存在、是否可写。如果空间不足立刻清理过期归档这是最快速的恢复手段。第二步检查归档进程状态。确认归档进程是否存在异常。如果归档目标配置有问题可以临时将归档参数调整到有效目录让归档流转起来。第三步尽快触发日志切换。清理完空间、恢复归档后可以手动触发日志切换验证归档是否恢复正常。如果切换成功数据库会从这个挂起状态中恢复过来。第四步排查归档目标为何不可用。是存储故障还是配置失误找到根本原因后修复避免下次再犯。5. 并发一致性与运维经验5.1 故障七锁等待与死锁导致业务卡死故障现象应用出现大面积卡顿所有操作都在等待数据库中有大量会话处于等待状态。有些场景下还会直接抛出死锁相关的错误信息事务被强制回滚。原因分析锁问题在并发场景下非常典型原因主要出在事务设计上多个事务并发更新同一行数据后到的请求要等前面的事务提交或回滚后才能继续。事务持锁时间过长。事务中执行了大量操作或者事务开启后长时间不提交把锁一直握着。应用层资源循环等待典型的死锁场景事务A锁了记录1想获取记录2事务B锁了记录2想获取记录1互相等待谁也走不下去。处理步骤锁故障的处理核心就一句话找到阻塞源头打破等待链。第一步查询当前锁等待情况。通过锁相关的动态视图找到哪些会话在等待锁、哪些会话持有锁、阻塞关系是什么。这里要特别关注阻塞者是谁也就是持锁的事务正在做什么、持锁多久了。第二步评估后处理阻塞会话。找到阻塞源头后和业务确认这个会话是否可以中断。如果可以杀掉阻塞会话让等待的请求继续执行。杀会话前一定要确认好影响如果阻塞者是关键业务的事务贸然kill可能导致该事务回滚影响也不小。第三步解除死锁。数据库检测到死锁后会自动回滚代价较小的事务但应用侧通常会收到异常报错。在应用层需要做好死锁异常的重试机制避免报错直接抛给用户。第四步从事务设计上规避锁问题。这是治本之策。尽量减少事务的持锁时间把大事务拆成小事务保证多个资源的获取顺序一致在业务低峰期执行批量更新操作。特别是在秒杀、热点账户等高度竞争的场景下要对事务并发设计做专门的评估。5.2 七类故障速查对照表为了便于日常快速查阅我把这7种故障的定位命令和应急手段整理成了一张速查表。建议把它贴在运维文档里或者打印出来放在手边。故障类型核心排查命令/手段应急处理手段实例无法启动查看告警日志、检查端口和进程、检查文件权限清理残留进程后重试不要反复强启连接数打满查询会话状态和数量清理空闲会话临时评估是否调大连接数上限慢SQL拖库抓取慢SQL、查看执行计划先kill极端耗时SQL再优化索引和SQL写法内存不足OOM查看系统日志确认OOM记录重启实例恢复服务再调整内存参数磁盘空间耗尽查看磁盘使用率和表空间使用率清理归档日志和临时文件紧急释放空间日志归档失败检查归档目录空间和归档进程状态清理归档空间恢复归档后手动触发日志切换锁等待与死锁查询锁视图定位阻塞源确认影响后kill阻塞会话应用层做好重试5.3 运维新人最容易踩的坑最后分享几个我在实战中踩过的坑。这些教训都是用线上事故换来的希望看到这篇文章的朋友不用再走同样的弯路。第一个坑磁盘满的时候去删在线日志。有一次磁盘告警某位同事为了快速释放空间把在线日志目录里的文件删了几个结果数据库直接crash恢复花费的时间比清理空间多出好几倍。记住文章前面提到的优先清理归档日志、备份文件、临时文件绝不要动在线日志。第二个坑出现问题时不保存现场直接重启。有些故障本来可以拿到完整的诊断信息一顿重启之后现场全丢了最后问题反复出现。重启是最后的应急手段不是第一排查手段。在条件允许的情况下优先把日志、视图数据、参数配置留存下来。第三个坑kill会话前不确认影响。看到一个会话卡住了就kill结果那个会话正在跑一个批处理任务kill之后任务进度归零业务方还得重跑。kill之前先查一下这个会话的SQL和事务状态确认中断代价可控再动手。第四个坑调大连接数解决问题。连接数打满就调大连接数内存不足就加内存条这些操作短期内有效但都是治标不治本。真正要解决的是连接池配置、慢SQL、事务设计这些源头问题。如果只调参数不加治理同一个故障会在不久之后以更严重的形式再次出现。第五个坑忽略监控和巡检。大部分故障在发生前都有征兆比如磁盘使用率持续攀升、慢SQL数量逐渐增加、锁等待次数变多。如果配置了完善的监控指标和定期巡检很多故障可以在影响业务之前就被发现和处理。事后救火不如事前防火这句话在数据库运维里永远是真理。数据库故障排查这门手艺靠的是平时的积累和复盘。每次故障处理完我都建议大家花点时间把过程整理成文档把当时怎么判断的、为什么这么做、后续如何预防写清楚。日积月累你会发现自己面对故障时越来越从容。对我个人来说处理故障最踏实的时刻不是把实例拉起来的那一刻而是通过日志和时序数据把根因搞明白确认它不会再来第二次的那一刻。希望这7种故障的处理思路能帮你在下次遇到问题时心里更有底。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进