一、问题展现
由于本人从事数据中心项目,数据中心有一个共享实例是对外提供数据的,6月11日发现数据库报ora_12516错误,一般ORA-12516有两个原因,一个是session数不够
,另一个就是客户端和服务端建立连接的时候频繁链接数据库,打开数据库链接而不关闭导致的。
通过plsq工具查询session,发行从6月9日到6月11日上午,有个用户频繁(每隔5分钟就要链接一次)的链接数据库,但是每次链接不能释放,导致用户该用户链接超过900多,正于是电话沟通业务厂家,让他们尽快排查关闭链接的功能(通过jdbc怀疑没有关闭链接功能或者关闭失效),但是数据库不能停止,只有自己想办法(我不是dba,而是开发人员),想起以前给其他项目写过oracle单机处理杀掉无效进程的过程,于是试试。
二、处理步骤
1、查看数据库参数
1)查看当前数据库的processes设置
SQL> show parameter processes
NAME                                 TYPE        VALUE 
db_writer_processes                  integer     1
gcs_server_processes                 integer     0
job_queue_processes                  integer     10
log_archive_max_processes            integer     2
processes                            integer     1200
SQL> show parameter sessions
NAME                                 TYPE        VALUE
java_soft_sessionspace_limit         integer     0l
icense_max_sessions                 integer     0
license_sessions_warning             integer     0
logmnr_max_persistent_sessions       integer     1
sessions                             integer     1500
shared_server_sessions               integer
一般按照经验值,将processes数设置为1200,则sessions数必须为1.1*1200+5>=1325就行
数据库参数应该是够的,但是数据库不能轻易的改动参数,估计dba来了只有改参数了,但是改参数需要走流程,需要时间还得重启库(正式环境重启需要走流程),于是我觉得在等待业务厂家处理的同时,还是自己写个kill过程吧,毕竟万事不求人🐴。
2、编写存储过程(代码为本人知识产权)
在包头中定义:
CREATE OR REPLACE PACKAGE PKG_SYS IS
  PROCEDURE PROC_KILL_INACTIVE_SESSIONS;
  PROCEDURE SESSION_LOGS(P_SID        IN NUMBER,
                         P_SERIAL     IN NUMBER,
                         P_INST_ID    IN NUMBER,
                         P_MODULE     IN VARCHAR2,
                         P_STATUS     IN VARCHAR2,
                         P_PROGRAM    IN VARCHAR2,
                         P_MACHINE    IN VARCHAR2,
                         P_LOGIN_TIME IN DATE,
                         P_MSG        IN VARCHAR2,
                         P_OSUSER     IN VARCHAR2);
