联系我们
18591797788
hubin@rlctech.com
北京市海淀区中关村南大街乙12号院天作国际B座1708室
18681942657
lvyuan@rlctech.com
上海市浦东新区商城路660号乐凯大厦26c-1
18049488781
xieyi@rlctech.com
广州市越秀区东风东路华宫大厦808号1608房
029-81109312
service@rlctech.com
西安市高新区天谷七路996号西安国家数字出版基地C座501
本手册适用于以 JDBC 作为底层数据库访问通道的数据迁移、同步或 ETL 工具,典型场景包括:
涉及目标数据库类型:OceanBase(MySQL/Oracle 模式)、Oracle、MySQL、TiDB、PostgreSQL 等。
在数据迁移、同步或批量查询过程中,任务日志中出现如下异常栈:
java.sql.SQLRecoverableException: No more data to read from socket
at oracle.jdbc.driver.T4CMAREngineNIO.prepareForReading(T4CMAREngineNIO.java:...
at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:...
...
或在 MySQL/OceanBase 驱动下可能表现为类似 CommunicationsException、SocketTimeoutException、Connection reset。
核心特征:
No more data to read from socket 本质上是 JDBC 客户端在期望继续读取数据库返回的数据时,TCP 连接被对方或中间网络设备异常关闭,导致 socket 缓冲区中没有数据可读。
从 JDBC 客户端到数据库服务端的完整链路大致如下:
[DataX/OMS JVM] --(1)--> [JDBC Driver] --(2)--> [本地 TCP 栈] --(3)--> [网卡/内核]
|
v
[客户端侧网络设备:防火墙/SLB/VPN/网关]
|
v
[服务端侧网络设备:防火墙/SLB/VPC/安全组]
|
v
[数据库服务端 TCP 栈] --(4)--> [数据库进程]
在上述链路的任意一个点,如果连接被单方面关闭、数据包丢失未被恢复、或应用层协议交互异常,都可能导致 No more data to read from socket。
socketTimeout 小于 SQL 实际执行时间,驱动在等待服务端响应时超时断开。sqlnet.expire_time、MySQL wait_timeout / interactive_timeout、OceanBase ob_query_timeout / ob_trx_timeout / connection_timeout。ob_query_timeout / max_execution_time,会话被 kill,服务端关闭连接。使用与目标数据库版本匹配的官方驱动:
oceanbase-client 或兼容的 MySQL Connector/J;oceanbase-client Oracle 模式驱动;ojdbc8 / ojdbc11 匹配数据库版本;mysql-connector-java 8.0.x 或更高。在 JDBC URL 中显式设置:
# MySQL / OceanBase MySQL 模式示例
jdbc:mysql://host:port/db?connectTimeout=30000&socketTimeout=300000
# Oracle 示例
jdbc:oracle:thin:@host:port/SERVICE?oracle.net.CONNECT_TIMEOUT=30000&oracle.jdbc.ReadTimeout=300000
建议:
connectTimeout:设为 10~30 秒;socketTimeout:根据业务 SQL 最大执行时间设置,建议比最长 SQL 执行时间稍大(如 5~10 分钟),避免过短导致正常慢查询被误杀。在 Linux 上可调整系统参数:
# 7200 秒无数据后开始探测,建议改为 60~300 秒sysctl -w net.ipv4.tcp_keepalive_time=60# 探测间隔sysctl -w net.ipv4.tcp_keepalive_intvl=10# 探测次数sysctl -w net.ipv4.tcp_keepalive_probes=6
在 Windows 上:
# 查看当前 keepalive 时间(毫秒)
netsh int tcp show global
# 设置 keepalive 时间为 60 秒(60000 毫秒)
netsh int tcp set global keepalivetime=60000
注意:仅调整操作系统参数还不够,必须确认 JDBC 驱动是否开启 SO_KEEPALIVE。部分驱动默认不开启,可通过自定义 SocketFactory 或 Java 启动参数控制。
| 设备类型 | 配置项 | 建议 |
|---|---|---|
| 云厂商 SLB | 空闲连接超时 | 设置为 >= 600 秒,或在迁移期间临时关闭空闲超时 |
| NAT 网关 | 会话老化时间 | 调大或配置长连接保持 |
| 防火墙 | 空闲会话超时 | 放行 JDBC 端口长连接,关闭相关超时或调大 |
| VPN/专线 | DPD/保活间隔 | 开启并缩短探测间隔 |
SELECT 1 或 SELECT 1 FROM DUAL 心跳,保持连接活跃;ping -M do -s 或 iperf3 验证网络质量。OceanBase:
ob_query_timeout:单条语句超时,单位微秒;ob_trx_timeout:事务超时;ob_tcp_invited_nodes:确保客户端 IP 在白名单内;__all_server / __all_virtual_processlist 观察会话是否被 kill。MySQL:
wait_timeout、interactive_timeout:空闲连接超时;net_read_timeout、net_write_timeout:网络读写超时。Oracle:
sqlnet.expire_time:建议设置为 10 分钟以内,用于探测死连接;sqlnet.inbound_connect_timeout、sqlnet.outbound_connect_timeout。WHERE 切分、splitPk 分片,控制单次查询数据量;gv$sql_audit 和 __all_virtual_processlist,确认是否有会话因超时被终止。socketTimeout、connectTimeout 是否合理;jdbc:mysql://host:port/db?useUnicode=true&characterEncoding=UTF-8&connectTimeout=30000&socketTimeout=300000&autoReconnect=true&failOverReadOnly=false
jdbc:oceanbase:thin:@host:port:schema?user=&password=&connectTimeout=30000&socketTimeout=300000
jdbc:oracle:thin:@(DESCRIPTION=(ENABLE=BROKEN)(CONNECT_TIMEOUT=30)(TRANSPORT_CONNECT_TIMEOUT=30)(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=host)(PORT=port)))(CONNECT_DATA=(SERVICE_NAME=service)))
Oracle 可在 tnsnames.ora 或 JDBC URL 中配置
ENABLE=BROKEN以启用 keepalive。
jdbc:mysql://host:port/db?useSSL=false&serverTimezone=Asia/Shanghai&connectTimeout=30000&socketTimeout=300000&autoReconnect=true&maxReconnects=3&initialTimeout=10000
java.sql.SQLRecoverableException: No more data to read from socket 是一个典型的 连接在读取数据过程中被异常关闭 的问题。排查时应从客户端、网络、服务端三个层面入手,重点检查:
通过抓包定位连接关闭发起方,通常可以快速锁定问题根因。