数据库原理差异
会话空闲时间超过sesseion_time后,数据库主动断开,客户端再发起请求,就会报此类错误;
当一个会话连接长时间没有执行SQL或者活动时,会将该会话释放,可以释放缓存避免出现例如OOM等问题。
在Oracle中连接会话默认永不超时,Mysql中连接会话默认8小时超时,而在GaussDB中,默认30min超时, postgresql 14 新增了idle_session_timeout参数,用来控制空闲会话连接超时的时间
问题排查
确认探活是否生效
方式一:查询审计日志,可以看到会话退出方式为超时退出:
select time,type,result,client_conninfo,detail_info from pg_query_audit('2023-06-06 13:56:00','2023-06-06 14:56:00') where database='xxx' and username='xxx';
time | type | result | client_conninfo | detail_info
------------------------+---------------+--------+--------------------------------------+----------------------------------------------------------------------
2023-06-06 | login_success | ok | [unknown]@. . . * | login success,the current user is:, SSL=off
2023-06-06 | user_logout | ok | PostgreSQL JDBC Driver@ .. .*** | session timeout, logout db(**) success
(4 rows)
方式二:查询DN日志,可以看到:
dn_6001 0 [BACKEND] LOG: close session : 978843 for 1 times due to session timeout : 180, max finish time is 754196672463385. But now is:754196673078048
方式三:在应用运行过程中查询pg_stat_activity视图,观察query是否有探活语句
gaussdb=# select datname,usesysid,usename,application_name,client_addr,query_start,waiting,state,query,connection_info from pg_stat_activity where datname='xxx';
常见的问题有:
druid为配置探活或者探活不生效,数据库session_timeout默认30min超时后自动断开连接,druid连接池无感知,继续使用该链接则会抛出异常;
问题解决方案
应用使用druid连接池,添加以下配置可进行连接池连接保活。
#在1.0.27之前版本,是建议使用TestWhileIdle来保证连接的有效性
test-while-idle:true
#在1.0.28版本之后,是建议使用keepAlive来保证连接的有效性
keep-alive: true
validation-query: SELECT 1
应用使用tomcat连接池,添加以下配置可进行连接池连接保活。
#空闲连接验证/清理线程运行之间休眠的毫秒数。此值不应设置在 1 秒以下。它决定了我们检查空闲连接、放弃连接的频率,以及验证空闲连接的频率。可不配置,默认5s。
timeBetweenEvictionRunsMillis: 60000
#指示对象是否将由空闲对象驱逐者(如果有)验证。如果一个对象验证失败,它将从池中删除。
test-while-idle:true
应用使用hikari连接池,添加以下配置可进行连接池连接保活。
#一个连接的生命时长(毫秒)超时而且没被使用则被释放,默认:30分钟,建议设置比数据库超时时长少60秒
spring.datasource.hikari.max-lifetime=1740000