一 JDBC
jdbc是java连接关系型数据库的标准API,Sun公司一共定义了4种类型的JDBC,我们主要使用的是第4种,该类型的Driver完全由Java代码实现,通过使用socket与数据库进行通信。
第4种类型的JDBC底层通过socket对字节流进行操作,因此也会有一些基本网络操作,当在网络操作中遇到问题的时候,将会消耗大量的cpu资源,并且失去响应超时。
二 常见Timeout
(WAS/BLOC是具体应用名称,不需要关心)
DBCP 获取连接超时
数据库连接池getConnection获取不到
Statement Timeout
statement timeout用来限制statement的执行时长,或者statement timeout可以简单认为一次sql的执行时间控制,timeout的值通过调用JDBC的java.sql.Statement.setQueryTimeout(int timeout) API进行设置。
JDBC的超时处理,在不同的数据库里,处理是不一样的,在这里只说下mysql的,其它数据库的可以翻看传送门
处理步骤
调用connection createStatement 创建 statement
执行statement的executeQuery方法
statement通过自己的connect发送query给mysql
statement新创建一个timeout-execution线程用于进行超时处理
给statement的原有connection分配一个超时处理线程(^5.1)
向timeout-execution线程进行注册
达到超时条件
TimerThread调用JtdsStatement实例中的TsdCore.cancel()方法
timeout-execution线程创建一个同statement对应的(配置相同)connection
使用新创建的connection向超时query发送cancel query(KILL QUERY “connectionId”)
Transaction Timeout
一次事务的超时控制,一个事务由多个statement组成,简单地说,transaction timeout就是“statement Timeout * N(需要执行的statement数量) + @(垃圾回收等其他时间)”。transaction timeout用来限制执行statement的总时长。
JDBC Timeout
TCP/IP结构原因,socket无法探知网络中断,因此应用无法主动发现数据库连接断开。如果没有设置jdbc socketTimeout,应用就会一直的等待下去,这种连接被称为dead connection(坏死连接)。
不推荐使用socket timeout来限制statement的执行时长,因此socket timeout的值必须要高于statement timeout,否则,socket timeout将会先生效,这样statement timeout就变得毫无意义,也无法生效。
下面展示了socket timeout的两个设置项,不同的JDBC驱动其配置方式会有所不同。
socket连接时的timeout:通过Socket.connect(SocketAddress endpoint, int timeout)设置
socket读写时的timeout:通过Socket.setSoTimeout(int timeout)设置
mysql的socket timeout配置方式
jdbc:mysql://xxx.xx.xxx.xxx:3306/database?connectTimeout=60000&socketTimeout=60000
操作系统的socket timeout配置
操作系统可以通过socket timeout进行配置,来检测坏死socket 连接。Linux一般默认2小时。
所以有时候会发现为什么我们没有设置jdbc的socket timeou,当出现问题后过了段时间奇迹般的好了,那是因为系统帮我们重连了。
sudo sysctl -a|grep keepal
net.ipv4.tcp_keepalive_time = 7200(s)
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_intvl = 75
三 案例
系统上线了一段时间,总是时不时的报出一些慢接口、statement 超时的问题甚至出现数据库连接池获取不到连接的问题。因为这些问题是偶发性的,并且随机出现在某些一两台机器上(当前机器集群>6)又能很快的自我恢复所以没有引起重视。
短时间的连接池不够用
有一次爆发获取不到数据连接的问题,当时立马看了看GC,QPS,数据库服务器RT全部正常,但是网络出现ping丢包。
网络
数据库平均响应时间
翻阅日志发现在这段时间出现了大量的2s响应时间的接口,正是这些接口把数据库连接hang住导致连接池连接耗尽,其他请求获取不到连接。后来经过确认的确在这段时间出现了网络问题(持续1分钟),所以我们认为是网络 丢包 问题导致接口响应慢,占用数据库连接不释放,进而引发数据库连接池不够用的问题。
网络问题再次爆发,持续获取不到数据库连接
时运不济,我们的系统再次出现了接口超时的问题,而这一次却是出现了致命的故障,因为请求量太大,所以没有等系统检测socket 连接,数据库连接池已经被耗尽,在大量的请求下,故障越发的明显。
案例总结
第一个案例,我们可以认为是网络丢包问题引发连接被hold(jdbc连接没有坏死)导致其它请求获取不到连接。也有可能有部分的坏死连接(日志显示也有请求超时的异常),在低请求量下,问题被掩盖住了,等过了1分钟网络恢复,网络丢包问题没有了,对应的jdbc连接又能很快的响应。而那些坏死的连接在系统检测到后又进行了重连。第二个案例应该是第一个案例的放大版,请求量大了。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。