Oracle ORA-29276 오류 원인과 해결 방법 완벽 가이드

ORA-29276
2026년 10월 06일 | DBMS Error 가이드

이 글에서 다루는 내용

ORA-29276 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.

ORA-29276 transfer timeout 는?

ORA-29276 에러는 Oracle UTL_HTTP, UTL_TCP, UTL_SMTP 등의 네트워크 패키지를 사용할 때 데이터 전송(transfer) 과정에서 설정된 타임아웃 시간을 초과하면 발생하는 에러입니다. 주로 Oracle 데이터베이스 서버가 외부 HTTP 서버, 메일 서버, TCP 소켓 등과 통신하는 도중 응답이 지연되거나 네트워크 연결이 불안정할 때 나타납니다. 이 에러는 단순한 네트워크 지연뿐만 아니라 방화벽 정책, 외부 서버의 과부하, 잘못된 타임아웃 설정 등 다양한 복합적인 원인으로 인해 발생할 수 있습니다.


주요 발생 원인

  • UTL_HTTP 타임아웃 설정 미흡

Oracle의 UTL_HTTP 패키지를 사용하여 외부 REST API나 웹 서버에 HTTP 요청을 보낼 때, 기본 타임아웃 값이 너무 짧게 설정되어 있거나 아예 설정되지 않은 경우 발생합니다. 외부 서버의 응답이 기본 타임아웃 임계값을 초과하면 Oracle은 즉시 ORA-29276을 발생시키고 연결을 종료합니다. 특히 대용량 데이터를 주고받거나 외부 API의 처리 시간이 긴 경우에 빈번하게 발생합니다.

  • 네트워크 불안정 및 방화벽 차단

Oracle 서버와 외부 엔드포인트 사이의 네트워크 경로에 방화벽, 프록시, 로드 밸런서 등이 개입하는 경우 TCP 세션이 중간에 강제로 끊기거나 패킷 손실이 발생할 수 있습니다. 방화벽이 특정 시간 이상 유지되는 TCP 연결을 강제 종료하는 정책을 가지고 있을 경우, Oracle 입장에서는 데이터 전송이 완료되지 않은 상태에서 연결이 끊겨 타임아웃으로 인식합니다. 이 경우 DBA 혼자서는 해결이 어렵고 네트워크 엔지니어와의 협력이 필수적입니다.

  • UTL_TCP 또는 UTL_SMTP 소켓 통신 지연

UTL_TCP나 UTL_SMTP를 이용해 직접 소켓 통신이나 이메일 발송을 처리할 때, 상대방 서버(SMTP 서버 등)가 응답하지 않거나 처리 속도가 느린 경우에도 동일한 에러가 발생합니다. 특히 SMTP 서버가 스팸 방지 목적으로 응답을 의도적으로 지연시키는 Greylisting 정책을 사용하는 경우, Oracle PL/SQL 코드에서 설정한 타임아웃보다 응답 시간이 길어져 에러가 발생합니다. 이 원인은 운영 환경이 변경되거나 SMTP 서버 정책이 업데이트될 때 갑작스럽게 나타나는 경우가 많습니다.


해결 방법

1. UTL_HTTP 타임아웃 값 조정

UTL_HTTP.SET_TRANSFER_TIMEOUT 프로시저를 사용하여 적절한 타임아웃 값을 설정합니다. 기본값은 60초이므로, 외부 API의 응답 특성에 맞게 조정이 필요합니다.

DECLARE
  v_req   UTL_HTTP.REQ;
  v_resp  UTL_HTTP.RESP;
  v_buffer VARCHAR2(4000);
BEGIN
  -- 타임아웃을 120초로 설정 (기본값 60초에서 증가)
  UTL_HTTP.SET_TRANSFER_TIMEOUT(120);
  
  -- HTTP 요청 생성
  v_req := UTL_HTTP.BEGIN_REQUEST(
    url    => 'http://your-api-endpoint.com/data',
    method => 'GET'
  );
  
  -- 요청 헤더 설정
  UTL_HTTP.SET_HEADER(v_req, 'Content-Type', 'application/json');
  
  -- 응답 받기
  v_resp := UTL_HTTP.GET_RESPONSE(v_req);
  
  DBMS_OUTPUT.PUT_LINE('HTTP Status: ' || v_resp.status_code);
  
  -- 응답 본문 읽기
  BEGIN
    LOOP
      UTL_HTTP.READ_LINE(v_resp, v_buffer, TRUE);
      DBMS_OUTPUT.PUT_LINE(v_buffer);
    END LOOP;
  EXCEPTION
    WHEN UTL_HTTP.END_OF_BODY THEN
      NULL;
  END;
  
  UTL_HTTP.END_RESPONSE(v_resp);
  
