暂无图片
暂无图片
9
暂无图片
暂无图片
暂无图片

inactive会话累积将Oracle库夯死

原创 董小姐 2024-11-26
769

作者:董小姐yyds
Oracle 11g OCM,KCP,PGCE,墨天轮技术专家,青学会成员
擅长主流Oracle、MySQL、PG安装部署、故障定位处理、性能优化,
金仓、达梦、openGauss系等各种商用和开源国产数据库

微信:margaretdy
公众号:董小姐yyds
视频号:DongxiaojieYYDS
墨天轮:https://www.modb.pro/u/3121
CSDN:https://blog.csdn.net/qq961573863?type=blog
知乎:https://www.zhihu.com/people/fuwaxiaohuan


问题描述

现场同事反馈应用卡顿的厉害,让其导出awr报告发现负载并不高,就是会话数有些高,库里查询活动会话才2位数,就和现场反馈非数据库问题,也是自己不专业,后面现场同事反馈昨天资深DBA分析的结果是非活动会话占用服务器资源不释放怀疑是爬虫,感觉瞬间被打脸,赶紧接着百度分析,真是基础不扎实。下面是分析过程:

分析过程

分析AWR报告

查看会话数和参数

通过以下查询发现并未超过最大进程数和最大会话数

--查看当前的数据库连接数
select count(*) from v$process;  --返回30
--查看数据库允许的最大连接数
select value from v$parameter where name ='processes';   --返回3000
--查看数据库允许的最大会话数
select value from v$parameter where name ='sessions';  --返回4544

检查数据库中存在的非活动会话

--查看当前并发连接数
select status, count(1) from v$session group by status;

select username, program, count(1) from v$session where status='INACTIVE' group by username, program;

select p.username "OSUSERNAME", p.terminal,p.program,s.username "DBUSERNAME",s.command,s.status,s.server,s.process,s.machine,s.port,s.terminal,s.program,s.sid,s.serial#,p.spid FROM v$session s,v$process p WHERE p.addr=s.paddr and s.status='INACTIVE'order by 1,4;

查询是否有死锁

查询结果为no rows selected,说明数据库中没有死锁。

select * from v$locked_object;

查看内存

内存不释放

找出状态为INACTIVE超过60秒的session信息

last_call_et:单位秒

单实例

select sid, serial#, module, status
  from v$session s
 where s.username is not null
  --and upper(s.program) in ('TOAD.EXE', 'W3WP.EXE', 'PLSQLDEV.EXE','DBEAVER.EXE')
   and s.last_call_et >= 60
   and s.status = 'INACTIVE'
 order by sid desc;
 
 
 select DISTINCT(module) from 
 (select sid, serial#, module, status
  from v$session s
 where s.username is not null
  --and upper(s.program) in ('TOAD.EXE', 'W3WP.EXE', 'PLSQLDEV.EXE','DBEAVER.EXE')
   and s.last_call_et >= 60
   and s.status = 'INACTIVE'
 order by sid desc);

集群

SELECT SID, SERIAL#, INST_ID, MODULE, STATUS
  FROM GV$SESSION S
 WHERE S.USERNAME IS NOT NULL
   AND UPPER(S.PROGRAM) IN ('TOAD.EXE', 'W3WP.EXE', 'PLSQLDEV.EXE')
   AND S.LAST_CALL_ET >= 60
   AND S.STATUS = 'INACTIVE'
 ORDER BY INST_ID DESC;

产生原因

当会话处于INACTIVE状态过久可能导致资源浪费和ORA-00018错误,该场景中未出现超过最大会话数引发的ORA-00018错误。

解决办法

法一

sqlnet.ora位置在$ORACLE_HOME/dbs目录下

vi sqlnet.ora 
sqlnet.expire_time=60

参数说明:
sqlnet.expire_time:单位分钟,视业务情况设置时长

单点:alter system set resource_limit=true  scope=both;
      alter profile customers_profiles limit idle_time 60;


集群:alter system set resource_limit=true sid='*' scope=both;
      alter profile customers_profiles limit idle_time 60;

法二

--手动杀会话
select A.SID,B.SPID,A.SERIAL#,a.lockwait,A.USERNAME,A.OSUSER,a.logon_time,a.last_call_et/3600 LAST_HOUR,A.STATUS, 
'orakill '||sid||' '||spid HOST_COMMAND,
'alter system kill session '''||A.sid||','||A.SERIAL#||'''' SQL_COMMAND
from v$session A,V$PROCESS B where A.PADDR=B.ADDR AND SID>6

