AWS Glue写入本地Oracle报Connection reset的解决方案
AWS Glue写入本地Oracle 200万条数据报Connection reset报错解决方案
问题复现
执行数据同步任务向本地部署的Oracle数据库写入约200万条大规模数据集时,任务抛出如下错误:
py4j.protocol.Py4JJavaError: An error occurred while calling o318.pyWriteDynamicFrame. : java.sql.SQLRecoverableException: IO Error: Connection reset at oracle.jdbc.driver.T4CConnection.logoff(T4CConnection.java:770) at oracle.jdbc.driver.PhysicalConnection.close(PhysicalConnection.java:4585) at org.apache.spark.sql.jdbc.glue.GlueJDBCSink$.save(GlueJDBCSink.scala:43) at com.amazonaws.services.glue.util.JDBCWrapper.writeDF(JDBCUtils.scala:892) at com.amazonaws.services.glue.sinks.OracleDataSink.writeDynamicFrame(OracleDataSink.scala:20) ... Caused by: java.net.SocketException: Connection reset at java.net.SocketInputStream.read(SocketInputStream.java:210) at oracle.net.ns.Packet.receive(Packet.java:311) at oracle.jdbc.driver.T4C7Ocommoncall.doOLOGOFF(T4C7Ocommoncall.java:59) at oracle.jdbc.driver.T4CConnection.logoff(T4CConnection.java:757) ... 16 more
根因确认
- 网络链路中的防火墙将长时间无数据包传输的JDBC长连接判定为空闲失效连接主动断开,触发连接重置。该根因已在cx_Oracle驱动场景下通过配置连接保活机制验证有效。
- 临时规避方案为对DataFrame做分区,按每批次5万条小粒度分块写入,但该方案需要反复创建销毁数据库连接,执行耗时过长,无法满足性能要求。
解决方案
1. 配置AWS Glue Oracle连接保活(首选方案)
AWS Glue写入Oracle底层使用官方Oracle JDBC Thin驱动,可直接在JDBC连接URL中追加驱动原生的TCP保活参数,无需自定义代码或替换驱动,配置方式如下:
在作业代码的connection_options配置中,给JDBC URL追加保活参数:
connection_oracle18_options_source = { "url": "jdbc:oracle:thin:@//<你的Oracle地址>:1521/<服务名>?oracle.net.keepAlive=true&oracle.net.tcpKeepAliveIdle=120&oracle.net.tcpKeepAliveInterval=60", "dbtable": "<目标表名>", "user": "<数据库账号>", "password": "<数据库密码>", "batchSize": "100000" } glueContext.write_from_options( frame_or_dfc=detailHistoryMapping, connection_type="oracle", connection_options=connection_oracle18_options_source )
如果是在Glue控制台预配置的JDBC连接,直接在连接的JDBC URL字段末尾追加上述三个保活参数即可,无需修改作业代码。
参数说明:
oracle.net.keepAlive=true:开启驱动层面的TCP保活探针oracle.net.tcpKeepAliveIdle=120:连接空闲120秒后自动发送第一个保活探针,数值设置为比防火墙空闲连接超时阈值小30%以上即可oracle.net.tcpKeepAliveInterval=60:首次探针未收到响应时,每60秒重发一次探针
2. 性能&稳定性配套优化
配置保活的同时调整以下参数,可在解决连接重置问题的基础上,写入性能相比5万条手动分块方案提升1~3倍:
- 调整JDBC原生批大小:将
batchSize参数设置为50000~200000(根据Oracle服务器CPU、内存承载能力压测调整),复用连接批量提交数据,减少网络交互次数,性能远高于手动拆分DataFrame分区的方案。 - 合理开启并行写入:将待写入的DynamicFrame重分区为Glue作业分配的Executor总核数的23倍(例如作业配置为4台16核Worker,总核数64,分区数设置为128192即可),在
connection_options中配置numPartitions参数与数值一致,选择分布均匀的整型/日期型字段作为partitionColumn,多Executor并行写入,注意分区数不要过高避免打满Oracle最大连接数。 - 数据库侧双向保活配置:在Oracle服务器的
sqlnet.ora配置文件中添加SQLNET.EXPIRE_TIME=2(单位为分钟),从数据库侧主动发送保活探针,双向避免空闲连接被防火墙断开。 - 写入阶段临时降低数据库开销:数据写入前将目标表调整为
NOLOGGING模式,临时禁用非必要的二级索引、外键约束,等全量数据写入完成后再重建索引、恢复日志模式和约束,可减少60%以上的数据库侧写入开销。 - 关闭自动提交:在JDBC URL中追加参数
oracle.jdbc.autoCommit=false,由JDBC驱动按批次提交事务,减少单条提交带来的网络和事务日志开销。
内容的提问来源于stack exchange,提问作者sujays
相关产品推荐
相关产品推荐

