DBA 실무/Oracle(오라클)

[오라클 운영] Oracle 12c 멀티테넌트(CDB/PDB) 운영 가이드 - 상태 관리부터 Unplug/Plug까지

isony 2026. 6. 22. 08:15
반응형

[오라클 운영] Oracle 12c 멀티테넌트(CDB/PDB) 운영 가이드 - 상태 관리부터 Unplug/Plug까지

테스트 환경: Oracle 12c / 19c / 21c / 23ai

12c부터 도입된 멀티테넌트 아키텍처는 19c에서 사실상 표준이 되었고, 21c부터는 비-CDB(non-CDB) 모드가 desupport되어 CDB가 유일한 옵션입니다. 이제 오라클을 다룬다면 CDB/PDB 환경을 피할 수 없어요.

그런데 한국어 운영 자료의 상당수가 11g 시절 비-CDB 환경 기준이라, 처음 CDB 환경을 마주한 DBA는 다음과 같은 질문에 막힙니다.

  • 접속했더니 갑자기 객체가 안 보임 (다른 컨테이너에 있는 줄도 모르고)
  • DB 재시작 후 ORA-12514 발생 (이전 글에서 다룬 PDB MOUNTED 상태)
  • 사용자를 만들었더니 ORA-65096: invalid common user... 발생
  • PDB를 다른 서버로 옮기고 싶은데 방법 모름

이번 글에서는 CDB/PDB의 기본 개념부터 시작해, 상태 관리(SAVE STATE), PDB 이동(Unplug/Plug), 그리고 운영 표준 패턴까지 정리했습니다. 이 글은 ORA-12514 글의 후속 심화편 성격입니다.

 

CDB/PDB 아키텍처 한눈에

먼저 멀티테넌트 구조를 그림으로 이해해 봅시다.

┌──────────────────── CDB (Container Database) ────────────────────┐
│                                                                  │
│  ┌─────────────┐  ┌───────────┐  ┌──────────┐  ┌──────────┐      │
│  │  CDB$ROOT   │  │ PDB$SEED  │  │ PRODPDB  │  │ TESTPDB  │      │
│  │             │  │           │  │          │  │          │      │
│  │ - 시스템     │  │ - 템플릿   │  │ - 운영용  │  │ - 테스트  │       │
│  │ - 메타데이터 │   │ - 읽기전용 │  │   사용자  │  │   사용자  │       │
│  │ - 공통사용자 │   │           │  │   데이터 │  │   데이터  │       │
│  └─────────────┘  └───────────┘  └──────────┘  └──────────┘       │
│                                                                   │
│  ┌─ 공유 ─────────────────────────────────────────────────────┐   │
│  │ 인스턴스(SGA, 백그라운드 프로세스), 컨트롤 파일, REDO, UNDO │   │
│  └────────────────────────────────────────────────────────────┘   │
└───────────────────────────────────────────────────────────────────┘

컨테이너별 역할

컨테이너 역할 평소 상태

CDB$ROOT 시스템 메타데이터, 공통 사용자, 운영 관리 READ WRITE (항상)
PDB$SEED 새 PDB 생성을 위한 템플릿 READ ONLY (자동)
사용자 PDB 실제 비즈니스 데이터 READ WRITE (목표 상태)

핵심 사실 4가지

  1. 모든 PDB는 인스턴스를 공유합니다 — SGA, 백그라운드 프로세스는 CDB 단 하나
  2. PDB는 독립적인 데이터베이스처럼 동작합니다 — 사용자, 객체, 권한이 각각 분리
  3. 하나의 CDB에 수백 개의 PDB를 담을 수 있습니다 — 19c 기준 최대 252개(라이선스에 따라)
  4. 비-CDB는 21c부터 사라졌습니다 — 신규 구축 시 CDB는 필수

 

컨테이너 전환과 기본 명령

CDB/PDB 운영의 출발점은 "내가 지금 어디 있는가" 를 아는 것입니다.

현재 컨테이너 확인

-- 현재 컨테이너 이름
SHOW CON_NAME

-- 현재 컨테이너 ID (1=ROOT, 2=SEED, 3+=PDB)
SHOW CON_ID

-- 모든 컨테이너 목록과 상태
SELECT con_id, name, open_mode FROM v$containers ORDER BY con_id;
SELECT name, open_mode FROM v$pdbs;  -- PDB만

컨테이너 전환

-- CDB$ROOT로 이동
ALTER SESSION SET CONTAINER = CDB$ROOT;

-- 특정 PDB로 이동
ALTER SESSION SET CONTAINER = PRODPDB;

