1

一 JDBC

jdbc是java连接关系型数据库的标准API,Sun公司一共定义了4种类型的JDBC,我们主要使用的是第4种,该类型的Driver完全由Java代码实现,通过使用socket与数据库进行通信。

clipboard.png

第4种类型的JDBC底层通过socket对字节流进行操作,因此也会有一些基本网络操作,当在网络操作中遇到问题的时候,将会消耗大量的cpu资源,并且失去响应超时。

二 常见Timeout

clipboard.png

(WAS/BLOC是具体应用名称,不需要关心)

DBCP 获取连接超时

数据库连接池getConnection获取不到

Statement Timeout

statement timeout用来限制statement的执行时长,或者statement timeout可以简单认为一次sql的执行时间控制,timeout的值通过调用JDBC的java.sql.Statement.setQueryTimeout(int timeout) API进行设置。

JDBC的超时处理,在不同的数据库里,处理是不一样的,在这里只说下mysql的,其它数据库的可以翻看传送门

clipboard.png

处理步骤

  1. 调用connection createStatement 创建 statement

  2. 执行statement的executeQuery方法

  3. statement通过自己的connect发送query给mysql

  4. statement新创建一个timeout-execution线程用于进行超时处理

  5. 给statement的原有connection分配一个超时处理线程(^5.1)

  6. 向timeout-execution线程进行注册

  7. 达到超时条件

  8. TimerThread调用JtdsStatement实例中的TsdCore.cancel()方法

  9. timeout-execution线程创建一个同statement对应的(配置相同)connection

  10. 使用新创建的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丢包。

clipboard.png

网络

clipboard.png
数据库平均响应时间

翻阅日志发现在这段时间出现了大量的2s响应时间的接口,正是这些接口把数据库连接hang住导致连接池连接耗尽,其他请求获取不到连接。后来经过确认的确在这段时间出现了网络问题(持续1分钟),所以我们认为是网络 丢包 问题导致接口响应慢,占用数据库连接不释放,进而引发数据库连接池不够用的问题

网络问题再次爆发,持续获取不到数据库连接

时运不济,我们的系统再次出现了接口超时的问题,而这一次却是出现了致命的故障,因为请求量太大,所以没有等系统检测socket 连接,数据库连接池已经被耗尽,在大量的请求下,故障越发的明显。

案例总结

第一个案例,我们可以认为是网络丢包问题引发连接被hold(jdbc连接没有坏死)导致其它请求获取不到连接。也有可能有部分的坏死连接(日志显示也有请求超时的异常),在低请求量下,问题被掩盖住了,等过了1分钟网络恢复,网络丢包问题没有了,对应的jdbc连接又能很快的响应。而那些坏死的连接在系统检测到后又进行了重连。第二个案例应该是第一个案例的放大版,请求量大了。

部分摘自 http://www.importnew.com/2466.html


青芒
205 声望60 粉丝

java骚年


引用和评论

0 条评论