Troubleshooting
Problem
Symptom
Cause
JCC Type 4 连数据库是通过TCP协议连接的,实现中其实就是打开一个到数据库服务器的Socket连接(即java.net.Socket,是TCP协议的一个封装和实现),之后,JCC与数据库服务器的通讯完全依赖于这个Socket对象。
参数keepAliveTimeOut不同于blockingReadConnectionTimeout,后者完全由JCC 控制,当JCC发现在blockingReadConnectionTimeout秒内从Socket读不到数据时,即认为连接已被中断,之后就触发 ACR。 这样一刀切的方式有可能会导致误判,所以我们推荐使用keepAliveTimeOut。 JCC参数keepAliveTimeOut只是用来覆盖数据库连接对应Socket对象中从操作系统层获取的tcp_keepalive等参数 (net.ipv4.tcp_keepalive_time, net.ipv4.tcp_keepalive_intvl, net.ipv4.tcp_keepalive_probes ),之后JCC完全依赖Socket在TCP层去发现连接的中断。因为Socket才是对TCP协议的真正实现,所以它对连接是否中断的判断很多时候要比 JCC一刀切的方式要准确。
当数据库服务器突然被Power off时,当前连接有可能出现两种状态:
状态1: 连接处于空闲状态,这种状态的连接属于tcp_keepalive等参数可控制的范围,keepalive数据包会被发出,所以在 tcp_keepalive_time + (tcp_keepalive_intvl * tcp_keepalive_probes) 秒后,连接被确认中断,Socket向JCC返回Timeout错误,JCC随即开始ACR。所以这部分连接可以成功切换到另外一个Member。
状态2: 连接不处于空闲状态,即正在传输数据中。 既然连接不处于空闲状态,所以不属于tcp_keepalive等参数可控制的范围。 此时Socket连接会不断尝试重传数据包,直到重传超时(RTO)发生。重传次数可以由tcp_retries2调整。默认情况下 tcp_retries2=15, 这时候重传超时至少发生在13分钟后,这就导致了连接在相当长时间内不能被切换到另外一个Member。
需要注意一点,重传超时(RTO)是一个动态的值,所以它的值往往是一个区间。它的工作机制大概如下(具体算法描述参见RCF1122,RCF793,RCF2988):
1. 首先获取当前Socket的历史RTT (Round-Trip Time, 即从发送端发送数据开始,到发送端收到来自接收端的确认,总共经历的时间)
2. 然后根据RTT计算第一次重传超时值。
3. 然后重传tcp_retries2次,每次的重传超时值以指数级上涨,比如第一次重传超时是10秒,那么第二次是20秒,第三次是40秒。
4. 重传tcp_retries2次后还不成功,则最终认为连接已经断开,放弃重传,并返回错误。
关于tcp_retries2的描述,可以参见 http://linux.die.net/man/7/tcp
Environment
Resolving The Problem
Was this topic helpful?
Document Information
Modified date:
02 October 2024
UID
swg21883798