本手册适用于以 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 是一个典型的
连接在读取数据过程中被异常关闭 的问题。排查时应从客户端、网络、服务端三个层面入手,重点检查:
通过抓包定位连接关闭发起方,通常可以快速锁定问题根因。
如果在操作过程中遇到问题,欢迎在评论区留言交流,后续我们会持续分享更多实战运维干货,记得 关注不迷路 ,下次见~
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70047467/viewspace-3183525/ ,如需转载,请注明出处,否则将追究法律责任。