EXCEPTION
  WHEN UTL_HTTP.TRANSFER_TIMEOUT THEN
    DBMS_OUTPUT.PUT_LINE('전송 타임아웃 발생: ORA-29276');
    UTL_HTTP.END_RESPONSE(v_resp);
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('에러 발생: ' || SQLERRM);
END;
/

2. 예외 처리 강화 및 재시도 로직 구현

단순히 타임아웃을 늘리는 것보다 재시도(Retry) 로직을 구현하여 일시적인 네트워크 장애에 대비하는 것이 더 안정적입니다.

DECLARE
  v_req        UTL_HTTP.REQ;
  v_resp       UTL_HTTP.RESP;
  v_buffer     VARCHAR2(32767);
  v_retry_cnt  NUMBER := 0;
  v_max_retry  NUMBER := 3;
  v_success    BOOLEAN := FALSE;
BEGIN
  -- 타임아웃 설정
  UTL_HTTP.SET_TRANSFER_TIMEOUT(180);

  WHILE v_retry_cnt < v_max_retry AND NOT v_success LOOP
    BEGIN
      v_retry_cnt := v_retry_cnt + 1;
      DBMS_OUTPUT.PUT_LINE('시도 횟수: ' || v_retry_cnt);

      v_req := UTL_HTTP.BEGIN_REQUEST(
        url    => 'http://your-api-endpoint.com/resource',
        method => 'POST'
      );

      UTL_HTTP.SET_HEADER(v_req, 'Content-Type', 'application/json');
      UTL_HTTP.SET_HEADER(v_req, 'Connection', 'close');

      v_resp := UTL_HTTP.GET_RESPONSE(v_req);

      IF v_resp.status_code = 200 THEN
        v_success := TRUE;
        DBMS_OUTPUT.PUT_LINE('요청 성공');
      END IF;

      UTL_HTTP.END_RESPONSE(v_resp);

    EXCEPTION
      WHEN UTL_HTTP.TRANSFER_TIMEOUT THEN
        DBMS_OUTPUT.PUT_LINE('타임아웃 발생, 재시도 중... (' || v_retry_cnt || '/' || v_max_retry || ')');
        -- 재시도 전 잠시 대기 (DBMS_LOCK 사용 또는 루프)
        DBMS_SESSION.SLEEP(5); -- 5초 대기 후 재시도
      WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('알 수 없는 에러: ' || SQLERRM);
        EXIT;
    END;
  END LOOP;

  IF NOT v_success THEN
    RAISE_APPLICATION_ERROR(-20001, '최대 재시도 횟수 초과: API 호출 실패');
  END IF;
END;
/

3. UTL_SMTP 타임아웃 처리

SMTP를 이용한 메일 발송 시 타임아웃을 명시적으로 처리하는 방법입니다.

DECLARE
  v_conn   UTL_SMTP.CONNECTION;
  v_reply  UTL_SMTP.REPLY;
BEGIN
  -- SMTP 서버 연결 (포트 25, 타임아웃 60초)
  v_conn := UTL_SMTP.OPEN_CONNECTION(
    host    => 'smtp.yourcompany.com',
    port    => 25,
    tx_timeout => 60  -- 전송 타임아웃 60초 명시
  );

  v_reply := UTL_SMTP.EHLO(v_conn, 'yourdb.yourcompany.com');
  v_reply := UTL_SMTP.MAIL(v_conn, 'sender@yourcompany.com');
  v_reply := UTL_SMTP.RCPT(v_conn, 'recipient@yourcompany.com');
  v_reply := UTL_SMTP.DATA(
    v_conn,
    'Date: ' || TO_CHAR(SYSDATE, 'DD MON YYYY HH24:MI:SS') || UTL_TCP.CRLF ||
    'From: sender@yourcompany.com' || UTL_TCP.CRLF ||
    'To: recipient@yourcompany.com' || UTL_TCP.CRLF ||
    'Subject: Oracle DB 알림' || UTL_TCP.CRLF ||
    UTL_TCP.CRLF ||
    '이것은 Oracle DB에서 발송된 테스트 메일입니다.'
  );
  UTL_SMTP.QUIT(v_conn);
  DBMS_OUTPUT.PUT_LINE('메일 발송 성공');