--批量杀会话
CREATE OR REPLACE PROCEDURE "KILL_SESSION" AS
v_sid number;
v_serial number;
killer varchar2(1000);
CURSOR cursor_session_info is select sid,serial# from v$session where type!='BACKGROUND' and status='INACTIVE' and last_call_et>2700 and username='ICWEB' and machine='orc';
BEGIN
open cursor_session_info;
loop
fetch cursor_session_info into v_sid,v_serial;
exit when cursor_session_info%notfound;
 
killer:='alter system disconnect session '''||v_sid||','||v_serial||''' post_transaction immediate';
execute immediate killer;
end loop;
dbms_output.PUT_LINE(cursor_session_info%rowcount||' users with idle_time>2700s have been killed!');
close cursor_session_info;
END;
/

法三

创建存储过程

场景1:创建直接kill的存储过程

创建存储过程sys.db_kill_idle_clients,方便调用该功能执行kill inactive会话.

CREATE OR REPLACE PROCEDURE SYS.DB_KILL_IDLE_CLIENTS AUTHID DEFINER AS
  job_no       number;
  num_of_kills number := 0;
BEGIN
  FOR REC IN (SELECT SID, SERIAL#, INST_ID, MODULE, STATUS
                FROM gv$session S
               WHERE S.USERNAME IS NOT NULL
                 AND UPPER(S.PROGRAM) IN ('TOAD.EXE', 'W3WP.EXE', 'PLSQLDEV.EXE')
                 AND S.LAST_CALL_ET >= 60
                 AND S.STATUS = 'INACTIVE'
               ORDER BY INST_ID ASC) LOOP
    ---------------------------------------------------------------------------
    -- kill inactive sessions immediately
    ---------------------------------------------------------------------------
    DBMS_OUTPUT.PUT('LOCAL SID ' || rec.sid || '(' || rec.module || ')');
    execute immediate 'alter system kill session ''' || rec.sid || ', ' ||
                      rec.serial# || '''immediate';
    DBMS_OUTPUT.PUT_LINE('. killed locally ' || job_no);
    num_of_kills := num_of_kills + 1;
  END LOOP;
  DBMS_OUTPUT.PUT_LINE('Number of killed xxxx system sessions: ' ||
                       num_of_kills);
END DB_KILL_IDLE_CLIENTS;
/

场景2:创建完成当前事务后kill的存储过程

由于kill session是直接将session kill,可能会出现导致事物回滚的现象,实际可以使用disconnect session完成当前事务后终止session.此方法比alter system kill session安全可靠

CREATE OR REPLACE PROCEDURE SYS.DB_KILL_IDLE_CLIENTS AUTHID DEFINER AS
  job_no       number;
  num_of_kills number := 0;
BEGIN
  FOR REC IN (SELECT SID, SERIAL#, INST_ID, MODULE, STATUS
                FROM gv$session S
               WHERE S.USERNAME IS NOT NULL
                 AND UPPER(S.PROGRAM) IN ('TOAD.EXE', 'W3WP.EXE', 'PLSQLDEV.EXE')
                 AND S.LAST_CALL_ET >= 60
                 AND S.STATUS <> 'KILLED'
               ORDER BY INST_ID ASC) LOOP
    ---------------------------------------------------------------------------
    -- kill inactive sessions immediately
    ---------------------------------------------------------------------------
    DBMS_OUTPUT.PUT('LOCAL SID ' || rec.sid || '(' || rec.module || ')');
    execute immediate 'alter system disconnect session ''' || rec.sid || ', ' ||
                      rec.serial# || '''immediate';
    DBMS_OUTPUT.PUT_LINE('. killed locally ' || job_no);
    num_of_kills := num_of_kills + 1;
  END LOOP;
  DBMS_OUTPUT.PUT_LINE('Number of killed system sessions: ' ||
                       num_of_kills);
END DB_KILL_IDLE_CLIENTS;
/

最后通过shell脚本清理空闲会话

在作业JOB或Schedule定期调用该存储过程,也可以通过后台作业结合shell脚本实现定期清理空闲会话

创建killSession.sh脚本,调用该存储过程SYS.DB_KILL_IDLE_CLIENTS

