RAC의 ASM과 파일 구성
RAC의 공유 ASM 파일과 인스턴스별 리두 및 UNDO, SID와 SCOPE 설정 및 파일 관리 실습
#핵심 요약
데이터 파일, 컨트롤 파일, SPFILE은 공유 저장소(실습에서는 ASM +DATA)에 하나만 있고 모든 인스턴스가 같은 파일을 봄
각 인스턴스는 자체 리두 버퍼와 LGWR로 자신에게 매핑된 redo thread에 기록하고, 자기 UNDO 테이블스페이스를 씀
파라미터는 SID='*'로 공통값, SID='인스턴스'로 인스턴스 전용값을 두며 전용값이 공통값보다 우선함
SWITCH LOGFILE, CHECKPOINT LOCAL은 접속한 인스턴스에만, ARCHIVE LOG CURRENT, CHECKPOINT GLOBAL은 모든 인스턴스에 적용됨
아카이브 모드는 DB 전체 속성이라 한 인스턴스만 MOUNT하고 나머지는 모두 내린 상태에서 바꿈
#개념과 동작 원리
| 구분 | 구성과 범위 |
|---|---|
| 데이터 파일 | 공유 저장소에 하나, 한 노드에서 만든 테이블스페이스가 복사 없이 다른 노드에서도 바로 보임 |
| 컨트롤 파일 | 모든 인스턴스가 함께 쓰는 DB 구조, 상태 정보, 다중화본도 같은 DB에 속함 |
| SPFILE | 공유 저장소에 하나, 각 노드의 $ORACLE_HOME/dbs/init<SID>.ora에는 spfile='+DATA/...' 한 줄만 두는 포인터 방식 |
| THREAD# | 인스턴스가 사용하는 리두 스트림 번호 |
| GROUP# | DB 전체에서 유일하며 한 thread에 여러 group을 할당해 순환 사용 |
| 리두 공유 접근 | 평상시에는 자기 thread에 기록하고 장애 시 다른 인스턴스가 읽어 복구 |
| 공유 UNDO | CDB 전체에서 인스턴스마다 활성 UNDO 하나 |
| 로컬 UNDO | 열린 컨테이너마다 인스턴스별 활성 UNDO 하나 |
| ASM_DISKGROUPS | ASM 시작 시 마운트할 디스크 그룹 목록 |
| ASM_DISKSTRING | ASM 디스크 검색 경로 |
두 인스턴스가 각자 DBWR로 같은 공유 데이터 파일에 써도, Global Cache Service(LMS, LMON, LMD)가 블록 상태와 소유권을 조정해 같은 블록을 무질서하게 동시에 바꾸지 않음
다른 인스턴스에서 블록을 받은 횟수는 gc cr blocks received, gc current blocks received 통계로 봄
RAC의 필수 조건은 모든 노드가 접근하는 공유 저장소이며 ASM은 그 방법 중 하나임
루트와 하나의 PDB가 두 인스턴스에서 모두 열린 실습 예시는 루트용 두 개와 PDB용 두 개의 활성 UNDO가 필요하다고 설명함
| 명령 | 적용 범위 |
|---|---|
ALTER SYSTEM SWITCH LOGFILE |
현재 접속한 인스턴스의 thread |
ALTER SYSTEM ARCHIVE LOG CURRENT |
활성화된 모든 thread의 current redo를 아카이브하는 전체 로그 스위치 |
ALTER SYSTEM CHECKPOINT LOCAL |
현재 인스턴스 |
ALTER SYSTEM CHECKPOINT GLOBAL |
DB를 연 모든 인스턴스 |
| 파라미터 변경 | 반영 위치와 시점 |
|---|---|
SCOPE=MEMORY |
현재 메모리에만, 재기동하면 사라짐 |
SCOPE=BOTH |
메모리와 SPFILE, 동적 파라미터에 주로 씀 |
SCOPE=SPFILE |
SPFILE에만, 정적 파라미터처럼 재기동이 필요할 때 |
SID |
적용할 인스턴스, '*'는 모든 인스턴스 공통 |
ISSYS_MODIFIABLE이 FALSE면 실행 중에 바꿀 수 없는 정적 파라미터(재기동 필요), IMMEDIATE면 바로 반영, DEFERRED면 새 세션부터 반영됨
실습의 분류: db_files, processes, sga_max_size, audit_trail은 FALSE, open_cursors, undo_retention은 IMMEDIATE, recyclebin은 DEFERRED
| 항목 | 역할 |
|---|---|
DB_FILES |
인스턴스가 열 수 있는 데이터 파일 상한, RAC 인스턴스끼리 같은 값 필요 |
MAXDATAFILES |
컨트롤 파일을 만들 때 DATAFILE 기록 영역의 초기 크기, DB_FILES 범위에서 자동 확장 가능 |
RECORDS_TOTAL |
현재 DATAFILE 기록 영역에 할당된 레코드 수, 생성 당시 MAXDATAFILES 값 자체는 아님 |
#필수 명령어 또는 SQL
#공유 파일과 인스턴스별 UNDO 확인
SELECT name FROM v$datafile;
SELECT tablespace_name, file_name FROM dba_data_files;
SELECT inst_id, name, value FROM gv$parameter
WHERE name = 'undo_tablespace' ORDER BY inst_id;
SELECT inst_id, name, value FROM gv$sysstat
WHERE name IN ('gc cr blocks received', 'gc current blocks received')
ORDER BY inst_id, name;
SELECT inst_id, name, description FROM gv$bgprocess
WHERE name IN ('DBW0', 'LMS0', 'LMON', 'LMD0')
ORDER BY inst_id, name;결과 해석:
실습 기록: 두 노드의 v$datafile이 같은 +DATA/<DB_NAME>/DATAFILE/... 다섯 파일로 나왔고, <NODE1>에서 CREATE TABLESPACE ts01 DATAFILE '+data' SIZE 10m 뒤 <NODE2>에서도 바로 TS01이 보였음undo_tablespace는 일반적으로 <NODE1>이 UNDOTBS1, <NODE2>가 UNDOTBS2임
SHOW PARAMETER spfile
SHOW PARAMETER asm_diskgroups
SHOW PARAMETER asm_diskstringSELECT property_name, property_value
FROM database_properties
WHERE property_name = 'LOCAL_UNDO_ENABLED';결과 해석: TRUE는 로컬 UNDO 모드이며 FALSE이면 PDB별 UNDO 절차의 전제가 충족되지 않음
#SID와 SCOPE로 파라미터 바꾸기
SHOW PARAMETER spfile
SHOW PARAMETER cluster_database
-- 인스턴스 전용값
ALTER SYSTEM SET undo_tablespace = 'UNDOTBS03' SCOPE = BOTH SID = '<INSTANCE1>';
-- 모든 인스턴스 메모리만 / 메모리와 SPFILE
ALTER SYSTEM SET open_cursors = 500 SCOPE = MEMORY SID = '*';
ALTER SYSTEM SET open_cursors = 400 SCOPE = BOTH SID = '*';
CREATE PFILE = '/home/oracle/pfile_both.ora' FROM SPFILE;
-- 정적 파라미터
ALTER SYSTEM SET db_files = 4000 SCOPE = BOTH SID = '*'; -- ORA-02095
ALTER SYSTEM SET db_files = 4000 SCOPE = SPFILE SID = '*';srvctl config database -d <DB_NAME>
grep -i open_cursors /home/oracle/pfile_both.ora결과 해석:
srvctl config database로 Clusterware가 쓰는 SPFILE 위치를 확인함
실습 기록: SCOPE=MEMORY로 500을 주자 두 인스턴스 현재값은 500이 됐지만 SPFILE을 PFILE로 뽑아 보면 500이 없었고, SCOPE=BOTH SID='*' 뒤에는 *.open_cursors=400 줄이 생겼음
정적 파라미터를 실행 중에 바꾸거나 SCOPE=BOTH, MEMORY로 주면 ORA-02095: specified initialization parameter cannot be modified가 남
DEFERRED 확인: ALTER SYSTEM SET recyclebin = off DEFERRED 뒤 현재 세션은 on, 새 세션은 off였고 다시 on으로 되돌렸음
SELECT inst_id, name, value, issys_modifiable FROM gv$parameter
WHERE name = 'db_files' ORDER BY inst_id;
SELECT inst_id, sid, name, value FROM gv$spparameter
WHERE name = 'db_files' AND isspecified = 'TRUE'
ORDER BY inst_id, sid;결과 해석: GV$PARAMETER는 실행 중인 값, GV$SPPARAMETER는 SPFILE에 적힌 값이라 SCOPE=SPFILE 직후에는 둘이 다름
비교할 때는 인스턴스 전용값(SID = 인스턴스 이름)을 '*'보다 먼저 봄db_files처럼 두 인스턴스가 같은 값을 가져야 하는 파라미터는 srvctl stop database -db <DB_NAME> -stopoption immediate 뒤 srvctl start database -db <DB_NAME>로 함께 반영함
수업 자료의 비교 예시: 현재값 200, SPFILE 변경 직후 200(저장값 4000), 재기동 뒤 4000
#SID별 값이 어긋날 때
| 구분 | 예 | 적용 기준 |
|---|---|---|
| 공통 설정 | SID='*' |
인스턴스 전용값이 없을 때 적용 |
| 전용 설정 | SID='<INSTANCE1>' |
그 인스턴스에 적용, 공통값보다 우선 |
| 인스턴스별로 다른 값 | thread, instance_number, undo_tablespace |
인스턴스 역할에 따라 설정 |
| 모두 같아야 하는 값 | db_files |
RAC 모든 인스턴스에서 동일 |
SELECT sid, name, value FROM v$spparameter
WHERE isspecified = 'TRUE' ORDER BY sid, name;
SELECT name, COUNT(DISTINCT value) AS value_cnt
FROM gv$parameter
GROUP BY name
HAVING COUNT(DISTINCT value) > 1
ORDER BY name;결과 해석: 두 번째 조회는 현재 값이 인스턴스마다 다른 파라미터를 보여 주지만, 달라도 되는지는 파라미터별 RAC 규칙으로 따로 확인함
ALTER SYSTEM SET db_files = 2000 SCOPE = SPFILE SID = '<INSTANCE1>';
SHUTDOWN IMMEDIATE
STARTUP -- ORA-01105, ORA-01174
SELECT instance_name, status FROM v$instance; -- STARTED
ALTER SYSTEM RESET db_files SCOPE = SPFILE SID = '<INSTANCE1>';
SHUTDOWN IMMEDIATE
STARTUP결과 해석:
실습 기록: 공통값 4000인 상태에서 <NODE1> 전용값 2000을 넣고 <NODE1>만 다시 띄우자 인스턴스는 시작됐지만 MOUNT에서 ORA-01105: mount is incompatible with mounts by other instances, ORA-01174: DB_FILES is 2000 buts needs to be 4000 to be compatible로 실패했음
NOMOUNT(STARTED) 상태에서 전용값을 RESET하고 다시 띄우자 두 인스턴스 모두 4000이 됐음
open_cursors를 SID='<INSTANCE1>'로 500을 준 뒤 SID='*'로 400을 주면 <NODE1>은 500, <NODE2>는 400으로 남음
전용값을 RESET ... SCOPE=SPFILE로 지워도 실행 중인 값은 그대로이고, 다음 기동부터 공통값이 적용됨
이 실습은 <NODE1> 기동 실패를 일부러 만들므로 <NODE2>가 정상인지 먼저 확인하고 실습 환경에서만 함
#thread별 리두 그룹 추가와 삭제
SELECT inst_id, instance_name, thread# FROM gv$instance ORDER BY inst_id;
SELECT thread#, group#, sequence#, status, archived,
ROUND(bytes / 1024 / 1024) AS size_mb, members
FROM v$log ORDER BY thread#, group#;
SELECT l.thread#, l.group#, lf.member
FROM v$log l JOIN v$logfile lf ON lf.group# = l.group#
ORDER BY l.thread#, l.group#, lf.member;
SELECT name, value FROM v$parameter
WHERE name IN ('db_create_online_log_dest_1', 'db_create_online_log_dest_2',
'db_create_file_dest', 'db_recovery_file_dest');ALTER DATABASE ADD LOGFILE INSTANCE '<INSTANCE1>' GROUP <GROUP1> SIZE <SIZE_MB>M;
ALTER DATABASE ADD LOGFILE INSTANCE '<INSTANCE2>' GROUP <GROUP2> SIZE <SIZE_MB>M;
-- 또는 thread 번호로
ALTER DATABASE ADD LOGFILE THREAD 1 GROUP <GROUP1>;
-- 각 인스턴스에서 필요한 만큼
ALTER SYSTEM SWITCH LOGFILE;
-- 삭제 조건 확인 뒤
ALTER DATABASE DROP LOGFILE GROUP <GROUP1>;
ALTER DATABASE DROP LOGFILE GROUP <GROUP2>;결과 해석:
새 group 번호는 DB 전체에서 겹치면 안 되고 크기는 기존 group과 같게 함
19c에서는 THREAD 대신 INSTANCE 절을 권장한다고 수업 자료는 적음
새 group은 처음에 UNUSED로 보일 수 있고, 자기 thread에서 쓰이면 CURRENT, ACTIVE, INACTIVE로 바뀜
삭제는 INACTIVE(ARCHIVELOG 모드면 ARCHIVED=YES까지)인 group만 하고, 삭제 뒤에도 thread마다 최소 2개 group을 남김
OMF 파일은 group 삭제 때 함께 지워지고, OMF가 아니면 파일 삭제를 따로 확인함
실습 환경이 <NODE1> = thread 1이어도 항상 그렇다고 가정하지 말고 V$INSTANCE.THREAD#로 확인함
#로그 스위치와 체크포인트 범위 비교
SELECT thread#, MAX(sequence#) AS max_sequence
FROM v$log_history GROUP BY thread# ORDER BY thread#;
ALTER SYSTEM SWITCH LOGFILE; -- 접속한 인스턴스의 thread만 증가
ALTER SYSTEM ARCHIVE LOG CURRENT; -- 모든 thread 증가
ALTER SYSTEM CHECKPOINT LOCAL;
ALTER SYSTEM CHECKPOINT GLOBAL;결과 해석:
수업 자료처럼 GV$LOG_HISTORY WHERE inst_id = 1로 보면 조회 인스턴스만 제한한 같은 DB 이력이라 thread별 비교가 헷갈리므로 V$LOG_HISTORY의 THREAD#로 비교함
SEQUENCE#는 다른 작업의 로그 스위치에도 바뀌므로 전후 시점과 alert log를 함께 봄
GV$DATAFILE_HEADER의 INST_ID별 행과 V$DATABASE.CHECKPOINT_CHANGE#만으로는 LOCAL과 GLOBAL 체크포인트의 수행 범위를 입증하기 어려워 각 인스턴스의 alert log와 체크포인트 통계를 함께 봄
#RAC의 아카이브 모드 전환
ARCHIVE LOG LIST
SELECT inst_id, name, log_mode FROM gv$database ORDER BY inst_id;
-- <NODE2>가 OPEN인 채로 <NODE1>만 MOUNT하면 실패
SHUTDOWN IMMEDIATE
STARTUP MOUNT
ALTER DATABASE NOARCHIVELOG; -- ORA-01126
-- <NODE2>에서 SHUTDOWN IMMEDIATE 뒤 <NODE1>에서
ALTER DATABASE NOARCHIVELOG;
ALTER DATABASE OPEN;
-- <NODE2>에서 STARTUP
-- 되돌리기: 두 인스턴스 모두 SHUTDOWN IMMEDIATE 뒤 <NODE1>에서
STARTUP MOUNT
ALTER DATABASE ARCHIVELOG;
ALTER DATABASE OPEN;SELECT thread#, sequence#, first_time, name
FROM v$archived_log
WHERE first_time > SYSDATE - 1/24
ORDER BY thread#, sequence#;
SELECT name, ROUND(space_limit / 1024 / 1024) AS limit_mb,
ROUND(space_used / 1024 / 1024) AS used_mb,
ROUND(space_reclaimable / 1024 / 1024) AS reclaimable_mb
FROM v$recovery_file_dest;
SELECT file_type, percent_space_used, number_of_files FROM v$recovery_area_usage;결과 해석:
실습 기록: <NODE2>가 열린 상태에서는 ORA-01126: database must be mounted in this instance and not open in any instance가 났고, <NODE2>를 내린 뒤 Database altered.였음<NODE1>의 ARCHIVE LOG LIST는 Archive Mode → No Archive Mode(Automatic archival Disabled) → 다시 Archive Mode로 바뀌었고 Archive destination은 USE_DB_RECOVERY_FILE_DEST였음
로그 모드는 DB 전체 값이지만 Current log sequence는 접속한 인스턴스의 thread 기준이라 노드마다 다를 수 있음
아카이브 로그는 thread별로 생기므로 각 인스턴스에서 로그 스위치한 뒤 THREAD# 1과 2의 기록을 봄
thread별 아카이브와 FRA 사용량의 실제 출력은 기재 없음
ARCHIVELOG로 바꾼 뒤에는 RMAN에서 CONFIGURE CONTROLFILE AUTOBACKUP ON, BACKUP DATABASE로 새 백업을 만듦
#컨트롤 파일 재생성 (MAXDATAFILES 변경)
SELECT inst_id, name FROM gv$controlfile ORDER BY inst_id, name;
SELECT type, record_size, records_total, records_used
FROM v$controlfile_record_section WHERE type = 'DATAFILE';
ALTER DATABASE BACKUP CONTROLFILE TO TRACE AS '/home/oracle/cre_controlfile.sql';grep -n -i -E "maxdatafiles|noresetlogs|resetlogs|tempfile" /home/oracle/cre_controlfile.sql
nl -ba /home/oracle/cre_controlfile.sql | sed -n '48,108p'-- 두 인스턴스 SHUTDOWN IMMEDIATE 뒤 <NODE1>만
STARTUP
SELECT sid, name, value FROM v$spparameter
WHERE name = 'cluster_database' AND isspecified = 'TRUE';
-- <INSTANCE1> 전용값이 있을 때만
ALTER SYSTEM RESET cluster_database SCOPE = SPFILE SID = '<INSTANCE1>';
ALTER SYSTEM SET cluster_database = false SCOPE = SPFILE SID = '*';
SHUTDOWN IMMEDIATE
STARTUP NOMOUNT
@/home/oracle/c.sql
SELECT instance_name, status FROM v$instance;
ALTER SYSTEM SET cluster_database = true SCOPE = SPFILE SID = '*';
SHUTDOWN IMMEDIATEsrvctl start database -db <DB_NAME>
srvctl status database -db <DB_NAME>결과 해석:
- 먼저 RMAN으로
CONFIGURE CONTROLFILE AUTOBACKUP ON,BACKUP DATABASE를 받아 둠(DB가 열린 상태의 백업은 ARCHIVELOG 모드가 전제) - trace 파일에서
NORESETLOGS실행 구간만 vi:53,104w /home/oracle/c.sql처럼 별도 파일로 복사함
행 번호는 trace를 만든 시점마다 다르므로-- Set #2. RESETLOGS case경계를 다시 확인함 c.sql에서 중복STARTUP NOMOUNT를 지우고, 파일 목록을 실제 DB와 대조하며MAXDATAFILES를 목표값으로 고침
수업 자료는 목표를 4000이라 하면서 캡처의c.sql은 4024라 실행 전에 다시 확인함RECOVER DATABASE,ALTER DATABASE OPEN, PDB와 TEMPFILE 구문은 실제 상태에 맞을 때만 실행하고 TEMPFILE 중복 추가를 막음- 재생성 뒤 두 인스턴스 OPEN, 공유 컨트롤 파일 경로, DATAFILE 기록 영역을 확인하고 새 컨트롤 파일 백업을 받음
CREATE CONTROLFILE ... REUSE는 기존 컨트롤 파일을 덮어씀
RECORDS_TOTAL < DB_FILES만으로 재생성이 필요하다고 판단하지 않으며, 4000으로 재생성하는 것은 수업 실습 목표임
재생성 결과와 RECORDS_TOTAL 값은 기재 없음
#사용 조건과 주의사항
로그 스위치는 현재 접속 인스턴스의 thread에만 적용됨
사용 중이거나 미완료 트랜잭션이 남은 UNDO는 삭제하지 않음
cluster_database = false로 한 노드만 띄운 상태를 그대로 두면 다른 인스턴스가 열리지 않으므로 작업 뒤 반드시 TRUE로 되돌리고 srvctl로 전체를 기동함
컨트롤 파일 재생성은 백업과 스크립트 검토를 마친 뒤에만 하며, 실습 환경 밖에서 따라 하지 않음