表空间满了却不报错——Oracle的沉默陷阱
表空间满了却不报错——Oracle的沉默陷阱故障现场城镇居民医疗系统突然卡住了。不是宕机不是报错就是写数据的时候卡在那里。前端界面转圈后台日志没异常数据库连接正常。用户打电话投诉“结算办不了病人等着出院。”检查了网络、应用服务器、数据库连接池一切正常。但就是写不进去数据。排查过程应用层排查检查Java应用日志没有异常堆栈连接池正常没有死锁。数据库层排查v$session显示会话在等待等待事件是db file sequential read——看起来像正常的IO等待。系统层排查服务器CPU、内存、IO都正常没有瓶颈。排查了两个小时最后才想到检查表空间SELECTtablespace_name,ROUND(used_space/1024/1024,2)used_mb,ROUND(tablespace_size/1024/1024,2)total_mb,ROUND(used_percent,2)used_pctFROMdba_tablespace_usage_metricsWHEREused_percent90;结果USERS表空间使用率100%。问题根源Oracle的表空间满了但写操作不报错只是卡住。这不是bug是Oracle的设计当表空间的数据文件达到最大大小且无法扩展时Oracle会让会话进入等待状态而不是立即报错。对于医疗结算系统这意味着交易卡住但系统不告警监控系统看不到异常CPU、内存、连接数都正常用户感知是系统慢而不是系统坏了解决方案紧急处理清理历史数据释放空间中期方案给表空间增加数据文件长期方案建立表空间监控告警阈值设到85%-- 增加数据文件指定固定大小不开启AUTOEXTENDALTERTABLESPACEUSERSADDDATAFILE/u01/oradata/prod/users02.dbfSIZE30G;注意AUTOEXTEND在生产环境一直是不推荐的做法。自动扩展听起来方便但会导致磁盘空间不可控——某天磁盘满了整个数据库挂掉比表空间满更难恢复。正确的做法是固定大小数据文件 监控告警 提前手动扩容。经验教训1. 监控不能只看是否存活传统监控关注CPU、内存、连接数但表空间满了这些指标都正常。需要监控表空间使用率阈值85%数据文件是否已达上限空间等待事件enq: HW - contention等2. 沉默的故障最危险报错的故障好处理不报错的故障难发现。Oracle很多静默失败场景表空间满写操作卡住归档目录满数据库挂起密码过期连接失败但不明确提示3. 政务系统的特殊性医疗结算系统不能停病人等着出院不能等7×24小时服务没有维护窗口数据不能丢事务必须完整这种场景下预防比救火重要。技术细节为什么Oracle不立即报错Oracle的存储管理是惰性的插入数据时先申请空间如果表空间不足检查数据文件是否能扩展无法扩展时会话进入等待状态等待其他会话释放空间提交或回滚超时后默认无限期等待才会报错如何立即发现-- 监控空间等待SELECTevent,count(*)FROMv$session_waitWHEREeventLIKE%space%GROUPBYevent;-- 监控已达上限的数据文件SELECTtablespace_name,file_id,blocks,maxblocksFROMdba_data_filesWHEREmaxblocksISNOTNULLANDblocksmaxblocks;总结表空间满了不报错是Oracle的一个特性不是bug。但在生产系统特别是政务医疗系统这种特性会变成致命陷阱。关键点监控表空间使用率阈值设到85%固定大小数据文件不用AUTOEXTEND靠监控手动扩容建立空间等待事件的监控告警定期清理历史数据预留缓冲空间系统不告诉你它病了等你知道时病人已经堵在结算窗口了。