cd /home/oracle/scripts/
cat killSession.sh
#!/bin/bash
source /home/oracle/.bash_profile
logfile=/home/oracle/session/logs/killSession.log
echo " " >> $logfile 2>&1
echo "START ----`date`" >> $logfile 2>&1
$ORACLE_HOME/bin/sqlplus -S sys/oracle_4U@heal as sysdba <<EOF
exec sys.db_kill_idle_clients;
exit;
EOF
echo "END ------`date`" >> $logfile 2>&1

chmod +x /home/oracle/scripts/killSession.sh

在crontab里面配置后台作业,此处测试每隔1分钟运行一次,清理满足条件的空闲会话

*/1 * * * * /home/oracle/scripts/killSession.sh &>/dev/null

补充:会话状态

ORACLE数据库会话有ACTIVE、INACTIVE、KILLED、 CACHED、SNIPED五种状态:

  • active 处于此状态的会话,表示正在执行,处于活动状态。
  • killed 处于此状态的会话,表示出现了错误,正在回滚,当然,也是占用系统资源的。还有一点就是,killed的状态一般会持续较长时间,而且用windows下的工具pl/sql developer来kill掉,是不管用的,要用命令:alter system kill session 'sid,serial#' immediate;
  • INACTIVE表示会话处于空闲状态(等待操作可理解为等待需要执行的SQL语句),如PL/SQL Developer连接到数据库,执行一条SQL语句后,如果不继续执行SQL语句,那此会话就处于INACTIVE状态.一般少量INACTVIE会话对数据库没影响,但如果由于程序设计等原因导致数据库出现大量会话长时间处于INACTIVE状态,那将消耗大量系统资源,造成会话数超过系统session最大值,出现ORA-00018:maximum number of sessions exceeded错误。此时就需要清理那些长时间处于INACTIVE状态的会话,最好的就是在oracle中直接设置超时时间,也可通过Job来解决此问题。

影响长时间处于INACTIVE状态的会话因素:

  • Dead Connection或IDLE Connection造成。DEAD 连接由 SQLNET.ORA 文件处理,通过配置参数 SQLNET.EXPIRE_TIME=minutes 打开 SQLNET ORA 文件并设置参数。它是客户端文件,所以在客户端设置它。SQLNET.EXPIRE_TIME=60 (1 hour);IDLE 连接设置为 USER PROFILES,定义具有 IDLE_TIME 限制的配置文件,以便在达到时间限制后终止 INACTIVE SESSION。
--需要启用资源限制,以便它自动终止会话
alter system set resource_limit=true scope=both;

--检查用户使用哪个配置文件
SELECT USERNAME, USER_ID, PROFILE FROM DBA_USERS;

--检查 IDLE_TIME 的配置文件设置
select profile, limit from DBA_PROFILES where resource_name = 'IDLE_TIME';

--将 IDLE TIME 更改为断开连接后 30 分钟  
alter profile customers_profiles limit idle_time 30;

参数说明:idle_time 参数将在30分钟不活动后断开会话,单位分钟
  • 会话须长时间处于INACTIVE状态,如处于INACTIVE超两小时的会话才考虑Kill,可视具体业务决定,有可能超过半小时就可以杀掉会话进程。
  • 通过V$SESSION的LAST_CALL_ET字段(单位是秒)来判断,查询条件S.LAST_CALL_ET >= 7200。
  • 连接会话的程序.如某特定应用程序产生的INACTIVE会话才要清理,如Toad工具、PL/SQL Developer、W3WP.EXE工具。

作者:董小姐yyds
Oracle 11g OCM,KCP,PGCE,墨天轮技术专家,青学会成员
擅长主流Oracle、MySQL、PG安装部署、故障定位处理、性能优化,
金仓、达梦、openGauss系等各种商用和开源国产数据库

微信:margaretdy
公众号:董小姐yyds
视频号:DongxiaojieYYDS
墨天轮:https://www.modb.pro/u/3121
CSDN:https://blog.csdn.net/qq961573863?type=blog
知乎:https://www.zhihu.com/people/fuwaxiaohuan



参考链接:https://blog.csdn.net/m0_55928215/article/details/128550223

https://www.cnblogs.com/lkj371/p/17024709.html

https://blog.csdn.net/tylz04/article/details/9041775

最后修改时间:2024-11-27 17:14:25
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论