十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

达梦数据库Communication error排查全攻略:从网络到连接池的实战指南

达梦数据库Communication error排查全攻略:从网络到连接池的实战指南 1. 一次凌晨两点的突然连不上Communication error 的典型现场先说一个我印象特别深的案例。有个系统上线已经跑了半年多某天凌晨两点值班同事在群里发了张报错截图核心异常就是dm.jdbc.driver.DMException: Communication error。业务方的第一反应是数据库挂了但登录服务器一看dmserver进程还在端口也 listening表面一切正常。可应用端就是反复报错重启应用也不行。这种诡异场景在达梦数据库的日常运维里并不少见。Communication error这个错误信息非常笼统它不像ORA-12541: TNS:no listener那样能直接告诉你监听不存在也不像Communications link failureMySQL那样有一长串辅助诊断信息。它就是一句话客户端和数据库服务器之间的通信链路出了问题。但具体是网络不通、端口被防火墙拦了、数据库实例异常、驱动版本不对、还是连接池把空闲连接干掉了全靠你自己去拆。本篇文章我打算把这条排查路径完整走一遍。文章面向的对象是那些正在被dm.jdbc.driver.DMException: Communication error困扰的开发者、DBA、运维工程师。我会从这个异常到底是什么讲起再到怎么按链路逐层排查最后给出几个真实的案例复盘。力求让你下次再看到这个报错时能直接按图索骥而不是像无头苍蝇一样先重启一遍所有服务。2. 先别慌Communication error 到底是什么2.1 它是错误更准确说是错误的总集合达梦 JDBC 驱动DmJdbcDriver.jar内部有一套自定义的异常体系。dm.jdbc.driver.DMException是所有数据库端抛出异常的基类而Communication error是驱动内部定义的一个通用错误标识一般配合的错误码是6001或类似编号。遇见这个错误时驱动层的意思是它发给服务端的请求没有得到预期的响应或者连接本身已经被对端重置。驱动并不清楚底层发生了什么只能把通信失败这一结果反馈给应用。所以在排查方向上你必须建立几个基本认知能发起连接请求说明应用服务器的 JDBC URL 配置基本成型报错发生在通信阶段说明要么 TCP 层没握手成功要么握手成功但数据交换异常服务端进程活着不代表服务端可用。有时候数据库进程在但线程池、日志空间、锁等待已经到了崩溃边缘无力接受新连接。2.2 驱动分层结构里Connection error 的不同阶段达梦 JDBC 驱动建立连接的过程大致分三个阶段TCP 建连阶段驱动通过jdbc:dm://IP:PORT发起 Socket 连接这个阶段失败通常是网络问题报错可能是Connection refused或Connection timed out但也可能统一表现为Communication error。协议握手阶段TCP 已通驱动向服务端发送协议握手包。如果服务端端口监听的是一个非达梦服务例如被别的进程占用或者达梦服务正在启动早期响应不正确就会报通信错误。会话认证阶段如果数据库繁忙、内存分配失败、授权文件失效dm.key过期服务端可能在认证过程中异常中止连接驱动同样会抛出Communication error。所以当你看到Communication error时实际上要在这三个阶段里找问题。这也是为什么我建议别盯着报错本身去搜——因为你能搜到的解决方案五花八门而每个方案适用的阶段根本不同。3. 第一次复盘网络链路的排查90% 的错误出在这里3.1 从ping开始但别止于ping我见过不少同事遇到Communication error第一反应就是ping目标 IP。ping通只能证明 ICMP 可达而 JDBC 走的是 TCP所以第二步要立刻测试端口连通性。在 Linux 应用服务器上执行telnet 192.168.1.100 5236或者用ncnc -vz -w 5 192.168.1.100 5236达梦数据库默认端口是5236如果返回Connection refused说明端口不对或者服务端确实没有监听。如果返回Connection timed out说明中间链路防火墙、安全组、路由大概率拦截了请求。提示达梦提供dmrman和dm_svc.conf相关工具但它们更多用于管理和服务名解析最快速判断端口还是telnet和nc。3.2 服务端有没有真正监听登录数据库服务器执行netstat -anp | grep 5236 ss -tunlp | grep 5236正常情况会看到类似tcp LISTEN 0 128 0.0.0.0:5236 0.0.0.0:*如果这里显示的不是LISTEN而是别的状态或者根本没有输出那么要么是dmserver进程没起来要么是dm.ini里配置的监听端口被改动了。这里提一个容易忽略的地方达梦支持多个实例你ps -ef | grep dmserver看到的进程不一定监听在你以为的端口上。用netstat确认端口与进程 PID 的对应关系比直接搜进程更可靠。3.3 服务器本机连接测试这是排查里非常关键的一步在数据库服务器本机使用达梦自带的disql工具连接cd /opt/dmdbms/bin ./disql SYSDBA/SYSDBAlocalhost:5236如果本机能连而远程连不上问题基本锁定在网络层。如果本机也连不上那就要进入第四步检查数据库服务本身。3.4 防火墙和安全组很多生产环境会启用firewalld或iptables云上环境还有安全组规则。检查方法# firewalld firewall-cmd --list-all # iptables iptables -L -n | grep 5236特别注意双网卡场景应用服务器连接的是业务网 IP但dmserver启动时绑定的地址是0.0.0.0还是具体网卡 IP直接影响能否从业务网访问。有些部署案例里DBA 把服务绑在了内网管理网段业务网自然无法访问。3.5 负载均衡和中间件网络设备如果应用通过负载均衡如 LVS、Nginx 四层代理、F5连接数据库那故障点又多了一层。我有一次排查到深夜最后发现是 LVS 的 RS真实服务器健康检查配置错误认为数据库节点宕机把流量导向了一个空的备用 IP。这种场景下应用端看到的始终是Communication error因为 TCP 连接发送到无人监听的主机内核直接返回 RST。排查这类问题需要看应用端到数据库端的完整网络路径图。如果是容器环境或 K8s再叠加一层 Service 和 Endpoints 的映射关系复杂度会成倍上升。4. 服务端状态的体检dmserver 的暗病4.1 进程在不代表一切正常dmserver进程存在端口也 LISTEN但连接仍然失败常见原因有这么几类。第一数据库实例处于 MOUNT 或 SUSPEND 状态。达梦数据库实例有 OPEN、MOUNT、SUSPEND 等状态。如果之前做过恢复操作没完成实例可能停在 MOUNT 状态此时无法接受正常的用户连接。用disql查询SELECT STATUS$ FROM V$INSTANCE;STATUS$字段为OPEN才正常如果是MOUNT或SUSPEND需要执行对应的ALTER DATABASE OPEN;操作。第二授权文件失效。达梦数据库的授权文件dm.key有有效期。授权过期后数据库服务可能仍在运行但新连接会被拒绝而且服务端日志里会记录授权问题。检查授权状态cd /opt/dmdbms/bin ./dmkeycheck授权过期这个问题在测试环境特别常见测试库装完跑了一年多某天突然连不上怎么查都查不到原因最后发现是试用授权到期。这种暗病靠网络排查永远找不到根因。第三数据库归档日志空间满。如果开启了归档模式ARCH_MODE1而归档空间被写满达梦数据库为了保证数据一致性会挂起所有新事务反映到连接层就是无法建立新的会话。查看归档相关的系统函数SELECT * FROM V$ARCHIVED_LOG; SELECT * FROM V$ARCHIVE_DEST_STATUS;或者直接在dm.ini中确认归档目录配置ARCH_DEST和空间使用情况。清理方式是在确保归档已被备份的前提下删除或转移旧的归档日志文件。4.2 服务端日志里藏着真正的报错达梦运行日志默认在安装目录下的log文件夹中文件名格式类似dm_实例名_日期.log。排查Communication error时一定要登录服务器去看这个日志。很多异常在客户端只表现为一句话但服务端日志会详细记录2025-XX-XX 14:23:11.123 [ERROR] session 12345 login fail, error code: -1234, reason: invalid username or password如果你看到login fail相关的记录那问题就从通信变成了认证这是完全不同的排查方向。4.3 参数配置陷阱MAX_SESSIONS与MAX_SESSION_STATEMENT达梦数据库在dm.ini中有几个参数控制会话资源MAX_SESSIONS最大会话数默认值通常是 100。MAX_SESSION_STATEMENT单个会话允许的最大语句数。当连接数达到上限时新的连接请求会被拒绝客户端表现就是握手失败或连接中断。查看当前会话数SELECT COUNT(*) FROM V$SESSIONS;与MAX_SESSIONS对比。如果接近上限要么扩容要么排查是不是有应用没关闭连接导致连接泄漏。5. 连接配置与连接池背锅侠还是真凶5.1 JDBC URL 写没写对达梦 JDBC 的 URL 格式jdbc:dm://192.168.1.100:5236?compatibleModeoraclecharacterEncodingutf-8有几个参数容易引起问题connectTimeout单位毫秒默认可能是 0无限等待某些场景下网络闪断会导致驱动长时间阻塞应显式设置比如connectTimeout3000。socketTimeout与通信超时相关如果业务本身有长事务设置过小会在运行中报Communication error。5.2 连接池探活机制与数据库的默契这是最常见、也最隐蔽的坑之一。许多应用使用 Druid、HikariCP 或 DBCP 管理连接。连接池为了维持可用性会定期发送探测语句比如SELECT 1。如果连接池的validationQuery配置不当或者空闲连接回收时间idleTimeout与数据库端的SESSION_TIMEOUT不匹配就可能出现数据库端空闲超时主动断开了物理连接连接池并不知情还认为连接可用应用从连接池拿到死连接执行 SQL驱动发现对端已关闭抛出Communication error。这种问题的显著特征是系统跑着跑着突然报错重启应用后恢复过一段时间又复发。解决方案是在连接池配置中加好探活参数。以 HikariCP 为例spring: datasource: hikari: connection-test-query: SELECT 1 idle-timeout: 60000 max-lifetime: 1800000核心原则连接池的max-lifetime必须小于数据库端的会话超时时间。假设达梦的SESSION_TIMEOUT是 2 小时那么连接池max-lifetime应设置为 1.5 小时左右确保连接池在数据库踢掉连接之前主动重建。5.3 连接池参数怎么配才稳下面是达梦数据库环境下一份经过生产验证的连接池参考配置以 Druid 为例参数推荐值说明initialSize5初始连接数避免冷启动排队minIdle5最小空闲连接maxActive50最大活跃连接结合业务压测调整maxWait60000获取连接超时单位毫秒validationQuerySELECT 1探活 SQL达梦兼容此语法testWhileIdletrue空闲时检测建议开启timeBetweenEvictionRunsMillis60000每隔多少毫秒检测一次空闲连接minEvictableIdleTimeMillis300000连接最小可空闲时间phyTimeoutMillis1800000物理连接最大存活时间必须小于达梦会话超时这份配置我用了两年多除了网络本身故障外几乎没有因为连接池问题报过Communication error。6. 驱动版本一个容易被忽略的兼容性问题6.1 高版本数据库配低版本驱动通信协议对不上达梦数据库的 JDBC 驱动DmJdbcDriver.jar也分版本。达梦 8.1 对应旧版驱动和达梦 8.1 的协议如果你拿它去连达梦 9如果存在或中间小版本跨度很大的数据库可能出现协议不兼容。驱动版本查看方式解压DmJdbcDriver.jar查看META-INF/MANIFEST.MF或驱动类dm.jdbc.driver.DmDriver的版本信息。也有更简单的方式在 Java 代码里打印Class.forName(dm.jdbc.driver.DmDriver); Driver dmDriver new dm.jdbc.driver.DmDriver(); System.out.println(dmDriver.getMajorVersion() . dmDriver.getMinorVersion());从达梦官网或安装目录drivers/jdbc下获取对应版本驱动。安装目录里的驱动通常与数据库版本严格匹配优先使用这个。6.2 Java 版本与驱动的不兼容这个问题比协议不兼容更隐蔽。达梦 JDBC 驱动从某版本开始对 JDK 版本有要求。如果你的应用跑在比较老的 JDK 上而驱动是比较新的版本加载时可能不报错但连接过程中某些加密或认证逻辑在旧 JVM 上执行异常最终抛出的异常就是Communication error。排查方式是换一个已知能工作的环境组合进行交叉测试用新驱动连老数据库用老驱动连新数据库换不同的 JDK 版本运行同一段连接测试代码。锁定问题后要么升级 JDK要么换对应版本的驱动。7. 真实案例复盘之一连接池的死连接循环7.1 现象描述某业务系统每天上午 10 点到 11 点定时报dm.jdbc.driver.DMException: Communication error每次持续几分钟后自行恢复。应用日志里有大量从连接池获取连接失败的记录且报错时间点与业务高峰基本重合。7.2 排查过程第一步查看服务端日志。达梦日志没有明显异常没有login fail大量记录。第二步检查数据库会话数。用disql登录后执行SELECT COUNT(*), STATUS$ FROM V$SESSIONS GROUP BY STATUS$;发现大量会话处于ACTIVE状态总数接近MAX_SESSIONS。第三步查看连接池配置。发现应用连接池maxActive设置为 100与数据库MAX_SESSIONS上限几乎一样。业务高峰时应用程序持有连接执行慢 SQL连接池占满新请求等待获取连接超时部分连接池内的物理连接又被提前断开于是报Communication error。7.3 解决方法将maxActive调到 50留出 50 个会话余量给管理操作和 disql优化慢 SQL降低单个事务的持连接时间连接池maxWait从默认值调低到 5 秒快速失败避免线程无限期等待。处理后问题消失。这个案例虽然不算复杂但它说明了一个很重要的问题应用连接池与数据库参数必须整体考虑单独调整任何一端都可能掩盖问题而不是解决它。8. 真实案例复盘之二网络设备的链路空闲回收8.1 现象描述某测试环境数据库和应用服务器在同一机房但中间经过了两台防火墙。测试人员发现只要一段时间不用超过 30 分钟再去点页面就会报Communication error刷新一次或等待几秒后又恢复正常。8.2 排查过程端口连通性正常telnet能通数据库日志无异常数据库会话数远低于上限。把应用和数据库放在同一台服务器上测试发现长时间不用后连接依然保持正常。初步判断问题出在网络硬件。查看防火墙会话超时配置发现该设备对空闲 TCP 连接默认回收时间是 30 分钟。连接被设备静默清除后客户端并不知道下次使用时发送数据包得不到响应超时后驱动抛出Communication error。8.3 问题根因与解决方案根因TCP 长连接被中间网络设备静默回收客户端和服务端都没有感知。解决方案有两条路修改防火墙空闲超时时间调大到超过业务最大空闲时间应用侧启用 TCP KeepAlive在系统层面让连接定期活跃。Java 侧可以通过自定义Socket工厂设置 KeepAlive但更通用更简单的方案是在 JDBC URL 上配合连接池的探活机制确保空闲连接在防火墙回收前被主动重建或探测。这个案例提醒我们网络设备把连接静默丢弃时最可怕的一点是它不留任何日志你从数据库日志、应用日志、系统日志三个方向都看不到直接线索只能通过排除法逐步锁定。9. 总结与最后一步有效的处置顺序Communication error这类报错本身简单但背后的成因非常发散。我在实际排查中踩过的坑比顺利的排查多得多。有一套固定的处置顺序可以直接帮你少走弯路第一步确认服务端进程和端口。ps -ef | grep dmserver netstat -anp | grep 5236第二步本机disql连接测试。cd /opt/dmdbms/bin ./disql SYSDBA/SYSDBAlocalhost:5236这步能快速区分数据库问题还是网络问题。第三步检查数据库状态和授权。SELECT STATUS$ FROM V$INSTANCE;./dmkeycheck第四步查看服务端日志。根据时间点匹配客户端报错与服务端日志找到服务端视角下的真实失败原因。第五步检查连接池配置与数据库会话数上限的匹配度。第六步交叉测试驱动版本。最后再分享一个小技巧如果你的项目环境允许上报错误时尽量把完整堆栈贴出来包括 Caused by 链。dm.jdbc.driver.DMException: Communication error通常只是最外层包装Caused by 里可能带有SocketException: Connection reset或SocketTimeoutException这些底层异常能帮你把问题范围缩小一半。不要一上来就重启服务。重启能暂时恢复但掩盖了真实根因。治标不治本的做法往往会在业务最忙碌的时候反噬你。
返回列表