-- 다시 ROOT로
ALTER SESSION SET CONTAINER = CDB$ROOT;

직접 PDB로 접속

# Easy Connect로 PDB에 바로 접속
sqlplus scott/tiger@dbserver:1521/prodpdb

# tnsnames.ora에 service_name = prodpdb 별칭이 있으면
sqlplus scott/tiger@PRODPDB

PDB는 마치 독립 DB처럼 service_name으로 접속합니다.

일상적으로 가장 많이 쓰는 명령 모음

-- PDB 상태 확인
SHOW PDBS

-- 출력 예시:
-- CON_ID  CON_NAME    OPEN MODE   RESTRICTED
-- ------  --------    ---------   ----------
--   2     PDB$SEED    READ ONLY   NO
--   3     PRODPDB     READ WRITE  NO
--   4     TESTPDB     MOUNTED     (안 열림)

-- PDB 단순 열기
ALTER PLUGGABLE DATABASE TESTPDB OPEN;

-- 모든 PDB 한꺼번에 열기
ALTER PLUGGABLE DATABASE ALL OPEN;

-- 특정 PDB만 제외
ALTER PLUGGABLE DATABASE ALL EXCEPT TESTPDB OPEN;

-- PDB 닫기
ALTER PLUGGABLE DATABASE TESTPDB CLOSE IMMEDIATE;

 

★ PDB 상태 관리 - SAVE STATE (가장 중요)

CDB/PDB 운영에서 가장 자주 발생하는 사고가 DB 재시작 후 PDB가 MOUNTED 상태로 머무름 입니다. ORA-12514 글에서 다룬 그 문제예요.

무엇이 문제인가

기본 동작:

DB 재시작 전: PDB1 = READ WRITE, PDB2 = READ WRITE
       ↓ SHUTDOWN IMMEDIATE / STARTUP
DB 재시작 후: PDB1 = MOUNTED,    PDB2 = MOUNTED

PDB는 CDB가 재기동되면 기본적으로 MOUNTED 상태로 올라옵니다. 접속하려면 매번 수동으로 OPEN해야 하고, 자동화 스크립트나 모니터링 도구가 ORA-12514로 실패합니다.

해결: SAVE STATE 명령 (12.1.0.2+)

-- 1) PDB를 원하는 상태로 만들기
ALTER PLUGGABLE DATABASE prodpdb OPEN;

-- 2) 그 상태를 저장
ALTER PLUGGABLE DATABASE prodpdb SAVE STATE;

-- 3) 또는 모든 PDB의 현재 상태를 한꺼번에 저장
ALTER PLUGGABLE DATABASE ALL SAVE STATE;

이렇게 하면 CDB 재시작 후에도 PDB가 자동으로 OPEN 상태로 복원됩니다.

저장 상태 확인

SELECT con_name, instance_name, state
FROM   cdb_pdb_saved_states;

-- 또는
SELECT con_id, con_name, state
FROM   dba_pdb_saved_states;

저장 상태 제거

특정 PDB를 더 이상 자동 OPEN하지 않으려면:

ALTER PLUGGABLE DATABASE testpdb DISCARD STATE;

이후 DB 재시작 시 그 PDB는 MOUNTED 상태로 유지됩니다.

트리거 방식 (12.1.0.1 이하만)

12.1.0.2 미만 환경에서는 SAVE STATE가 없어서 트리거로 처리해야 합니다.

CREATE OR REPLACE TRIGGER open_all_pdbs
AFTER STARTUP ON DATABASE
BEGIN
    EXECUTE IMMEDIATE 'ALTER PLUGGABLE DATABASE ALL OPEN';
END;
/

12.1.0.2 이상이라면 트리거 방식은 권장하지 않습니다. SAVE STATE가 더 안전하고 표준입니다.

실무 팁

신규 PDB를 생성하면 반드시 마지막에 SAVE STATE를 실행하세요. 한 줄 빠뜨려서 야간에 사고가 나는 사례가 많습니다.

-- 신규 PDB 생성 표준 절차
CREATE PLUGGABLE DATABASE newpdb FROM PDB$SEED ...;
ALTER PLUGGABLE DATABASE newpdb OPEN;
ALTER PLUGGABLE DATABASE newpdb SAVE STATE;  -- ★ 잊지 말 것

 

★ 공통 사용자 vs 로컬 사용자

CDB 환경에서 사용자 관리의 핵심입니다. 잘못하면 ORA-65096 에러가 발생하거나 보안 문제가 생깁니다.

