ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

达梦数据库“网络通信异常“排查实战

达梦数据库“网络通信异常“排查实战 达梦数据库网络通信异常排查实战适用场景应用日志出现dm.jdbc.driver.DMException: 网络通信异常/SocketTimeoutException: Read timed out。按实际排查顺序组织每步给出命令和判断标准。0. 先看懂这个报错典型堆栈长这样关键看最下面的Caused byorg.springframework.dao.DataAccessResourceFailureException: ### Error querying database. Cause: dm.jdbc.driver.DMException: 网络通信异常 ### SQL: SELECT ... WHERE (ALARM_ID ?) ... Caused by: java.net.SocketTimeoutException: Read timed out这句话的含义客户端把 SQL 发给数据库了但在超时时间内没等到回包。它不等于网络断了。实际原因按概率排序SQL 执行太慢本次案例的根因索引失效 → 全表扫描 2400 万行数据库太忙/卡顿备份、批量任务、磁盘 IO 打满网络链路问题中间代理掐断、丢包。先看报错发生在哪个环节能立刻缩小范围报错位置大概率原因获取连接/建立连接时网络不通、端口、连接池耗尽执行 SQL 时Read timed out慢 SQL 或 DB 忙本次案例空闲很久后第一次用就报Connection reset/ EOF空闲连接被中间件nginx/防火墙掐断第 1 步收集基本信息从日志里摘出来报错的完整 SQL堆栈里### SQL:后面就是原句报错时间点是随机的还是集中在整点/固定时间集中在 0 点、6 点 → 强烈暗示和定时批量任务有关是单个请求偶发还是多个线程同一秒集中报错集中报错 大家同时变慢指向 DB 侧或共性资源不是个别连接问题。本次案例报错集中在00:00:10和06:01:45~06:02:41多个 gRPC 线程同一秒内集体超时——这个特征最后证明是批量并发 慢 SQL的典型表现。第 2 步排除空闲连接被掐断嫌疑看连接池配置本项目application.yml生产配置在服务器/xx/xxxx/application.ymldruid:test-on-borrow:true# 借连接前先发 SELECT 1 FROM DUAL 验证test-while-idle:true# 空闲连接定期验证validation-query:SELECT 1 FROM DUALtime-between-eviction-runs-millis:10000min-evictable-idle-time-millis:30000# 空闲 30s 驱逐max-evictable-idle-time-millis:60000# 空闲 60s 强制关闭判断逻辑配了test-on-borrow: true的每次拿连接都会先验证一遍。如果连接已被中间件掐死验证那一步就会失败并换新连接轮不到执行真实 SQL 时才报错。堆栈显示失败点在execute执行真实 SQL→ 说明连接是活的 → 排除空闲连接问题。配了max-evictable-idle-time-millis: 60000的空闲连接 60 秒就被物理关闭重建中间件根本没机会掐断池内连接。配置陷阱本次踩过yml 里写了keep-alive-between-time-millis: 30000但 IDEA 提示Cannot resolve property——这个警告是真的dynamic-datasource-spring-boot-starter3.5.x 的DruidConfig类里没有这个字段Spring Boot 默认静默忽略未知配置不写进日志也不报错。第 3 步数据库侧日志——DB 有没有卡死在 DB 服务器上cd/xxxxxx/dmdba/dmdbms/logls-lht# 实例日志一般是 dm_DMSERVER_YYYYMM.log# 提取报错时间窗口的完整日志不要只 grep 关键字先看全貌awk/^2026-09-23 05:5[5-9]/,/^2026-09-23 06:15/dm_DMSERVER_202609.log# 再找异常行awk...dm_DMSERVER_202609.log|grep-inEerror|fatal|fail|hang|timeout|killcheckpoint 节奏判断本次踩过的坑SELECTPARA_NAME,PARA_VALUEFROMV$DM_INIWHEREPARA_NAMELIKECKPT%;CKPT_INTERVAL180表示每 180 秒一次 checkpoint 是正常节奏。看到日志里 3 分钟空档不要急着判DB 卡死先对一下这个参数。如果 checkpoint 在报错窗口内正常执行时间戳连续、有checkpoint end说明DB 进程当时活着且在正常干活DB 整体卡死基本排除。查库内定时作业备份、归档清理等排除它们的干扰时段SELECT*FROMSYSJOB.SYSJOBS;-- 有哪些作业SELECT*FROMSYSJOB.SYSJOBHISTORIES2ORDERBYSTART_TIMEDESCLIMIT50;-- 最近执行记录本次案例备份在 22:00/23:00报错在 00:00/06:00时间不重合 → 库内作业排除。报错窗口内 checkpoint 正常 → DB 卡死排除。第 4 步给报错的 SQL 做体检4.1 表有多大SELECTCOUNT(*)FROM模式名.表名;-- 本次2377 万行4.2 看执行计划/xxxxxx/dmdba/dmdbms/bin/disql 用户名localhost:5236计划怎么看记两个关键字就够关键字含义好坏CSCN2全表扫描把整表读一遍再过滤大表上出现 危险SSEK2索引查找精准定位正常完整的计划阅读教程见文末【附 4】。本次案例WHERE ALARM_ID?的 SQL 计划是CSCN2 ... 24062124扫 2400 万行实测单条耗时7~9 秒——病根浮出水面。4.3 手动跑一遍计时disql 里直接执行原 SQL看used time。多跑几次取稳定值。4.4 索引三层检查-- ① 有没有索引SELECTINDEX_NAME,UNIQUENESSFROMDBA_INDEXESWHERETABLE_OWNER模式名ANDTABLE_NAME表名;-- ② 索引建在哪些列上SELECTTABLE_NAME,INDEX_NAME,COLUMN_NAME,COLUMN_POSITIONFROMDBA_IND_COLUMNSWHERETABLE_OWNER模式名ANDTABLE_NAME表名;-- ③ ★索引状态是不是 VALID本次的根因就藏在这里SELECTOBJECT_NAME,STATUSFROMDBA_OBJECTSWHEREOWNER模式名ANDOBJECT_TYPEINDEXANDSTATUSVALID;-- ④ 索引段大小几千万行的索引应该是几百 MB~GB 级1MB 空壳SELECTSEGMENT_NAME,BYTES/1024/1024ASMBFROMDBA_SEGMENTSWHEREOWNER模式名ANDSEGMENT_NAMELIKEINDEX_UWMATI%202609;本次案例索引存在列也对但STATUS INVALID、字段只有 1MB——是个空壳优化器根本用不了它。4.5 统计信息检查SELECTTABLE_NAME,NUM_ROWS,LAST_ANALYZEDFROMDBA_TABLESWHEREOWNER模式名ANDTABLE_NAME表名;NUM_ROWS0但实际有几千万行 统计信息失真会导致优化器选错计划。修复DBMS_STATS.GATHER_TABLE_STATS(模式名,表名);-- 或 DM 原生语法STAT 100 ON 模式名.表名;4.6 对照实验找一张同结构的老表上月分表跑同一条 SQL 的 EXPLAINEXPLAINSELECTIDFROM模式名.表名_202608WHEREALARM_IDxxxx;本次案例老表SSEK2走索引代价 1新表CSCN2全表扫代价 3297——同样的表结构和 SQL命运不同 → 问题一定出在新表自身的状态上和 SQL 写法无关。这一步直接终结了是不是 ORDER BY 导致不走索引的争论。第 5 步修复-- INVALID 索引重建会全量扫表重建索引段2400 万行约 1~2 分钟ALTERINDEX模式名.INDEX_UWMATI_ALARM_ID_202609 REBUILD;注意重建期间新旧索引段短暂并存先确认表空间剩余空间参照同表老月份的索引段大小批量生成所有坏索引的重建命令SELECTALTER INDEX ||OWNER||.||OBJECT_NAME|| REBUILD;ASCMDFROMDBA_OBJECTSWHEREOWNER模式名ANDOBJECT_TYPEINDEXANDSTATUSVALID;查出来几条就修几条结果为 0 行才算清完别只修报错 SQL 用到的那一个。第 6 步验证修复后按四层验收状态DBA_OBJECTS.STATUS VALID计划EXPLAIN 出现SSEK2 索引名不再有CSCN2耗时真实 SQL 从秒级降到毫秒级实战窗口在原本报错的时间点本次是 0 点、6 点观察应用日志网络通信异常不再出现才算闭环。附 1本次故障完整因果链建表脚本迁移工具生成里 CREATE INDEX 带 UNUSABLE 关键字 → 9 月新表的索引建出来就是 INVALID 空壳1MB没人做 REBUILD → 优化器用不了索引WHERE ALARM_ID? 只能全表扫描 → 9 月表从 0 涨到 2400 万行单条查询从毫秒涨到 7~9 秒 → 平时请求零散7 秒没超客户端超时看着正常 → 每天 0 点/6 点上游批量任务并发打进来几十条全表扫描互相抢 IO → 每条拖到几十秒集体越过读超时阈值 → 应用日志爆发网络通信异常: Read timed out为什么数据量越大报错越频繁全表扫描耗时和行数成正比。为什么修连接池没用连接一直是好的病在 SQL 执行速度。连接池校验test-on-borrow检查的是电话线通不通本次的问题是电话打通了但对方半天不说话。附 2排查方法论小结 transferable 到任何数据库问题读完整报错尤其Caused by链——它往往比表面错误名诚实。先分类再动手连接问题 / 慢 SQL / DB 卡死 / 网络问题每类的证据特征不同见第 0 节的表。每个猜想都要设计一个能证伪它的实验做完看结果再决定下一步。本次依次证伪了连接池配置未生效查了依赖源码→ 空闲连接被掐test-on-borrow 逻辑推理→ DB 进程卡死checkpoint 节奏参数核对→ ORDER BY 写法问题去掉 ORDER BY 仍全表扫→ 统计信息失真收完计划不变→ 最终落到索引 INVALID。对照实验是最强武器找同结构的健康对象上月表跑同一条 SQL一次对比胜过十次猜测。配置改动必须验证生效IDEA 的Cannot resolve property警告不是误报未知配置会被静默忽略。时间点特征是金线索报错总在整点/固定时间 → 优先怀疑定时任务 慢查询的组合。附 3如何看懂执行计划是什么、怎么跑EXPLAIN SQL让数据库把打算怎么执行这条 SQL的计划打印出来——只编译、不真正执行随便跑不伤数据。注意有些 web 控制台会把 EXPLAIN 当非查询语句拒绝报Error 9005: 非查询SQL语句这时去 DB 服务器上用 disql/xxxxxx/dmdba/dmdbms/bin/disql 用户名localhost:5236 SQLEXPLAIN SELECT...;附 4案例二COMMIT 超时存储 IO 抖动2026-09-26 发生的第二次同类报错根因与案例一完全不同形态和查法也不同一并固化。症状特征org.springframework.transaction.TransactionSystemException: Could not commit JDBC transaction Caused by: dm.jdbc.driver.DMException: 网络通信异常 at dm.jdbc.a.a.commit(DBAccess.java:249) ← 关键卡在 COMMIT不是卡在执行 SQL Caused by: java.net.SocketTimeoutException: Read timed out与案例一的区分点堆栈里是commit(DBAccess.java:xxx)提交阶段而不是executeInner执行阶段。说明 SQL 已执行完死在等事务提交的回执。为什么 COMMIT 会卡数据库 WAL预写日志机制COMMIT 必须等 redo 日志落盘成功才能回执客户端。redo 盘一旦卡顿所有提交排队 → 客户端读超时 → 报网络通信异常。决定性证据DB 实例日志里的刷盘告警awk/^2026-09-26 20:3[0-9]/,/^2026-09-26 20:40/dm_DMSERVER_202609.log看到这种行就是事件真相[WARNING] rlog4_write_to_file rlog_pkg[...] uses 1877ms, pkg_len:4096含义4KB 的 redo 写入花了 1.8 秒正常为毫秒级。本次窗口 10 分钟内出现 22 次1~4.3 秒/次同时 checkpoint 耗时从 0.1 秒涨到 5~11 秒、节奏迟到——存储抖动造成。形态特征与案例一区分案例一索引 INVALID案例二IO 抖动卡在执行 SELECTCOMMIT 提交形态每天定时窗口必现瞬时几次自行消失时间0 点/6 点批量时刻随机DB 日志干净rlog4_write_to_file uses XXXms告警排查命令# 告警是否常态、从何时开始按 日期小时 统计greprlog4_write_to_filedm_DMSERVER_YYYYMM.log|awk{print $1 substr($2,1,2)}|sort|uniq-c# 磁盘当时状态sar-d-p-f/var/log/sa/sa日|lessdmesg-T|grep-iEi/o error|blocked|hung|taildf-h;lsblk# 确认 redo 盘与备份盘是否同一块盘IO 互相抢数据一致性检查COMMIT 超时 客户端不知道服务端到底提交成没成可能已提交只是回执丢失。上游若重试可能产生重复数据——报错时间窗口的业务数据要抽查一遍。处置方向确认抖动源云盘类型/积分、同盘 IO 争抢、宿主争抢后对症处理换高性能盘、备份与数据分盘等把rlog4_write_to_file告警纳入监控出现即告警它比应用报错更早暴露存储问题应用侧不用为此改连接池配置——这既不是连接问题也不是 SQL 问题。本次问题的真实计划对比修复前——注意第 5 行1 #NSET2: [4376, 1, 329] 2 #PRJT2: [4376, 1, 329]; exp_num(12), is_atom(FALSE) 3 #SORT3: [4376, 1, 329]; key_num(1), top_flag(1) 4 #SLCT2: [4375, 1, 329]; 表名.ALARM_ID 5000_... 5 #CSCN2: [4375, 24062124, 329]; INDEX33557234(表名); btr_scan(1)执行顺序⑤ 扫表2400 万行全读→ ④ 过滤 ALARM_ID → ③ 排序 → ② 选列 → ① 输出CSCN2后面跟着的INDEX33557234是主键聚集索引——“沿着主键把整表读一遍”别被INDEX这个词迷惑本质还是全表扫代价4375实测 7~9 秒。修复后正常6 #SSEK2: [2, 131, 48]; scan_type(ASC), INDEX_UWMATI_ALARM_ID_202609(...), scan_range[UWMAI.ALARM_ID, UWMAI.ALARM_ID]直接写着用了哪个索引scan_range[5000_...,5000_...] 只扫索引里等于该值的一小段代价2实测毫秒级。代价差 2000 倍与实测耗时完全对应。常见节点速查表CSCN 不是原罪大表上的 CSCN 才是。判断顺序永远是先看表多大COUNT(*)再看计划。节点含义CSCN2全表扫描SSEK2二级索引范围查找BLKUP2回表按行号回表取索引里没有的列SLCT2过滤把扫描出来的行按条件筛SORT3排序top_flag(1) LIMIT 的 top-N 优化PRJT2投影挑出 SELECT 要的列NSET2结果集封装输出HASH JOIN/INDEX JOIN SEMI JOIN两表关联方式SEMI JOIN 来自 EXISTS/NOT EXISTS明明有索引却不走的排查清单按本次实战验证过的顺序索引是不是 INVALID/空壳★本次根因SELECTOBJECT_NAME,STATUSFROMDBA_OBJECTSWHEREOWNER模式名ANDOBJECT_TYPEINDEXANDSTATUSVALID;-- 结果为 0 行才正常有记录就用 ALTER INDEX owner.索引名 REBUILD; 修复辅助确认空壳大表的索引段应是几百 MB~GB 级1MB 空壳SELECTSEGMENT_NAME,BYTES/1024/1024ASMBFROMDBA_SEGMENTSWHEREOWNER模式名ANDSEGMENT_NAMELIKE索引名%;统计信息是不是失真DBA_TABLES里NUM_ROWS0但表实际有几千万行 →DBMS_STATS.GATHER_TABLE_STATS(模式名,表名);列上有没有套函数、有没有隐式类型转换如字符串列传了数字查询命中行数占比太大如要查出全表 30% 的行——这种情况 CSCN 是正确选择别硬逼它走索引LIKE %xxx%这类写法天生用不上 B 树索引。
返回列表