EXCEPTION
  WHEN UTL_SMTP.TRANSIENT_ERROR OR UTL_SMTP.PERMANENT_ERROR THEN
    DBMS_OUTPUT.PUT_LINE('SMTP 에러: ' || SQLERRM);
    BEGIN
      UTL_SMTP.QUIT(v_conn);
    EXCEPTION
      WHEN OTHERS THEN NULL;
    END;
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('기타 에러 (ORA-29276 포함): ' || SQLERRM);
END;
/

4. 현재 ACL 및 네트워크 설정 확인

Oracle 12c 이상에서는 네트워크 접근 제어 목록(ACL) 설정을 확인하고, 타임아웃 관련 권한을 점검해야 합니다.

-- 현재 ACL 설정 확인
SELECT HOST, LOWER_PORT, UPPER_PORT, ACE_ORDER,
       GRANT_TYPE, PRIVILEGE, PRINCIPAL
FROM   DBA_HOST_ACES
ORDER  BY HOST, ACE_ORDER;

-- UTL_HTTP 권한 부여 예시 (Oracle 12c 이상)
BEGIN
  DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE(
    host       => 'your-api-endpoint.com',
    lower_port => 80,
    upper_port => 80,
    ace        => xs$ace_type(
                    privilege_list => xs$name_list('http'),
                    principal_name => 'YOUR_SCHEMA',
                    principal_type => xs_acl.ptype_db
                  )
  );
END;
/

-- 월별 타임아웃 에러 발생 빈도 모니터링 (에러 로그 테이블 가정)
SELECT TO_CHAR(ERROR_DATE, 'YYYY-MM') AS MONTH,
       COUNT(*)                        AS ERROR_COUNT
FROM   APP_ERROR_LOG
WHERE  ERROR_CODE = 'ORA-29276'
GROUP  BY TO_CHAR(ERROR_DATE, 'YYYY-MM')
ORDER  BY MONTH DESC;

예방 방법

  • 타임아웃 값을 환경에 맞게 표준화하고 모니터링 체계 구축

개발, 테스트, 운영 환경별로 외부 연동 시스템의 평균 응답 시간을 사전에 측정하고, 측정된 평균 응답 시간의 3~5배를 타임아웃 기준값으로 설정하는 것을 권장합니다. 또한 애플리케이션 에러 로그 테이블을 별도로 운영하여 ORA-29276 에러 발생 빈도와 패턴을 주기적으로 분석하고, 특정 임계값 초과 시 DBA에게 알람이 가도록 모니터링 체계를 구축해야 합니다.

  • 외부 연동 로직의 비동기 처리 및 방어적 코딩 적용

외부 HTTP API 호출이나 SMTP 메일 발송과 같이 응답 시간이 불확실한 작업은 Oracle Advanced Queuing(AQ)이나 DBMS_SCHEDULER를 활용하여 비동기 방식으로 처리하는 아키텍처를 권장합니다. 동기 방식이 불가피한 경우에는 반드시 예외 처리 블록에서 UTL_HTTP.TRANSFER_TIMEOUT 예외를 명시적으로 캡처하고, 에러 로그 기록, 재시도 횟수 제한, 서킷 브레이커(Circuit Breaker) 패턴을 적용하여 하나의 외부 연동 실패가 전체 배치나 트랜잭션에 영향을 주지 않도록 방어적으로 코드를 작성해야 합니다.


관련 에러

  • ORA-29273: UTL_HTTP.REQUEST_FAILED — HTTP 요청 자체가 실패했을 때 발생하며, ORA-29276과 함께 자주 나타납니다.
  • ORA-29278: UTL_HTTP.PERSISTENT_CONN_FAILED — HTTP 지속 연결(Keep-Alive)에 실패했을 때 발생합니다.
  • ORA-29279: UTL_SMTP.PERMANENT_ERROR — SMTP 영구 에러로, SMTP 서버가 요청을 거부할 때 발생합니다.
  • ORA-12170: TNS:Connect timeout occurred — Oracle Net 수준에서의 연결 타임아웃으로, 네트워크 레이어의 문제를 나타냅니다.
  • ORA-29259: UTL_TCP.END_OF_INPUT — TCP 소켓 입력 스트림의 종료를 나타내며, 예기치 않은 연결 종료 시 ORA-29276과 함께 발생할 수 있습니다.
DBMS 에러 코드 시리즈

주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.

본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.

댓글 남기기