数据库关键配置
1. socketTimeout
未配置socketTimeout时,应用不会超时,会永远等待。当出现网络隔离故障时,服务端访问数据库的连接会hang住,导致需要等到tcp重传失败或者keepalive失败才会断开连接,故障时间会非常长。
数据库连接池中的连接可能处于如下两种状态
- 连接处于繁忙状态(数据传输状态),会启动Tcp重传,默认情况下需要约15min才可以断开连接。
- 连接处于空闲状态(idle),启用了keepalive机制,默认配置下需要Tcp KeepAlive|7975秒,约2个多小时才会断开。
应用对socket中数据的读写操作都是阻塞的,socketTimeout即是读写socket底层数据时的阻塞超时时间。服务端可以通过配置socketTimeout来控制读或写数据的超时时间,避免陷入tcp重传或tcp keepalive,从而导致长时间故障。
[!note]
socketTimeout的时间一般以应用最长sql等待时间为准,也就是最慢的那条sql的执行时间为参考。同时,考虑到API接口的超时时间,可以设置为30秒。如果是时延敏感型应用,这个时间还可以设置得更短一点。
1.1. soketTimeout与tcp_retries2
如果我们在应用层设置的socketTimeout很小的话(例如3s),tcp_retries这个内核参数调整是没有必要的。
<font color="#ff0000">【木桶效应】但是,有些系统会因为一两个慢的接口或者SQL,从而将socketTimeout设的很大。
物理机突然宕机时,由于soketTimeout设置的过大,导致所有落到这台宕机的机器都会在$min(soketTimeout,924.6s-1044.6s)$,Linux默认tcp_retries2是15后才能从read系统调用返回。假设soketTimeout设置了个5min,系统总线程数是200,那么只要5min内有200个请求落到宕机的server就会使系统失去响应!
这时候我们可以通过将tcp_retries2设置为5,那么超时返回时间即为$min(soketTimeout假设为 5min,25.6-51.2s)$,也就是30s左右。
echo 5 > /proc/sys/net/ipv4/tcp_retries2
此情况下:
- 在慢SQL场景下,客户端和数据库服务器之间的 TCP 连接实际上是正常的,数据包能够正常发送和接收,只是数据库处理请求的时间过长。因此,不会出现TCP重传的情况,
tcp_retries2参数也就不会发挥作用,连接超时只会受socketTimeout控制。 - 如果出现物理主机宕机或网络故障,tcp连接异常,会进入tcp重传,此时所有的的线程都可以在约30秒发现故障。
1.2. socketTimeout底层时间
底层调用java.net.Socket.setSoTimeout(int timeout)方法进行设置,官方解释如下
With this option set to a non-zero timeout, a read() call on the InputStream associated with this Socket will block for only this amount of time. If the timeout expires, a java.net.SocketTimeoutException is raised, though the Socket is still valid. The option must be enabled prior to entering the blocking operation to have effect. The timeout must be > 0. A timeout of zero is interpreted as an infinite timeout.
在linux中,通常是通过调用Tcp重传#5. tcp user timeout|setsetsockopt实现的。
2. connectTimeout
控制创建tcp连接最大等待超时,默认永远等待。
- 如果未配置connectTimeout,但jdbc url中配置了多个数据库ip的情况下,第一个数据库节点如果故障了,将会永远卡在连接第一个节点上,而无法逃生至后续节点。
- 如果配置connectTimeout,且服务端jdbc url中配置了N个数据库节点ip,在前N-1个节点故障失联的情况下,最长可能会故障$(N-1)*connectTimeout$
[!note]
应用一般会配置健康检查或看门狗,在应用无响应的情况下重新拉起进程。这种情况下,一定要保证$(N-1)*connectTimeout$大于健康检查或看房狗允许的最长启动等待时间,避免健康检查或看门狗失败反复拉起进程,导致应用没有恢复的机会。一般tcp建链需要三次握手,时间不可能很长,因此建议配置值为5秒。
3. loginTimeout
数据库用户成功登录到数据库服务器的超时时间,一定要保证$connectTimeout < loginTimeout < getConnectionTimeout$