두 종류의 사용자

항목 공통 사용자 (Common User) 로컬 사용자 (Local User)

접두사 C## 또는 c## 필수 일반 이름
소속 CDB 전체 (모든 PDB) 특정 PDB만
생성 위치 CDB$ROOT에서 생성 특정 PDB에서 생성
권한 부여 CONTAINER=ALL 가능 해당 PDB만
운영 용도 DBA, 모니터링, 백업 애플리케이션 사용자

공통 사용자 생성

-- CDB$ROOT에 접속
ALTER SESSION SET CONTAINER = CDB$ROOT;

-- C## 접두사 필수
CREATE USER c##dba_monitor IDENTIFIED BY pwd
    CONTAINER = ALL;
    
GRANT CREATE SESSION TO c##dba_monitor CONTAINER = ALL;
GRANT SELECT_CATALOG_ROLE TO c##dba_monitor CONTAINER = ALL;

이렇게 생성한 사용자는 모든 PDB에 같은 이름으로 존재합니다.

로컬 사용자 생성 (가장 흔한 경우)

-- 특정 PDB로 이동
ALTER SESSION SET CONTAINER = PRODPDB;

-- 일반 이름 사용
CREATE USER app_user IDENTIFIED BY pwd;
GRANT CONNECT, RESOURCE TO app_user;
GRANT UNLIMITED TABLESPACE TO app_user;

이 사용자는 PRODPDB에만 존재하고 다른 PDB에서는 보이지 않습니다.

자주 발생하는 에러

ORA-65096: invalid common user or role name

-- ❌ CDB$ROOT에서 일반 이름으로 사용자 생성 시도
ALTER SESSION SET CONTAINER = CDB$ROOT;
CREATE USER scott IDENTIFIED BY tiger;
-- → ORA-65096

해결: 컨테이너를 PDB로 옮긴 후 생성하거나, 이름에 C## 접두사를 붙입니다.

ORA-65049: creation of local user or role is not allowed in CDB$ROOT

위와 같은 케이스. 로컬 사용자는 PDB에서만 생성 가능합니다.

사용자 조회

-- 현재 컨테이너의 사용자만
SELECT username, common, created FROM dba_users;

-- CDB 전체의 사용자 (공통 사용자만 보임)
SELECT username, con_id, common FROM cdb_users;

 

PDB 생성과 제거

운영 환경에서 새 사업부나 신규 시스템 도입 시 자주 하는 작업입니다.

PDB$SEED로부터 생성 (기본)

-- CDB$ROOT에서 실행
CREATE PLUGGABLE DATABASE newpdb
    ADMIN USER pdb_admin IDENTIFIED BY secure_pwd
    FILE_NAME_CONVERT = (
        '/u01/oradata/cdb/pdbseed/',
        '/u01/oradata/cdb/newpdb/'
    );

-- 생성 후 열기 + 상태 저장
ALTER PLUGGABLE DATABASE newpdb OPEN;
ALTER PLUGGABLE DATABASE newpdb SAVE STATE;

ADMIN USER는 해당 PDB의 관리자 계정으로 자동 생성됩니다.

기존 PDB 복제 (Clone)

-- 소스 PDB를 READ ONLY로 변경
ALTER PLUGGABLE DATABASE prodpdb CLOSE;
ALTER PLUGGABLE DATABASE prodpdb OPEN READ ONLY;

-- 복제
CREATE PLUGGABLE DATABASE testpdb FROM prodpdb
    FILE_NAME_CONVERT = (
        '/u01/oradata/cdb/prodpdb/',
        '/u01/oradata/cdb/testpdb/'
    );

-- 소스를 다시 READ WRITE로
ALTER PLUGGABLE DATABASE prodpdb CLOSE;
ALTER PLUGGABLE DATABASE prodpdb OPEN;

테스트 환경 구축, 마이그레이션 테스트에 자주 사용됩니다.

PDB 삭제

-- 1) 닫기
ALTER PLUGGABLE DATABASE testpdb CLOSE IMMEDIATE;

-- 2) 데이터파일까지 삭제
DROP PLUGGABLE DATABASE testpdb INCLUDING DATAFILES;

경고: INCLUDING DATAFILES는 물리 파일까지 영구 삭제합니다. 백업 확인 후 실행하세요.

 

★ PDB Unplug / Plug - 다른 CDB로 이동

CDB/PDB의 가장 강력한 기능 중 하나입니다. PDB를 통째로 다른 서버의 CDB로 옮길 수 있습니다. 한국어 자료에 깊이 있는 글이 거의 없는 영역이에요.

