2026년 05월 28일 | DBMS Error 가이드
?? 이 글에서 다루는 내용
ORA-00018 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-00018란?
ORA-00018 에러는 Oracle 데이터베이스에서 허용 가능한 최대 세션 수를 초과했을 때 발생하는 오류입니다. 새로운 사용자나 애플리케이션이 데이터베이스에 접속을 시도할 때, 이미 SESSIONS 파라미터에 설정된 한도에 도달한 경우 신규 접속이 거부되며 이 에러가 발생합니다. 운영 환경에서 갑작스러운 트래픽 증가, 커넥션 풀 설정 오류, 또는 세션 누수(Session Leak) 등이 복합적으로 작용할 때 주로 나타나며, 서비스 장애로 직결될 수 있는 심각한 에러입니다.
주요 발생 원인
1. SESSIONS 파라미터 설정값 부족
Oracle 데이터베이스의 SESSIONS 파라미터는 동시에 허용할 수 있는 최대 세션 수를 결정합니다. 기본값은 PROCESSES 파라미터 값을 기반으로 자동 계산되지만(SESSIONS = (1.5 * PROCESSES) + 22), 애플리케이션 규모나 사용자 수 증가에 따라 이 값이 부족해지는 경우가 빈번합니다. 특히 초기 설계 단계에서 충분한 여유분을 확보하지 않으면 서비스 확장 시점에 반드시 이 문제에 직면하게 됩니다.
2. 세션 누수(Session Leak) 및 좀비 세션 누적
애플리케이션에서 데이터베이스 커넥션을 정상적으로 반환하지 않거나, 예외 처리 미흡으로 인해 커넥션이 닫히지 않고 계속 쌓이는 현상을 세션 누수라고 합니다. 특히 JDBC, OCI, ODBC 등을 사용하는 Java 또는 .NET 애플리케이션에서 finally 블록 없이 커넥션을 종료하거나, WAS(Web Application Server)의 커넥션 풀이 제대로 회수되지 않을 경우 비활성 세션이 기하급수적으로 증가하여 세션 한도를 빠르게 소진시킵니다.
3. 커넥션 풀(Connection Pool) 설정 오류
WAS나 미들웨어에서 커넥션 풀의 최대 커넥션 수가 과도하게 높게 설정되거나, 여러 WAS 인스턴스가 동시에 운영될 때 각각의 풀 설정이 합산되어 DB 세션 한도를 초과하는 경우입니다. 예를 들어 WAS 인스턴스가 4개이고 각각 최대 커넥션을 100으로 설정했다면, 최대 400개의 세션이 DB에 연결될 수 있으며 이를 사전에 계산하지 않으면 ORA-00018이 발생할 수 있습니다.
해결 방법
① 현재 세션 및 파라미터 현황 확인
먼저 현재 상태를 정확히 파악하는 것이 우선입니다.
-- 현재 SESSIONS, PROCESSES 파라미터 확인
SELECT NAME, VALUE, DESCRIPTION
FROM V$PARAMETER
WHERE NAME IN ('sessions', 'processes', 'transactions')
ORDER BY NAME;
-- 현재 활성 세션 수 및 최대 세션 수 확인
SELECT CURRENT_UTILIZATION,
MAX_UTILIZATION,
LIMIT_VALUE,
ROUND((CURRENT_UTILIZATION / LIMIT_VALUE) * 100, 2) AS USAGE_PCT
FROM V$RESOURCE_LIMIT
WHERE RESOURCE_NAME = 'sessions';
-- 세션 상태별 현황 파악
SELECT STATUS,
COUNT(*) AS SESSION_COUNT
FROM V$SESSION
GROUP BY STATUS
ORDER BY SESSION_COUNT DESC;
② SESSIONS / PROCESSES 파라미터 증설 (즉각적인 해결책)
현재 한도가 너무 낮다면 파라미터를 조정합니다. 이 파라미터는 static 파라미터이므로 변경 후 DB 재시작이 필요합니다.
-- 현재 값 확인
SHOW PARAMETER SESSIONS;
SHOW PARAMETER PROCESSES;
-- PROCESSES 값을 먼저 올리고 (예: 500으로 변경)
ALTER SYSTEM SET PROCESSES = 500 SCOPE = SPFILE;
-- SESSIONS는 자동 계산되지만 명시적으로 설정도 가능
-- SESSIONS = (1.5 * PROCESSES) + 22 공식 참고
ALTER SYSTEM SET SESSIONS = 772 SCOPE = SPFILE;
-- 변경 후 데이터베이스 재시작
-- SHUTDOWN IMMEDIATE;
-- STARTUP;
-- 재시작 후 변경 값 검증
SELECT NAME, VALUE
FROM V$PARAMETER
WHERE NAME IN ('sessions', 'processes');
> ⚠️ 주의: 운영 DB는 재시작 전 반드시 사전 공지 및 다운타임 협의가 필요합니다.
③ 좀비 세션 / 비활성 세션 강제 종료 (긴급 조치)
세션 누수로 인한 비활성 세션을 확인하고 정리합니다.
-- 오랫동안 유휴 상태인 세션 목록 조회 (60분 이상 비활성)
SELECT S.SID,
S.SERIAL#,
S.USERNAME,
S.STATUS,
S.MACHINE,
S.PROGRAM,
S.LOGON_TIME,
ROUND(S.LAST_CALL_ET / 60, 1) AS IDLE_MINUTES,
S.MODULE
FROM V$SESSION S
WHERE S.STATUS = 'INACTIVE'
AND S.LAST_CALL_ET > 3600 -- 3600초(1시간) 이상 비활성
AND S.USERNAME IS NOT NULL
ORDER BY S.LAST_CALL_ET DESC;
-- 특정 세션 강제 종료 (SID, SERIAL# 확인 후 실행)
ALTER SYSTEM KILL SESSION '1234,56789' IMMEDIATE;
-- 다수의 좀비 세션을 한 번에 정리하는 스크립트 생성
SELECT 'ALTER SYSTEM KILL SESSION ''' || SID || ',' || SERIAL# || ''' IMMEDIATE;'
FROM V$SESSION
WHERE STATUS = 'INACTIVE'
AND LAST_CALL_ET > 7200 -- 2시간 이상 유휴
AND USERNAME IS NOT NULL
AND USERNAME NOT IN ('SYS', 'SYSTEM', 'DBSNMP');
④ 세션 누수 원인 애플리케이션 추적
어떤 프로그램이나 머신에서 세션 누수가 발생하는지 확인합니다.
-- 머신 및 프로그램별 세션 점유 현황
SELECT MACHINE,
PROGRAM,
USERNAME,
STATUS,
COUNT(*) AS SESSION_CNT,
MAX(LAST_CALL_ET) AS MAX_IDLE_SEC
FROM V$SESSION
WHERE USERNAME IS NOT NULL
GROUP BY MACHINE, PROGRAM, USERNAME, STATUS
ORDER BY SESSION_CNT DESC;
-- 특정 사용자(애플리케이션 계정)의 세션 상세 조회
SELECT SID,
SERIAL#,
STATUS,
MACHINE,
PROGRAM,
MODULE,
ACTION,
TO_CHAR(LOGON_TIME, 'YYYY-MM-DD HH24:MI:SS') AS LOGON_TIME,
LAST_CALL_ET
FROM V$SESSION
WHERE USERNAME = 'APP_USER' -- 실제 계정명으로 변경
ORDER BY LAST_CALL_ET DESC;
⑤ Profile을 이용한 세션 제한 설정
특정 계정이 과도하게 세션을 점유하지 못하도록 Profile로 제한합니다.
-- 사용자별 최대 동시 세션 수 제한 Profile 생성
CREATE PROFILE APP_USER_PROFILE LIMIT
SESSIONS_PER_USER 50 -- 계정당 최대 세션 수
IDLE_TIME 30 -- 유휴 허용 시간 (분)
CONNECT_TIME 480 -- 최대 접속 유지 시간 (분)
FAILED_LOGIN_ATTEMPTS 5
PASSWORD_LOCK_TIME 1/24;
-- 사용자에게 Profile 적용
ALTER USER APP_USER PROFILE APP_USER_PROFILE;
-- 적용된 Profile 확인
SELECT USERNAME, PROFILE
FROM DBA_USERS
WHERE USERNAME = 'APP_USER';
-- Profile 상세 설정 확인
SELECT RESOURCE_NAME, LIMIT
FROM DBA_PROFILES
WHERE PROFILE = 'APP_USER_PROFILE'
ORDER BY RESOURCE_NAME;
예방 방법
1. 세션 사용률 모니터링 자동화 및 임계치 알람 설정
세션 사용률이 70~80%에 도달했을 때 선제적으로 알람을 받을 수 있도록 모니터링 체계를 갖추는 것이 핵심입니다. Oracle Enterprise Manager(OEM)의 Metric 알람을 활용하거나, 아래와 같은 SQL을 스케줄러(DBMS_SCHEDULER)에 등록하여 주기적으로 임계치를 점검하고 DBA에게 이메일 또는 알람을 발송하는 배치 작업을 구성하는 것을 권장합니다.
-- 세션 사용률 모니터링 쿼리 (Cron 또는 DBMS_SCHEDULER로 주기 실행)
SELECT RESOURCE_NAME,
CURRENT_UTILIZATION,
MAX_UTILIZATION,
LIMIT_VALUE,
ROUND((CURRENT_UTILIZATION / LIMIT_VALUE) * 100, 2) AS USAGE_PCT,
CASE
WHEN ROUND((CURRENT_UTILIZATION / LIMIT_VALUE) * 100, 2) >= 90
THEN '🔴 위험 - 즉시 조치 필요'
WHEN ROUND((CURRENT_UTILIZATION / LIMIT_VALUE) * 100, 2) >= 75
THEN '🟡 경고 - 점검 필요'
ELSE '🟢 정상'
END AS ALERT_LEVEL
FROM V$RESOURCE_LIMIT
WHERE RESOURCE_NAME IN ('sessions', 'processes');
2. 커넥션 풀 설계 표준화 및 정기 점검
전체 WAS 인스턴스의 최대 커넥션 합계가 DB SESSIONS 파라미터의 70~75%를 초과하지 않도록 설계 표준을 수립하고, 분기 단위로 커넥션 풀 설정과 실제 세션 사용 패턴을 비교 검토해야 합니다. 또한 커넥션 풀에서 testOnBorrow, validationQuery, removeAbandonedTimeout 등의 설정을 통해 커넥션 유효성 검사를 활성화하고, 방치된 커넥션을 자동으로 회수하도록 WAS 설정을 표준화하는 것이 장기적인 세션 누수 예방의 핵심입니다.
관련 에러
- ORA-00019:
maximum number of session licenses exceeded— 라이선스 기반 세션 제한 초과로,LICENSE_MAX_SESSIONS파라미터와 관련됩니다. - ORA-00020:
maximum number of processes exceeded—PROCESSES파라미터 한도 초과로, ORA-00018과 함께 연쇄적으로 발생하는 경우가 많습니다. - ORA-12516:
TNS: listener could not find available handler with matching protocol stack— 리스너 레벨에서 사용 가능한 핸들러가 없을 때 발생하며, 세션 부족 상황에서 함께 나타날 수 있습니다. - ORA-12520:
TNS: listener could not find available handler for requested type of server— Shared Server(MTS) 환경에서 디스패처가 부족할 때 발생하며, 세션 초과 상황과 유사한 접속 불가 증상을 보입니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.