1、问题描述:oracle可以连接成功,偶尔不可以或需要很长时间
在使用java连接oracle数据库(主要是oracle)时,可能会遇到一个奇怪的问题,就是偶尔可以执行,偶尔不可以,日中没有发现明显报错,且不能稳定复现,日志只有一个socket readtime timeout的错误打印出来
当这种问题出现后,尝试更改很多设置,并没有效果,可能是出现了tcp重传引发了一个更深层次的问题。
2、解决方案
2.1 原因分析
经过排查发现,此问题出现后,在不可用和可用的过程中,时间较为规律,比如最长是15分钟。并且没有其他报错,怀疑是网络连接问题
可能的原因:在客户端与数据库服务端,创建连接的过程中,在tcp握手后tls握手时,网络发生异常,导致创建连接的线程长时间卡在socketread0,无法创建新连接。导致整个连接池或连接不可用。
这种网络的异常可能是网络抖动或服务器宕机触发的tcp重传机制引发,由于客户端的操作系统tcp_retries2采用的默认值偏大,客户端最长需要924秒才能感知,双方建立的连接是无效连接
2.2 解决办法
linux操作系统的tcp_retries2默认值是15,调整该参数。
通过 /etc/sysctl.conf文件,设置 net.ipv4.tcp_retries2 为5
cat >> cat /etc/sysctl.conf << EOF
net.ipv4.tcp_retries2 = 5
EOF
sysclt -p
注:设置值之后,需要重启java服务
2.3 复现的方式和参数值
关于复现该问题的猜测,可以通过将数据库服务器直接屋里关机(不是重启和shutdown,而是直接拔掉电源),如果是虚机,用管理工具,将其电源关掉,这种方式可能能复现这个问题,但不建议过多次数使用
关于tcp_retries2参数,该参数不建议设置的太小,如果太小可能会造成频繁释放开启连接的新问题。对于绝大多数的网络环境,该参数设置为5或6都是可行的。设置为5,最多12秒就可以感知连接异常,设置为6,最多25秒感知连接异常。
在此提供一个表格:对应关系是tcp_retries2设置的值和感知需要的时长,需要错一位看,比如tcp_retries2为5,需要看6的那行
Retransmission | RTO(ms) | time before a timeout | |
---|---|---|---|
1 | 200 | 0.2 secs | 0 mins |
2 | 400 | 0.6 secs | 0 mins |
3 | 800 | 1.4 secs | 0 mins |
4 | 1600 | 3.0 secs | 0.1 mins |
5 | 3200 | 6.2 secs | 0.1 mins |
6 | 6400 | 12.6 secs | 0.2 mins |
7 | 12800 | 25.4 secs | 0.4 mins |
8 | 25600 | 51.0 secs | 0.9 mins |
9 | 51200 | 102.2 secs | 1.7 mins |
10 | 102400 | 204.6 secs | 3.4 mins |
11 | 120000 | 324.6 secs | 5.4mins |
12 | 120000 | 444.6 secs | 7.4mins |
13 | 120000 | 564.6 secs | 9.4mins |
14 | 120000 | 684.6 secs | 11.4mins |
15 | 120000 | 804.6 secs | 13.4mins |
16 | 120000 | 924.6 secs | 15.4mins |