Unplug (꺼내기)

-- 1) PDB를 닫기 (Unplug는 닫힌 상태에서만 가능)
ALTER PLUGGABLE DATABASE prodpdb CLOSE IMMEDIATE;

-- 2) XML 메타데이터 방식 (전통적)
ALTER PLUGGABLE DATABASE prodpdb UNPLUG INTO '/backup/prodpdb.xml';

-- 또는 PDB 아카이브 방식 (12.2+, 데이터파일까지 압축)
ALTER PLUGGABLE DATABASE prodpdb UNPLUG INTO '/backup/prodpdb.pdb';

형식 차이

.xml 메타데이터만. 데이터파일은 별도로 복사 필요
.pdb 메타데이터 + 데이터파일을 하나로 압축. 이동에 편리

Unplug된 PDB 제거 (원본 CDB에서)

Unplug 후에도 PDB는 원본 CDB에 남아있습니다(MOUNTED 상태). 완전히 제거하려면:

DROP PLUGGABLE DATABASE prodpdb KEEP DATAFILES;

KEEP DATAFILES로 해야 데이터파일은 보존되어 새 CDB에 plug할 수 있습니다.

Plug (꽂기) - 다른 CDB에서

새 서버의 CDB로 파일을 옮긴 후:

-- XML 방식
CREATE PLUGGABLE DATABASE prodpdb USING '/backup/prodpdb.xml'
    NOCOPY 
    TEMPFILE REUSE;

-- 또는 .pdb 아카이브 방식
CREATE PLUGGABLE DATABASE prodpdb USING '/backup/prodpdb.pdb';

-- 열기 + 상태 저장
ALTER PLUGGABLE DATABASE prodpdb OPEN;
ALTER PLUGGABLE DATABASE prodpdb SAVE STATE;

활용 시나리오

  • DB 서버 교체: PDB를 그대로 새 서버로 이동
  • 클라우드 이전: 온프레미스 → 클라우드 마이그레이션
  • 테스트 환경 구축: 운영 PDB를 테스트 CDB로 복제
  • 버전 업그레이드: 19c CDB의 PDB를 21c CDB로 plug (compatibility 체크 필요)

주의사항

  • 호환성 검사 필수: plug 전에 DBMS_PDB.CHECK_PLUG_COMPATIBILITY로 확인
  • TDE 사용 중이면: ENCRYPT USING transport_secret 옵션 필수
  • CDB 호환성: 19c CDB → 12c CDB로 plug는 불가 (downgrade 안 됨)

 

운영 모니터링 - CDB_* 뷰 활용

CDB 환경에서는 DBA_* 뷰가 현재 컨테이너만 보여줍니다. CDB_* 뷰가 전체 CDB를 보여주는 표준입니다.

자주 쓰는 CDB_* 뷰

-- 전체 PDB와 상태
SELECT con_id, name, open_mode, restricted, application_root
FROM   cdb_pdbs;

-- 전체 PDB의 데이터파일 사용량
SELECT con_id, tablespace_name, 
       ROUND(SUM(bytes)/1024/1024, 2) AS size_mb
FROM   cdb_data_files
GROUP  BY con_id, tablespace_name
ORDER  BY con_id, tablespace_name;

-- 전체 PDB의 사용자
SELECT con_id, username, common, account_status
FROM   cdb_users
ORDER  BY con_id, username;

-- 전체 PDB의 세션 수
SELECT con_id, COUNT(*) AS session_cnt
FROM   v$session
GROUP  BY con_id
ORDER  BY con_id;

-- 전체 PDB의 백업 이력
SELECT con_id, session_key, input_type, status,
       TO_CHAR(start_time, 'YYYY-MM-DD HH24:MI:SS') AS start_at
FROM   cdb_rman_backup_job_details
ORDER  BY start_time DESC;

CON_ID로 컨테이너 식별

CON_ID 컬럼이 각 행이 어느 컨테이너에 속한지 알려줍니다.

  • 0: CDB 전체 (공유 정보)
  • 1: CDB$ROOT
  • 2: PDB$SEED
  • 3+: 사용자 PDB

 

운영 환경 권장 패턴 5가지

1. SAVE STATE는 PDB 생성 시 자동화

PDB 생성 스크립트 마지막에 항상 SAVE STATE를 포함하세요.

-- 표준 PDB 생성 스크립트 (사내 표준으로 보관)
PROMPT === PDB 생성 시작 ===
CREATE PLUGGABLE DATABASE &pdb_name FROM PDB$SEED ...;

