dba经常会被开发或应用运维人员问起,数据库的会话超时时间的是多少,应用的数据库会话在多长时间会被终结,或者说kill掉。MySQL dba在被问起这个问题时回答起来非常简单,一般就是两个超时参数。Oracle dba回答起来可能更简单,可能就一句话,会话没有超时设置。这个简单的回答其实掩盖了Oracle数据库会话超时设置的复杂性。Oracle会话的超时设置可以在net services中设置,也可以设置实例级参数,还可以在用户的profile中设置,本文时这个系列的第二篇,谈谈会话超时的实例级参数。
1 会话超时实例级参数
Oracle数据库中,可以设置max_idle_time和max_idle_blocker_time两个实例级别的会话超时参数,从v$parameter视图中看一下这两个视图的说明。
SQL> l 1*select NAME,DESCRIPTION from v$parameter where name like'%idle%'NAME DESCRIPTION ------------------------ --------------------------------------------------------------------------------max_idle_time maximum session idle timein minutes max_idle_blocker_time maximum idle time for a blocking session in minutes
这两个参数的单位都是分钟,max_idle_time设置的会话空闲最大时间,会话空闲超过这个时间会被终结,对应的Oracle服务进程会被kill掉。max_idle_blocker_time设置的时阻塞会话的最大空闲时间,阻塞会话空闲时间超过设定值会被kill掉。这两个参数有没有默认值,可不可以在会话级设置,设置后是不是要重启一下服务器,这些信息也可以从v$parameter视图中查询到。
SQL>select NAME,VALUE,ISDEFAULT,ISSYS_MODIFIABLE,ISSES_MODIFIABLE from v$parameter where name like'%idle%';NAME VALUE ISDEFAULT ISSYS_MOD ISSES ------------------------ -------------------- --------- --------- -----max_idle_time 0TRUE IMMEDIATE FALSEmax_idle_blocker_time 0TRUE IMMEDIATE FALSE
可以看到这两个参数的默认值都是0,也就是没有超时设置,这两个参数都是实例级可调的,调整后立即生效。在会话级,这两个参数都不能调整。可以验证一下
SQL>alter session set max_idle_time=0;alter session set max_idle_time=0*ERROR at line 1:ORA-02096: specified initialization parameter isnot modifiable with this option
可以看到,这个参数在alter session时不能调整。
max_idle_blocker_time时阻塞会话的超时限制,什么时阻塞会话,Oracle官方文档对此有个说明:
A session is considered to be a blocking session when it is holding resources required by other sessions. For example:• The session is holding a lock required by another session. • The session is a parallel operation and its consumer group, PDB,or database has either reached its maximum parallel server limitor has queued parallel operations. • The session’s PDB or database instance is about to reach its SESSIONS orPROCESSES limit.
简单翻译下就是:一个会话当它持有其它会话需要的资源时被认为是阻塞会话。例如:
会话持有其它会话需要的锁。
会话执行一个并行操作,它的消费者组,PDB或者数据库达到了最大并行服务器限制或者排队的并行操作。
会话的PDB或者是数据库实例即将达到会话和进程限制。
官网列举的三个例子中,持有锁的阻塞会话比较常见,其它两种情况也需要注意。
2 实验验证max_idle_time参数
下面通过一个小实验验证一下这个参数,数据库的版本是
SQL>select BANNER_FULL from v$version;BANNER_FULL --------------------------------------------------------------------------------Oracle Database 19c Enterprise Edition Release 19.0.0.0.0- Production Version 19.3.0.0.0
max_idle_time的默认参数为0,将它改为1分钟,
SQL>alter system set max_idle_time=1;System altered. SQL> show parameter max_idle_time NAME TYPE VALUE ------------------------------------ ----------- ------------------------------max_idle_time integer1
打开一个会话,先运行一条sql,在等待1分钟后,在运行sql
SQL>select sysdate from dual;SYSDATE -------------------2023-02-1600:50:29SQL>select*from t_test;select*from t_test *ERROR at line 1:ORA-03135: connection lost contact Process ID:12154Session ID:70 Serial number:30076
执行sql报错,连接丢失,会话被kill的信息可以在数据库的alert.log中看到
2023-02-16T00:58:06.077747-05:00KILL SESSION for sid=(70,30076): Reason = max_idle_time parameter Mode = KILL HARD SAFE -/-/NO_REPLAY Requestor = PMON (orapid =2, ospid =1723, inst =1) Owner = Process: USER (orapid =49, ospid =12154) Result = ORA-0
这里被kill掉的会话的sid和serial#和之前报错的会话相同。alert日志里还可以看到会话被kill掉的原因Reason = max_idle_time parameter。
这个实验反复试过几次,更改过参数后,对之前的会话也是生效的,对sys用户不生效,和登录方式没有关系。
实验完成后,重置这个参数
SQL>alter system reset max_idle_time;System altered. SQL> show parameter max_idle_time NAME TYPE VALUE ------------------------------------ ----------- ------------------------------max_idle_time integer1
reset操作在不设置范围时只更改spfile里的值,要重置内存里的参数,需要指定范围
SQL>alter system reset max_idle_time scope=memory;System altered. SQL> show parameter max_idle_time NAME TYPE VALUE ------------------------------------ ----------- ------------------------------max_idle_time integer0
3 验证max_idle_blocker_time参数
使用行锁验证这个参数,首先,设置这个参数为1分钟
SQL>alter system set max_idle_blocker_time=1;System altered. SQL> show parameter max_idle_blocker_time NAME TYPE VALUE ------------------------------------ ----------- ------------------------------max_idle_blocker_time integer1
创建两个会话,关闭自动提交,运行更新语句更新一个有主键表同一主键值
会话1先运行更新语句
SQL>set autoc off SQL> show autoc autocommit OFF SQL>update t_test set id=12where id=2;1 row updated. SQL>select*from t_test;select*from t_test *ERROR at line 1:ORA-03113: end-of-file on communication channel Process ID:17950Session ID:36 Serial number:25168
然后再会话2上运行更新语句
SQL>set autoc 0SQL> show autoc autocommit OFF SQL>update t_test set id=102where id=2;1 row updated.
会话2在运行这个语句的时候被会话1阻塞,产生了行锁等待,会话1空闲时间超过1分钟之后,被数据库kill掉,会话2的更新操作成功。数据库告警日志里也有这次操作的信息
2023-02-16T02:48:18.203413-05:00Process termination requested for pid 17950[source = rdbms],[info =2][request issued by pid:1723, uid:54321]2023-02-16T02:48:18.252757-05:00KILL SESSION for sid=(36,25168): Reason = max_idle_blocker_time parameter Mode = KILL HARD SAFE -/-/NO_REPLAY Requestor = PMON (orapid =2, ospid =1723, inst =1) Owner = Process: USER (orapid =51, ospid =17950) Result = ORA-0
可以看到会话被kill掉的原因Reason = max_idle_blocker_time parameter,会话的sid和serial#,和会话1相同。
4 小结
在实例级别设置会话超时参数对数据库系统的sys用户不生效,对自定义的用户有效,会话因空闲超时被kill数据库的告警日志里会有记录。特别是max_idle_blocker_time这个参数,对于防止长时间的行锁有一定的作用,比如有些应用获得行锁后去做别的事情,导致其它会话长时间等待,这种场合下应该适用这个参数。