1.1现象
存在一套11.2.0.4 RAC 2节点,数据库存在5000个会话数量,其中active正在执行的会话500个,其余均为非活跃会话。
大量inactive会话过多给Oracle数据库带来什么样的影响?
[活跃说明数据库存在大量并发,正常情况下说明是业务负载这块只能拆库,常规无法优化套路】
1) 内存消耗,每个会话对应数据库来说都是一个pga process 需要单独分配一块内存区域,并且其中会话保留的游标越多,越消耗内存;
2) cpu资源消耗,每个会话对应操作系统来说都是一个Oracle用户进程,虽然大量属于inactive 但是对于操作系统来说还是一个进程运行;
1.2相关参数
SESSIONS
Default value Derived: (1.5 * PROCESSES) + 22Range of values1 to 216 (which is 1 to 65536)
SESSIONS specifies the maximum number of sessions that can be createdin the system. Because every login requires a session, this parameter effectively determines
the maximum number of concurrent users in the system. You should always set this parameter explicitly to a value equivalent to your estimate of the maximum number of concurrent users,
plus the number of background processes, plus approximately 10% forrecursive sessions.
PROCESSES
Default value100Range of values6to operating system dependent
PROCESSES specifies the maximum number of operating system user processes that can simultaneously connect to Oracle. Its value should allowfor all background processes such aslocks,
job queue processes, and parallel execution processes.
# vi/etc/security/limits.conf
oracle soft nproc32oracle hard nproc64#ulimit-a
1.3 方法论
状态1.活跃会话基本上无法处理,Oracle数据库拆分[极端情况例如:会话挤压等异常情况,处理数据库异常后,活跃会话趋于平稳】;2.非活跃会话可以定期清理
参考文档
https://www.anbob.com/archives/5837.html
非活跃会话方法论:
A:dead session
Dead connection detection(DCD)是Oracle网络功能,主要用于客户端关闭其系统电源或客户端计算机意外崩溃而又无法正常关闭Oracle数据库连接的环境。
如果客户端计算机因正确断开会话而突然崩溃,则这些会话锁定的资源将继续被锁定,从而导致环境性能问题。由于这种情况可以在任何环境中发生,因此Oracle网络服务提供了DCD的功能,可以在早期检测到这种情况,从而可以快速恢复锁定的资源。
为了解决这种情况并检测死连接,Oracle在网络会话(12c中的tcp)层引入了一个新概念。服务器进程将SQL*Net Probe数据包发送到客户端,以检查在sqlnet.expire_time【单位:分钟】参数指定的每个固定时间间隔内连接是否仍然可用。
如果通过探测数据包的通信失败,则会返回错误,导致服务器进程退出。
SQLNET.EXPIRE_TIME= 10B:idel session1.WAS等中间件或程序软件,存在会话一定时间不工作自动断开设置;2.MAX_IDLE_TIME指定会话可以空闲的最大分钟数。 此后会话将自动终止。12.2 引入的新参数。这参数是整个db或CDB级,不可以alter session. 单位分钟,超过idle上限时间后会收到 ORA-03113错误。3.编写plsql脚本,定期执行[如下详细说明]
C:idle blocker session1.目前常规基本上都是DBA人为参与处理;2.如果一个idle session阻塞了其他会话,在19c 20c中可以使用参数max_idle_blocker_time 自动终止blocker, 当会话持有其他会话所需的资源时,该会话被视为阻塞会话.1)如 该会话持有另一个会话所需的锁。2)该会话是并行操作,并且其使用者组,PDB或数据库已达到其最大并行服务器限制或已排队的并行操作。3)会话的PDB或数据库实例即将达到其SESSIONS或PROCESSES限制。
此参数与MAX_IDLE_TIME参数的不同之处在于,MAX_IDLE_TIME适用于所有会话(阻塞和非阻塞),而MAX_IDLE_BLOCKING_TIME仅适用于阻塞会话。 因此,为了使MAX_IDLE_BLOCKING_TIME有效,其限制必须小于MAX_IDLE_TIME限制。
1.4 模拟人工处理
操作系统并发20进行登录,使用1000并发测试主机hang
#!/bin/bash
i=1
while (($i<=20))dosqlplus-S scott/tiger &let"i++"echo $1done
测试环境process 400达到上限报错
ERROR:
ORA-00020: maximum number of processes (400) exceeded
Thu Oct22 02:24:15 2020ORA-00020: maximum number of processes (400) exceeded
ORA-20 errors will not be written to the alert log forthe next minute. Please look at trace files to see all
the ORA-20errors.
Process m000 submission failed with error= 20Process m000 submission failed with error= 20Process m000 submission failed with error= 20Process m000 submission failed with error= 20Thu Oct22 02:24:18 2020DB 什么视图记录历史登录情况达到上限值???
SQL> SELECT * FROM GV$RESOURCE_LIMIT WHERE RESOURCE_NAME='sessions' or RESOURCE_NAME='processes';
手工方法输出KILL语句
SELECT STATUS,COUNT(*) FROM GV$SESSION GROUP BY STATUS;select username,round(LAST_CALL_ET/3600) as "HH24",count(*) from gv$session where status='INACTIVE'group by username,round(LAST_CALL_ET/3600) order by 2,3,1;select 'ALTER SYSTEM KILL session'''||sid||','||serial#||'''IMMEDIATE;' AS "KILL_SQL" from v$session where status='INACTIVE'AND LAST_CALL_ET>600 AND USERNAME='CC'unionselect 'ALTER SYSTEM KILL session'''||sid||','||serial#||'''IMMEDIATE;' AS "KILL_SQL" from v$session where status='INACTIVE'AND LAST_CALL_ET>36000 AND USERNAME='CB';
plsql执行kill inactive session
SET SERVEROUTPUT ON
DECLARE
P_SID NUMBER;
P_SERIAL NUMBER;
P_STATUS VARCHAR2(32);
KILL_SQLTEXT VARCHAR2(4000);
CURSOR CUR_APP_ID IS
SELECT
SID, SERIAL#
FROM
V$SESSION
WHERE STATUS= 'INACTIVE' AND USERNAME IN('SCOTT') AND STATUS = 'INACTIVE' AND LAST_CALL_ET >6;
BEGIN
OPEN CUR_APP_ID;
LOOP
FETCH CUR_APP_ID INTO P_SID,P_SERIAL;
EXIT WHEN CUR_APP_ID%NOTFOUND;
SELECT
STATUS
INTO P_STATUS
FROM
V$SESSION
WHERE
SID= P_SID AND SERIAL# = P_SERIAL AND USERNAME IN('SCOTT') AND STATUS = 'INACTIVE' AND LAST_CALL_ET >6;
IF P_STATUS= 'INACTIVE'THEN
KILL_SQLTEXT := 'ALTER SYSTEM KILL SESSION'||CHR(39)||P_SID || ',' || P_SERIAL ||CHR(39)||'IMMEDIATE';
EXECUTE IMMEDIATE KILL_SQLTEXT;
DBMS_OUTPUT.PUT_LINE(KILL_SQLTEXT);
END IF;
END LOOP;
CLOSE CUR_APP_ID;
END;/
1.5 配置定时任务
!对于RAC 2节点,需要每个节点都配置这个脚本,建议时间错开一定时间,例如30分钟。 通过实际执行发现kill 1300 inactive session话费时间3分钟左右。
[oracle@test script]$ chmod +x kill_inactive_session.sh
[oracle@test script]$ cat kill_inactive_session.sh
#!/bin/bash
export ORACLE_HOME=/u01/app/oracle/product/11.2.0/dbhome_1/export ORACLE_SID=tt
export PATH=$PATH:$HOME/bin:$ORACLE_HOME/bin
sqlplus/ as sysdba <
spool/home/oracle/script/kill_session.logselect to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') as "date" fromdual;
SET SERVEROUTPUT ON
DECLARE
P_SID NUMBER;
P_SERIAL NUMBER;
P_STATUS VARCHAR2(32);
KILL_SQLTEXT VARCHAR2(4000);
CURSOR CUR_APP_ID IS
SELECT
SID, SERIAL#
FROM
V\$SESSION
WHERE STATUS= 'INACTIVE' AND USERNAME IN('SCOTT') AND STATUS = 'INACTIVE' AND LAST_CALL_ET >6;
BEGIN
OPEN CUR_APP_ID;
LOOP
FETCH CUR_APP_ID INTO P_SID,P_SERIAL;
EXIT WHEN CUR_APP_ID%NOTFOUND;
SELECT
STATUS
INTO P_STATUS
FROM
V\$SESSION
WHERE
SID= P_SID AND SERIAL# = P_SERIAL AND USERNAME IN('SCOTT') AND STATUS = 'INACTIVE' AND LAST_CALL_ET >6;
IF P_STATUS= 'INACTIVE'THEN
KILL_SQLTEXT := 'ALTER SYSTEM KILL SESSION'||CHR(39)||P_SID || ',' || P_SERIAL ||CHR(39)||'IMMEDIATE';
EXECUTE IMMEDIATE KILL_SQLTEXT;
DBMS_OUTPUT.PUT_LINE(KILL_SQLTEXT);
END IF;
END LOOP;
CLOSE CUR_APP_ID;
END;/exit;
EOF
[oracle@test script]$ crontab-l01 07,21 * * * sh /home/oracle/script/kill_inactive_session.sh tail-200f //var/log/cron
Oct 22 07:00:01 test crond[4834]: (oracle) CMD (sh /home/oracle/script/kill_inactive_session.sh &)