JDBC连接超时
简述
transaction timeout
statement timeout
- statement timeout用来限制statement的执行时长,timeout的值通过调用JDBC的java.sql.Statement.setQueryTimeout(int timeout) API进行设置。不过现在开发者已经很少直接在代码中设置,而多是通过框架来进行设置。
- MySQL JDBC Statement的QueryTimeout处理过程
- 通过调用Connection的createStatement()方法创建statement
- 调用Statement的executeQuery()方法
- statement通过自身connection将query发送给MySQL数据库
- statement创建一个新的timeout-execution线程用于超时处理
- 5.1版本后改为每个connection分配一个timeout-execution线程
- 向timeout-execution线程进行注册
- 达到超时时间
- TimerThread调用JtdsStatement实例中的TsdCore.cancel()方法
- timeout-execution线程创建一个和statement配置相同的connection
- 使用新创建的connection向超时query发送cancel query(KILL QUERY “connectionId”)
socket timeout
- JDBC的socket timeout在数据库被突然停掉或是发生网络错误(由于设备故障等原因)时十分重要。由于TCP/IP的结构原因,socket没有办法探测到网络错误,因此应用也无法主动发现数据库连接断开。如果没有设置socket timeout的话,应用在数据库返回结果前会无期限地等下去,这种连接被称为dead connection。
- 为了避免dead connections,socket必须要有超时配置。socket timeout可以通过JDBC设置,socket timeout能够避免应用在发生网络错误时产生无休止等待的情况,缩短服务失效的时间
- 为了避免dead connections,socket必须要有超时配置。socket timeout可以通过JDBC设置,socket timeout能够避免应用在发生网络错误时产生无休止等待的情况,缩短服务失效的时间
- 下面展示了socket timeout的两个设置项,不同的JDBC驱动其配置方式会有所不同。
- socket连接时的timeout:通过Socket.connect(SocketAddress endpoint, int timeout)设置
- socket读写时的timeout:通过Socket.setSoTimeout(int timeout)设置
操作系统的socket timeout
- 如果不设置socket timeout或connect timeout,应用多数情况下是无法发现网络错误的。因此,当网络错误发生后,在连接重新连接成功或成功接收到数据之前,应用会无限制地等下去。但是,30分钟后应用的连接问题奇迹般的解决了。这是因为操作系统同样能够对socket timeout进行配置。因此即使JDBC的socket timeout设置为0,由网络错误造成的数据库连接问题的持续时间也不会超过30分钟(默认是30分钟)
- 如发现系统存在大量TIME_WAIT状态的连接,通过调整内核参数解决,
vim /etc/sysctl.conf
编辑文件,加入以下内容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
然后执行 /sbin/sysctl -p 让参数生效。
net.ipv4.tcp_syncookies = 1 表示开启SYN cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_fin_timeout 修改系統默认的 TIMEOUT 时间
DBCP配置
配置项 | 值 | 说明 |
---|---|---|
maxWait | 5000 | 获取连接超时时间(单位ms) |
DBCP有个连接池,每次获取连接时,都会有个等待超时时间,如果超过了就可以抛出异常。
常见异常
- java.net.ConnectException: Connection timed out–连接超时
- java.net.ConnectException: Connection read timed out–读取超时
- java.util.NoSuchElementException: Timeout waiting for idle object–DBCP等待获取conn超时