«

2021年12月21日 线上问题数据库连接池无法获取

时间:2021-12-21 15:40     作者:Mahalalel     分类: Oracle


一、背景

小编维护的一个网站,最近频繁发生数据库连接池问题,异常如下:

Exception occurred during processing request: Could not open JDBC Connection for transaction; 
nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object
org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; 
nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object

二、排查问题

2.1 初步分析

小编遇到的这个问题,首先是先解决服务无法访问问题 ~ 先重启服务。
之后小编也相应排查了代码,因为最近没有代码提交,所以排除了代码没有关闭连接池的问题

2.2 nginx监控

接着,相应去排查nginx实时打印的日志,看是否有异常ip或者爬虫攻击。
监控发现,只有少量的异常ip请求,排查了nginx配置文件,也添加了相应的防爬虫机制。
排除!

2.3 数据库长连接

小编也问了几个小伙伴,基本都指向一个核心点 ~ 数据库连接池中存在长连接。
关键点找到了,由于数据库这方面也没有很多的经验,小编前几天的关注点也都在客户端,导致这个问题没有进展。

昨天的时候,小编突然想到可以通过 PL/SQL Developer 来查看相应的数据库连接数。
参考了以下的链接:
(PLSQL)查询数据库(连接池)连接情况
Oracle中V$session及session相关信息

三、验证问题

3.1 通过相关的SQL排查连接数

-- 查询数据库当前进程的连接数
select count(*) from v$process;
-- 查看数据库当前会话的连接数
select count(*) from v$session;
-- 查看数据库的并发连接数
select count(*) from v$session where status='ACTIVE';
-- 查看当前数据库建立的会话情况
select sid,serial#,username,program,machine,status from v$session;
-- 查询数据库允许的最大连接数
select value from v$parameter where name = 'processes';

连接数据不查不要紧,一查惊呆小编了,最大连接数为1000,当前进程连接数963,当前会话连接数960,并发的连接数是938。
这个数据也验证了小编及小伙伴的判断。
为了对比异常服务器与正常运行的服务器,小编也去相应数据库中查询了,发现进程连接数、会话连接数以及并发连接数都维持在100以内。

四、解决问题

问题得到了验证。
那么接下来就是解决问题。
此时,应用又开始报了个异常:

Caused by: java.sql.SQLException: Listener refused the connection with the following error:
ORA-12519, TNS:no appropriate service handler found

度娘之后,发现是:可能是数据库上当前的连接数目已经超过了它能够处理的最大值。
小编此时用plsql也无法查询了,直接崩溃了!
无奈之下,只能重启Oracle数据库,(慎用!!!)

4.1 重启数据库应用

登录数据库所在服务器

利用ssh登录数据库服务器
①、切换到Oracle用户

su - oracle

②、查看监听状态

lsnrctl status

③、关闭监听进程

lsnrctl stop

④、杀掉所有session

# 网上搜索杀掉session的命令如下:
ps -ef|grep $ORACLE_SID|grep -v ora_|grep LOCAL=NO|awk '{print $2}'|xargs kill
# 实际上,我使用的时候并没有用,索性就用比较粗暴的方式,查询所有的进程id
ps -ef|grep $ORACLE_SID|grep -v ora_|grep LOCAL=NO|awk '{print $2}'
# 会列出所有连接的进程id,如果没有则表示没有会话连接,
# 用以下命令杀死进程
kill -9 {进程id}

⑤、关闭数据库
使用命令登录数据库

sqlplus /nolog

进入sqlplus界面,然后连接dba

conn /as sysdba

关闭数据库

shutdown immediate

成功关闭显示:

Database closed.
Database dismounted.

然后退出sqlplus:

exit

⑥、启动数据库监听器,并查看监听器状态

lsnrctl start
lsnrctl status

⑦、启动数据库
进入sqlplus,并连接dba;

sqlplus /nolog
conn /as sysdba

启动数据库

startup

五、SQL查询验证是否解决

-- 查询数据库当前进程的连接数
select count(*) from v$process;
-- 查看数据库当前会话的连接数
select count(*) from v$session;
-- 查看数据库的并发连接数
select count(*) from v$session where status='ACTIVE';
-- 查看当前数据库建立的会话情况
select sid,serial#,username,program,machine,status from v$session;
-- 查询数据库允许的最大连接数
select value from v$parameter where name = 'processes';

此时再次查询时,当前进程连接数、当前会话连接数以及并发的连接数都降到100以内。

完美解决!

标签: Oracle重启 数据库连接池