END PKG_SYS;
/
在包体中编写
CREATE OR REPLACE PACKAGE BODY PKG_SYS IS
  /*-------------------------------------------------------------------------------------*/
  /*                                                                                     */
  /*   (C) Copyright IEDS Corporation 2017 All Rights Reserved.                          */
  /*                                                                                     */
  /*   函数名称    :PROC_KILL_INACTIVE_SESSIONS                                         */
  /*   功能说明    :杀无效进程                                                          */
  /*   参数说明    :                                                                    */
  /*     参数             (I/O)     类型           说明                                  */
  /*   返回值说明  :                                                                    */
  /*     无                                                                              */
  /*   详细说明    :                                                                    */
  /*   维度频率    :无                                                                  */
  /*   ORIGINAL    : (1.0)  2017-05-25  CODED   BY   [IEDS] JINWEI                       */
  /*-------------------------------------------------------------------------------------*/
  PROCEDURE PROC_KILL_INACTIVE_SESSIONS AS
    V_SID        NUMBER;
    V_SERIAL     NUMBER;
    V_INST_ID    NUMBER;
    V_MODULE     VARCHAR2(100);
    V_STATUS     VARCHAR2(100);
    V_PROGRAM    VARCHAR2(100);
    V_MACHINE    VARCHAR2(100);
    V_OSUSER     VARCHAR2(100);
    V_LOGIN_TIME DATE;
    V_SQL        VARCHAR2(1000);
    V_PROC_MSG   VARCHAR2(200);
    VDAYS        NUMBER;
  
    CURSOR C is
      select sid,
             serial#,
             inst_id,
             module,
             status,
             program,
             machine,
             logon_time,
             v.OSUSER
        from gv$session v
       where type != 'BACKGROUND'
         and status IN ('INACTIVE' /*,'KILLED'*/)
         and (sysdate - v.LOGON_TIME) > VDAYS
         and username = 'share'
         and v.PROGRAM like '%JDBC%';
  BEGIN
    --无效jdbc链接天数
    VDAYS := 3;
    --打开游标
    open C;
    loop
      BEGIN
        fetch C
          into V_SID,
               V_SERIAL,
               V_INST_ID,
               V_MODULE,
               V_STATUS,
               V_PROGRAM,
               V_MACHINE,
               V_LOGIN_TIME,
               V_OSUSER;
        exit when C%notfound;
      
        V_SQL := 'alter system disconnect session ''' || V_SID || ',' ||
                 V_SERIAL || ''' immediate';
        execute immediate V_SQL;
      
      EXCEPTION
        WHEN OTHERS THEN
          V_PROC_MSG := 'disconnect SESSION_SID=' || V_SID || ' 失败:';
          V_PROC_MSG := V_PROC_MSG || 'SQLCODE(' || TO_CHAR(SQLCODE) ||
                        ') SQLERRM(' || SUBSTR(SQLERRM, 1, 128) || ')';
          --异常日志              
          SESSION_LOGS(V_SID,
                       V_SERIAL,
                       V_INST_ID,
                       V_MODULE,
                       V_STATUS,
                       V_PROGRAM,
                       V_MACHINE,
                       V_LOGIN_TIME,
                       V_PROC_MSG,
                       V_OSUSER);
      END;
      --正常日志
      V_PROC_MSG := 'disconnect SESSION_SID=' || V_SID || '成功';
      SESSION_LOGS(V_SID,
                   V_SERIAL,
                   V_INST_ID,
                   V_MODULE,
                   V_STATUS,
                   V_PROGRAM,
                   V_MACHINE,
                   V_LOGIN_TIME,
                   V_PROC_MSG,
                   V_OSUSER);
    
    end loop;
    close C;
  EXCEPTION
    WHEN OTHERS THEN
      ROLLBACK;
  END PROC_KILL_INACTIVE_SESSIONS;
  --日志表
  PROCEDURE SESSION_LOGS(P_SID        IN NUMBER,
                         P_SERIAL     IN NUMBER,
                         P_INST_ID    IN NUMBER,
                         P_MODULE     IN VARCHAR2,
                         P_STATUS     IN VARCHAR2,
                         P_PROGRAM    IN VARCHAR2,
                         P_MACHINE    IN VARCHAR2,
                         P_LOGIN_TIME IN DATE,
                         P_MSG        IN VARCHAR2,
                         P_OSUSER     IN VARCHAR2) AS
    -- 定义自动提交事务
    PRAGMA AUTONOMOUS_TRANSACTION;
  BEGIN
    --删除3个月前日志
    DELETE FROM JC_M_KILL_ORACLE_SESSION_LOGS T
     WHERE T.NY <= TO_CHAR(ADD_MONTHS(SYSDATE, -3), 'YYYYMM');
    --插入异常日志      
    INSERT INTO JC_M_KILL_ORACLE_SESSION_LOGS
      (sid,
       serial,
       inst_id,
       module,
       status,
       program,
       machine,
       logon_time,
       SYSTIME,
       NY,
       MSG,
       OSUSER)
      SELECT P_SID,
             P_SERIAL,
             P_INST_ID,
             P_MODULE,
             P_STATUS,
             P_PROGRAM,
             P_MACHINE,
             P_LOGIN_TIME,
             SYSDATE,
             TO_CHAR(SYSDATE, 'YYYYMM'),
             SUBSTR(P_MSG, 1, 200),
             P_OSUSER
        FROM DUAL;
    COMMIT;
  EXCEPTION
    WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE('SQLCODE(' || TO_CHAR(SQLCODE) || ') SQLERRM(' ||
                           SUBSTR(SQLERRM, 1, 128) || ')');
  END SESSION_LOGS;
3、问题来了
1)问题1:
编译过程 报视图gv$session 在plsiq过程中不识别,缺乏权限。
原因:
Oracle为RAC集群机构,在单机可以,集群中gv$session和v$session都需要单独授权
于是通过操作系统用户root登录
su - oracle
sqlplus as / sysdba
grant select on gv$session to A ;
但是 gv$session不能直接授权,需要授权执行视图的同义词才行;
grant select on g_v$session to A ;
原因:
我们常用的v$ 是v_$的同义词,v_$是基于真正的视图v$,而真正的v$视图是在gv$的基础上限制inst_id得到;
我们常用的gv$是gv_$的同义词,gv_$基于真正的视图gv$,而真正的gv$视图基于系统表X$。
2)问题2:
继续编译,报错disconnect SESSION无权限;
su - oracle
sqlplus as / sysdba
GRANT ALTER SYSTEM TO A;
到此存储过程终于可执行了,但是还要增加定时自动执行JOB。
4、定时JOB
每天自动执行一次
begin
  sys.dbms_scheduler.create_job(job_name        => 'JOB_PROC_KILL_INACTIVE_SESSIONS',
                                job_type        => 'PLSQL_BLOCK',
                                job_action      => 'PROC_KILL_INACTIVE_SESSIONS;',
                                start_date      => to_date('2016-01-02 18:00:00',
                                                           'yyyy-mm-dd hh24:mi:ss'),
                                repeat_interval => 'Freq=Day;Interval=1',
                                end_date        => to_date(null),
                                job_class       => 'DEFAULT_JOB_CLASS',
                                enabled         => true,
                                auto_drop       => false);
end;
/
                    
                
                
            
        
浙公网安备 33010602011771号