PROMPT === PDB 열기 ===
ALTER PLUGGABLE DATABASE &pdb_name OPEN;

PROMPT === 상태 저장 (재시작 시 자동 OPEN) ===
ALTER PLUGGABLE DATABASE &pdb_name SAVE STATE;

PROMPT === 완료 ===

2. 명시적 서비스 사용

PDB 이름과 동일한 service_name에 의존하지 말고 별도 서비스를 만들어 사용하세요.

-- PRODPDB에서 실행
BEGIN
    DBMS_SERVICE.CREATE_SERVICE(
        service_name => 'app_prod_svc',
        network_name => 'app_prod_svc'
    );
    DBMS_SERVICE.START_SERVICE('app_prod_svc');
END;
/

이렇게 하면 나중에 PDB를 다른 CDB로 옮기거나 이름을 바꿔도 애플리케이션 연결 문자열을 변경할 필요가 없습니다.

3. DBA는 공통 사용자, 애플리케이션은 로컬 사용자

공통 사용자 (C##): 모니터링, 백업, 운영자
로컬 사용자: 애플리케이션, 비즈니스 사용자

이 분리를 지키면 보안 사고와 권한 혼란을 크게 줄일 수 있습니다.

4. CDB_* 뷰 사용 표준화

스크립트 작성 시 DBA_* 대신 CDB_* 뷰를 기본으로 사용하세요. CON_ID로 필터링하면 동일한 결과를 얻으면서도 전체 CDB 진단이 가능합니다.

5. PDB 단위 백업 정책 분리

RMAN으로 PDB 단위 백업을 분리해 두면 PDB 하나만 복구 가능합니다.

-- PRODPDB만 백업
BACKUP PLUGGABLE DATABASE PRODPDB;

-- PRODPDB만 복구
RESTORE PLUGGABLE DATABASE PRODPDB;
RECOVER PLUGGABLE DATABASE PRODPDB;

 

자주 발생하는 함정 5가지

함정 1: 컨테이너 전환 안 한 채 작업

CDB$ROOT에서 일반 사용자 만들기 시도 → ORA-65096. 작업 전 항상 SHOW CON_NAME으로 위치 확인.

함정 2: PDB 재시작 후 자동 OPEN 안 됨

SAVE STATE 미적용. 위 섹션 참고.

함정 3: DBA_USERS에 모든 사용자가 안 보임

DBA_USERS는 현재 컨테이너만 보여줌. 전체를 보려면 CDB_USERS 사용.

함정 4: PDB 이름 그대로 service_name 사용

운영 중 PDB 이름 변경이 어려워짐. 위 권장 패턴 2번 참고.

함정 5: Unplug 후 원본 CDB에 PDB 남아있음

DROP PLUGGABLE DATABASE ... KEEP DATAFILES로 정리해야 함.

 

23ai에서 새로 추가된 기능 (간단히)

23ai에서 PDB 운영에 관련된 주요 신기능:

  • PDB Snapshot Carousel: PDB의 시점별 스냅샷을 자동으로 회전 관리. 빠른 복구나 클론에 활용
  • Refreshable PDB 개선: 원격 PDB에서 자동 새로 고침
  • Read-Only User on PDB: 읽기 전용 사용자에게 PDB 단위 권한 부여

자세한 활용은 별도 글에서 다룰 예정입니다.

 

마무리

CDB/PDB 환경은 처음에는 복잡해 보이지만, 컨테이너 개념을 잡고 SAVE STATE를 적극 활용하면 운영이 오히려 더 편해집니다. 한 인스턴스에 여러 DB를 담을 수 있어서 자원 활용도와 관리 효율이 비-CDB 환경보다 압도적입니다.

운영 환경에 처음 도입한다면 다음 순서를 추천합니다.

  1. 테스트 CDB에서 SAVE STATE, 공통/로컬 사용자 충분히 익히기
  2. 표준 PDB 생성 스크립트 만들기 (SAVE STATE 포함)
  3. 명시적 서비스 사용 정책 수립
  4. CDB_ 뷰 기반 모니터링 쿼리 표준화*
  5. PDB 단위 백업 정책 도입

특히 ORA-12514로 인한 야간 사고를 막으려면 SAVE STATE 적용을 운영 표준에 반드시 포함시키세요. 이 한 가지만으로도 운영 사고의 상당 부분이 예방됩니다.

비슷한 CDB/PDB 운영 사례나 더 좋은 패턴이 있다면 댓글로 공유해 주세요.

 

 

반응형