代码改变世界

ORACLE中STATUS为INACTIVE但是SERVER为SHARED状态的会话浅析

2016-12-15 16:46  潇湘隐者  阅读(2580)  评论(0编辑  收藏  举报

   我们知道当ORACLE数据库启用共享服务器模式时,通过共享服务器模式连接到数据库的会话是有一些特征的。在v$session里面,其SERVER的状态一般为SHARED和NONE, 为SHARED时,表示当前会话正在执行SQL语句,其占用共享服务器进程,会话的STATUS状态为ACTIVE;当会话状态STATUS处于INACITVE时,它的SERVER字段值一般为NONE,意味着此时并没有共享服务器进程服务该会话,这个详细请见v$session中server为none与shared值解析 这篇博客。但是最近在一数据库中突然见到一些会话STATUS为INACTIVE,但是SERVER状态为SHARED的会话,如下所示:

clip_image001

 

其实发现这个问题是因为在追查一个TNS-12535的问题时发现的。当时突然出现短暂的数据库(Oracle 10g R2)连接不上的情况,nmon监控发现当时的整体资源开销都非常小,也分析过AWR、ASH报告,并没有发现很特殊的情况,但是在bdump下面发现shared server进程生成的trc文件。例如下面一个 epps_d004_24858.trc,截图所示:

 

clip_image002

 

在这篇博客”TNS-12535: TNS:operation timed out案例解析”里面我分析、构造过出现TNS-12535错误的场景。但是我们分析ASH报告和查询dba_hist_active_sess_history时发现出现问题的时间段,active会话的数量不超过4个。所以可以排除是这种情形。后面检查发现共享服务器模式的会话居然有STATUS为INACTIVE但是SERVER为SHARED状态的会话,而且数量较多,本身这台服务器的max_shared_servers参数为32,所以当大量INACTIVE会话一直占用shared server进程时,当ACITVE会话需要shared server服务进程时就会由于shared server进程不够而处于等待状态,时间长了就会出现TNS-12535错误。那么就有可能出现active session不多,但是连接不上数据库的这种情况。分析至此,那么就有两个问题需要解决:1 为什么INACTIVE的会话会占用shared server进程不释放? 2 这个分析必须要经测试验证确认. 3:如何解决这个问题?

 

SQL> show parameter max_shared_servers;
 
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
max_shared_servers                   integer     32
SQL> 

 

关于第一个问题,刚刚开始一直没有找到答案,后面才在oracle metalink上面找到了答案,官方文档High Number Of Shared Servers Usage In 10g When Compared To 9i (文档 ID 444950.1)里面有相关介绍,如下摘抄所示:

 

 

APPLIES TO:

Oracle Server - Enterprise Edition - Version: 9.2.0.1 to 10.2.0.3
This problem can occur on any platform.

SYMPTOMS

On 10g having a shared server configuration and seeing many sessions with "STATUS" "INACTIVE" but still these sessions are not releasing the shared server process.

When you query from V$SESSION

SQL>select sid,server,status FROM v$session WHERE SID='154';

SID SERVER STATUS
---------- --------- --------
154 SHARED INACTIVE

In 9i The shared server process is released.

SQL> select SID,Server,STATUS from V$Session where SID=10;

SID SERVER STATUS
---------- --------- --------
10 NONE INACTIVE

In 10g Since the sessions are not releasing the shared server processes, Number of shared server processes increases and will cause new connections to terminate with a message max limit(MAX_SHARED_SERVERS) for shared_servers exceeded.

If you trace the session then you will observe the following wait events.

WAIT #0: nam='virtual circuit status' ela= 30000256 circuit#=7 status=2 p3=0
obj#=-1 tim=745725456
*** 2006-11-28 14:46:43.906
WAIT #0: nam='virtual circuit status' ela= 30000250 circuit#=7 status=2 p3=0
obj#=-1 tim=775725785

CAUSE

When using WORKAREA_SIZE_POLICY=AUTO, In 10g for certain operations (Like SORT) SQL memory can intentionally spill into the PGA of the shared server rather than taking up space in shared memory. When data spills to the PGA the session has to stay tied to that specific shared server. And hence the Process in Inactive can still be holding a shared server until it is terminated.

SOLUTION

The behavior observed is expected in 10g when WORKAREA_SIZE_POLICY is set to automatic.

Use WORKAREA_SIZE_POLICY=MANUAL to prevent the SORT operation to spill over the PGA. This will make sure the session doesn't require any more shared server process and the SHARED_SERVER will be released by the process when it is in INACTIVE status.

BUG 5689608  can be referred for more information

REFERENCES

BUG:5689608 - INACTIVE SESSION IS NOT RELEASING SHARED SERVER PROCESS

 

当数据库参数WORKAREA_SIZE_POLICY = AUTO时,在10g中对于某些SQL操作(如SORT)所用的SQL内存,可能有意地放入( spill over这里没有翻译为溢出)共享服务器的PGA当中,而不是占用共享内存(shared memroy)中的空间。 当数据放入到PGA时,会话必须保持绑定到该特定的共享服务器(shared server)。 因此,处于非活动状态的进程仍可以持有共享服务器,直到会话终止。

另外,解决方案里面也介绍,可以将参数WORKAREA_SIZE_POLICY设置为MANUAL,这样可以阻止排序操作将数据放入PGA当中。这个设定可以确保会话不会要求更多的共享服务器进程,并且当会话变成INACTIVE状态时,共享服务器很快就能释放。

那么第一个问题解决了,接下来我们来看第二个问题,后面我观察时,发现出现问题的时候,ACTIVE和INACTVIE的shared server数量等于32了. 那么我们接下来看看,如何构造这种状态的会话

 

在共享连接方式的会话1中执行下面SQL

SQL> show user;
USER is "TEST"
SQL> create table test as select * from dba_objects;
 
Table created.
 
SQL> create or replace package cursor_package as
  2  cursor mycursor is select * from test order by object_name;
  3  end;
  4  /
 
Package created.
 
SQL> begin
  2   open cursor_package.mycursor;
  3   end;
  4   /
 
PL/SQL procedure successfully completed.
 
SQL> create or replace procedure test_case is
  2  l_row TEST%rowtype;
  3  begin
  4  if cursor_package.mycursor%isopen then
  5  fetch cursor_package.mycursor into l_row;
  6  end if;
  7  end;
  8  /
 
Procedure created.
 
SQL> select sys_context('userenv', 'sid') from dual;
 
SYS_CONTEXT('USERENV','SID')
--------------------------------------------------------------------------------
932

 

如上所示,我们知道这个会话ID为932,此时开启另外一个会话2,查看会话ID为932的状态。如下所示

SQL> select sid, serial#, status ,server from v$session where sid=932;
 
       SID    SERIAL# STATUS   SERVER
---------- ---------- -------- ---------
       932         23 INACTIVE NONE

 

在会话1中执行下面SQL语句,如下截图所示:

SQL> exec test_case;
 
PL/SQL procedure successfully completed.
 
SQL> 

clip_image003

 

然后去会话2中检查会话ID为932的状态,此时就会出现STATUS为INACTIVE,SERVER状态为SHARED的会话状态了。

 

image

 

关于如何解决这个问题,我们并没有将将参数WORKAREA_SIZE_POLICY设置为MANUAL,因为修改这个参数过后,需要调整sort_area_size,hash_area_size等参数. 在复杂环境下,一个固定值比较难满足各个时段的需求。这个数据库实例本身max_shared_server的值(32)比较小,我们将其调整为48, 另外本身设置了一个crontab作业, 定期清理那些空闲超过一段时间的INACTIVE会话。

 

参考资料:

High Number Of Shared Servers Usage In 10g When Compared To 9i (文档 ID 444950.1)