[오라클 운영] 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가지
- 모든 PDB는 인스턴스를 공유합니다 — SGA, 백그라운드 프로세스는 CDB 단 하나
- PDB는 독립적인 데이터베이스처럼 동작합니다 — 사용자, 객체, 권한이 각각 분리
- 하나의 CDB에 수백 개의 PDB를 담을 수 있습니다 — 19c 기준 최대 252개(라이선스에 따라)
- 비-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 환경보다 압도적입니다.
운영 환경에 처음 도입한다면 다음 순서를 추천합니다.
- 테스트 CDB에서 SAVE STATE, 공통/로컬 사용자 충분히 익히기
- 표준 PDB 생성 스크립트 만들기 (SAVE STATE 포함)
- 명시적 서비스 사용 정책 수립
- CDB_ 뷰 기반 모니터링 쿼리 표준화*
- PDB 단위 백업 정책 도입
특히 ORA-12514로 인한 야간 사고를 막으려면 SAVE STATE 적용을 운영 표준에 반드시 포함시키세요. 이 한 가지만으로도 운영 사고의 상당 부분이 예방됩니다.
비슷한 CDB/PDB 운영 사례나 더 좋은 패턴이 있다면 댓글로 공유해 주세요.