카테고리 : MySQL/기술노트

장애 시나리오별 runbook: primary crash, storage full, network partition 대응

MySQL primary crash, storage full, network partition의 관측 신호와 안전한 복구 순서, 승격 중단 조건과 Aurora 차이를 정리한다.

저자: MySQL 기술 노트 작성: 2026.11.05 약 14분 7,908자
다운로드

1. 장애 대응은 명령어보다 판단 순서가 중요하다

MySQL 연결이 끊겼다는 현상만으로 primary가 죽었다고 판단할 수는 없다. 프로세스 종료, 파일시스템 공간 부족, 네트워크 단절은 모두 연결 오류나 COMMIT 시간 초과로 나타날 수 있지만, 안전한 복구 순서는 서로 다르다. 프로세스가 살아 있는 서버를 죽었다고 간주해 다른 서버를 쓰기 가능 상태로 만들면 단순 통신 장애가 데이터 분기 장애로 바뀐다.

운영 절차서(runbook)는 “이 명령을 실행한다”는 목록이 아니다. 어떤 관측을 근거로 분기하고, 무엇을 확인하지 못하면 멈추며, 어느 시점부터 되돌리기가 별도 데이터 복구 작업이 되는지를 정의한 문서다. 여기서는 MySQL 8.0 이상, InnoDB와 비동기 복제를 기본으로 설명하고 Group Replication과 Aurora MySQL의 경계를 구분한다.

이 글의 SQL은 독립된 MySQL 8.0 테스트 서버에서 실행한 진단과 가정 입력의 의사결정 예제다. 실제 primary 강제 종료, 디스크 고갈, 네트워크 분할, replica 승격, Aurora 장애 조치는 수행하지 않았다. 따라서 SQL 성공을 장애 복구 성공이나 특정 RTO 달성의 증거로 해석하지 않는다.

공통 대응 계약

  • 사고 지휘자는 장애 선언, 쓰기 제한 범위, 복구 경로와 손실 수용 여부를 결정한다.
  • DB 담당자는 프로세스·로그·복제 위치·후보 상태를 수집하고 DB 변경을 실행한다.
  • 인프라 담당자는 전원·스토리지·네트워크 상태 및 이전 writer 격리를 확인한다.
  • 애플리케이션 담당자는 재시도 폭증을 제한하고 연결 풀과 결과 불명확 요청을 처리한다.
  • 작업 기록에는 관측 시각·시간대, 관측 지점, 대상 식별자, 변경 전후 값, 실행자, 승인자, 다음 중단 조건을 남긴다. 자동화 도구와 사람이 서로 다른 승격을 동시에 실행하지 않도록 실행 주체도 하나로 정한다.
flowchart TD
    A[연결 오류 또는 쓰기 실패 감지] --> B[관측 시각과 영향 범위 기록]
    B --> C[신규 쓰기와 재시도 폭증 제한]
    C --> D{독립 경로로 상태 확인}
    D --> E[프로세스 종료: 로그와 crash recovery]
    D --> F[공간 부족: 경로와 저장소 분리]
    D --> G[통신 단절: 양측 상태와 quorum]
    E --> H{기존 writer 복구 또는 후보 승격}
    F --> H
    G --> H
    H --> I[단일 writer 보장과 데이터 경계 확인]
    I --> J[연결 갱신과 제한된 업무 검증]
    J --> K[단계적 트래픽 재개]
    H --> L[증거 부족이면 쓰기 중단 유지]

2. 먼저 기록할 것은 접속 성공이 아니라 서버의 상태다

접속이 가능하다면 다음처럼 읽기 전용 상태와 durability 관련 설정을 함께 기록한다. endpoint 이름만 기록하면 장애 조치 후 같은 이름이 다른 서버를 가리켰다는 사실을 놓친다. 실제 사고 기록에는 별도로 server_uuid와 연결 대상 식별자도 보관하되, 외부 공유 문서에는 내부 주소나 계정 정보를 제거한다.

SELECT VERSION() AS mysql_version,
       @@GLOBAL.read_only AS read_only,
       @@GLOBAL.super_read_only AS super_read_only,
       @@GLOBAL.log_bin AS log_bin,
       @@GLOBAL.gtid_mode AS gtid_mode,
       @@GLOBAL.innodb_flush_log_at_trx_commit AS redo_flush,
       @@GLOBAL.sync_binlog AS binlog_sync;

실행 결과(MySQL 8.0.x):

mysql> SELECT VERSION() AS mysql_version,
    ->        @@GLOBAL.read_only AS read_only,
    ->        @@GLOBAL.super_read_only AS super_read_only,
    ->        @@GLOBAL.log_bin AS log_bin,
    ->        @@GLOBAL.gtid_mode AS gtid_mode,
    ->        @@GLOBAL.innodb_flush_log_at_trx_commit AS redo_flush,
    ->        @@GLOBAL.sync_binlog AS binlog_sync;

+---------------+-----------+-----------------+---------+-----------+------------+-------------+
| mysql_version | read_only | super_read_only | log_bin | gtid_mode | redo_flush | binlog_sync |
+---------------+-----------+-----------------+---------+-----------+------------+-------------+
| 8.0.46        |         0 |               0 |       0 | OFF       |          1 |           1 |
+---------------+-----------+-----------------+---------+-----------+------------+-------------+
1 row in set (0.00 sec)

이 결과는 테스트 서버의 설정이지 운영 권장값 전체가 아니다. 특히 log_bin=0, gtid_mode=OFF인 실험 서버는 GTID 복제 후보가 아니다. read_only=0도 해당 서버가 정당한 writer라는 증거는 아니다. topology와 실제 접근 경로를 확인해야 한다.

innodb_flush_log_at_trx_commit과 sync_binlog는 장애 때 잃을 수 있는 최근 변경의 범위를 해석하는 자료다. 설정값만으로 저장장치의 실제 내구성이나 이미 응답한 업무의 복구를 보증할 수는 없다. 또한 비동기 replica의 적용 지연은 원본 서버의 로컬 내구성과 별개다.

같은 시각에 비교할 관측면

  1. 사용자 경로: 연결 수립, 인증, 단순 읽기, 업무 쓰기 중 어디서 실패하는가.
  2. 서버 경로: 프로세스 생존, OOM·I/O 오류, 재시작 횟수, crash recovery 진행 여부는 무엇인가.
  3. 저장 경로: datadir, binlog, relay log, 임시 파일, 운영 로그가 각각 어느 파일시스템에 있는가.
  4. 복제·합의 경로: 수신과 적용 중 어느 부분이 멈췄는가. Group Replication이라면 유효한 과반수 그룹이 있는가.
  5. 제어 경로: 자동 장애 조치가 이미 진행 중인가. 사람이 관측한 상태가 최신 제어 상태와 같은가.

TCP 연결 성공과 SELECT 1 성공은 업무 쓰기 성공을 의미하지 않는다. 반대로 관리망에서 접속할 수 없다는 사실도 프로세스 사망을 증명하지 않는다. 단일 health check 결과만으로 승격하지 않는 이유다.

3. Primary crash: 재시작 복구와 replica 승격을 분리한다

3.1 InnoDB 내부에서는 무엇이 복구되는가

InnoDB는 crash 후 시작할 때 redo를 적용하여 데이터 페이지의 상태를 복구하고, 미커밋 트랜잭션을 rollback한다. redo 적용은 연결을 받기 전 초기화 단계에서 진행된다. 미완료 트랜잭션의 rollback은 서버가 연결을 받기 시작한 뒤에도 이어질 수 있으므로, 접속 재개 직후 특정 행을 기다리거나 I/O가 높은 상황이 남을 수 있다.

따라서 “프로세스가 아직 준비되지 않음”, “서버는 준비되었으나 복구 부하가 남음”, “복구가 오류로 중단됨”을 구별해야 한다. 정상적으로 진행 중인 복구를 짧은 health check 제한 때문에 반복해서 강제 종료하면 복구 시간만 늘고 증거를 잃는다. 로그의 진행 메시지, 오류 반복 여부, 자원 상태를 함께 확인한다.

3.2 대응 순서

① 종료 원인과 재시작 상태를 보존한다. 서비스 관리 로그, MySQL 오류 로그, 커널 OOM·I/O 기록과 직전 배포·DDL 이력을 확보한다. 증거 수집을 위해 장애 복구를 무기한 지연시키지는 않되, datadir 초기화나 로그 삭제처럼 되돌릴 수 없는 작업은 피한다.

② 기존 서버 복구가 안전한지 판단한다. 저장장치가 정상이고 기존 writer를 계속 사용할 계획이라면 통제된 시작과 복구 관찰을 우선할 수 있다. 이미 다른 서버를 승격했다면 이전 서버의 자동 재시작이 업무 쓰기 재개로 이어지지 않도록 격리를 먼저 유지한다.

③ 승격이 필요하면 이전 writer를 fencing한다. fencing은 이전 서버가 더 이상 업무 쓰기를 수락하지 못하도록 강제하는 조치다. 전원 차단이나 검증된 네트워크·스토리지 접근 차단 등을 topology에 맞게 사용한다. 프록시에서 제거하는 것만으로는 직접 연결, 기존 연결, 배치 작업을 모두 막았다는 보장이 없다. super_read_only는 유용한 방어 수단이지만, 접속 불가능한 서버에 적용되었다고 가정할 수 없고 재설정 권한을 가진 경로까지 대체하지도 않는다.

④ 후보의 수신·적용 경계와 손실 가능성을 확인한다. 살아 있는 후보마다 적용 오류, 수신된 미적용 트랜잭션, 실행 GTID 집합, 업무 검증 결과를 비교한다. Seconds_Behind_Source=0 하나로 완전성을 판정하지 않는다. 원본에 접근할 수 없다면 원본만 보유한 마지막 커밋의 범위를 확정하지 못할 수 있다. 이 불확실성을 숨기지 말고 RPO 정책에 따른 승인으로 처리한다.

⑤ 승격과 경로 변경 후 제한된 업무 검증을 수행한다. 새 연결에서 writer 신원과 쓰기를 확인하고, 결과 불명확 요청을 조정한 뒤 트래픽을 단계적으로 연다. 이전 writer는 새 기준 데이터와의 정합성 확인 또는 재구축을 거쳐 replica로 편입한다. 단순히 네트워크가 복구되었다고 다시 쓰기 경로에 넣지 않는다.

3.3 COMMIT 응답 유실은 재실행 허가가 아니다

서버가 COMMIT을 내구화한 다음 응답 전달 전에 연결이 끊길 수 있다. 클라이언트의 시간 초과는 “커밋하지 않음”이 아니라 “결과를 모름”일 수 있다. 재연결 후 주문번호·결제 요청번호 같은 멱등성 키로 결과를 조회하고, 같은 요청의 중복 실행을 방지해야 한다. DB 복구가 끝나도 중복 결제나 중복 작업이 남으면 업무 복구는 끝나지 않은 것이다.

중단 조건: 이전 writer 격리가 불확실하거나, 후보에 해결되지 않은 적용 오류가 있거나, 허용할 데이터 손실 경계의 승인 주체가 없으면 쓰기 재개를 보류한다. innodb_force_recovery는 일반 재시작 옵션이 아니라 손상 상황에서 데이터 구출을 위한 별도 절차다. 값을 높여 서비스 쓰기를 정상화하는 대응으로 사용하지 않는다.

4. Storage full: 공간을 비우기 전에 무엇이 찼는지 구분한다

4.1 하나의 오류가 서로 다른 저장 경로에서 발생한다

공간 부족은 데이터 파일 증가만의 문제가 아니다. binlog 보존량, relay log 적체, 대규모 정렬의 임시 파일, Online DDL의 중간 파일, 장기 트랜잭션에 따른 undo 보존, 운영 로그 증가가 각각 원인이 될 수 있다. 블록 여유가 있어도 inode·quota·tablespace 한도에 걸릴 수 있다. The table is full이라는 메시지도 곧바로 OS 디스크 100%를 뜻하지 않는다.

MySQL 공식 문서의 “디스크가 찼을 때 주기적으로 재시도한다”는 설명에는 MyISAM 및 binlog·binlog index 쓰기라는 적용 범위가 있다. 이를 모든 InnoDB 쓰기 경로에 일괄 적용하면 안 된다. 오류 경로에 따라 문장 실패, 대기, 서버 종료 등 영향이 달라지므로 오류 로그와 실패한 파일을 먼저 연결한다.

4.2 안전한 복구 순서

① 공간을 더 소비하는 작업을 제한한다. 신규 대량 적재, 배치, DDL을 멈추거나 일시 중단할 수 있는지 판단한다. 실행 중 작업 취소도 rollback과 정리에 I/O·시간을 요구하므로, 큰 트랜잭션을 무조건 종료하는 방식은 피한다. 애플리케이션 재시도도 함께 억제한다.

② 파일시스템과 소비자를 확인한다. 관리 권한이 있는 운영체제에서 대상 마운트의 블록·inode 사용량과 quota, 삭제되었으나 프로세스가 열고 있는 파일을 확인한다. DB의 datadir와 tmpdir 위치를 OS 관측과 연결한다. 전체 디스크를 무차별 재귀 스캔하면 장애 중 I/O를 추가하므로 알려진 경로부터 조사한다. 컨테이너 안의 여유와 호스트 볼륨의 여유도 따로 볼 필요가 있다.

③ 확장 또는 검증된 불필요 파일 정리를 선택한다. 볼륨 확대 시 블록 장치 확대와 파일시스템 확대는 별도 단계일 수 있다. 확인된 오래된 운영 로그나 다른 경로로 안전하게 보관한 파일의 정리와, MySQL 관리 파일 삭제는 전혀 다른 작업이다. binlog 정리는 replica가 요구하는 위치와 PITR 보존 경계를 확인한 뒤 MySQL 관리 절차로 수행한다.

④ 회복을 수치와 업무 결과로 확인한다. 확보한 바이트만 보지 말고 증가 속도, 남은 DDL·rollback 작업, 로그 재생성 속도를 확인한다. 쓰기 소량 재개 후 공간 감소 추세와 오류율을 관찰한다. 원인이 지속되면 수 분 뒤 같은 장애가 재발할 수 있다.

즉시 실행해서는 안 되는 조치

  • .ibd, ibdata, redo·undo 파일을 OS 명령으로 삭제하지 않는다. 디렉터리가 커 보인다는 이유는 삭제 근거가 아니다.
  • binlog나 relay log를 파일 단위로 임의 삭제하지 않는다. 복제와 복구에 필요한 이력 및 서버의 관리 상태가 어긋날 수 있다.
  • 대량 DELETE가 곧 파일시스템 여유 증가로 이어진다고 가정하지 않는다. undo·redo·binlog를 추가로 만들고, 해제된 페이지가 파일 내부에서 재사용되는 데 그칠 수 있다.
  • 공간이 부족한 상태에서 OPTIMIZE TABLE을 응급 청소 명령으로 실행하지 않는다. 재구축 자체가 추가 공간과 I/O를 요구할 수 있다.
  • 다른 replica도 같은 적재·보존 정책을 갖는다면 승격만으로 근본 원인이 사라진다고 판단하지 않는다.

5. Network partition: 상대의 침묵을 사망으로 해석하지 않는다

5.1 비동기 복제에는 자체 승격 합의가 없다

비동기 source와 replica가 서로 통신하지 못해도 source는 기존 애플리케이션에 계속 쓰기를 받을 수 있다. 다른 네트워크 구간에서 replica를 승격하면 두 writer가 서로 다른 변경을 받는다. GTID는 트랜잭션 이력을 식별하지만, 이런 분기를 자동으로 병합하거나 충돌을 업무적으로 해결하지 않는다.

네트워크 분할이 의심되면 애플리케이션, DB 관리망, 복제망, 장애 조치 제어기에서 각각 보이는 상태를 비교한다. 연결 방향별 방화벽·라우팅·DNS·TLS 오류를 분리하고, 기존 TCP 연결과 새 연결의 차이도 본다. 제어기 하나의 시간 초과만으로 “이전 writer 종료 확인”을 표시하지 않는다.

5.2 Group Replication에서는 quorum이 안전 경계다

Group Replication은 그룹 결정을 위한 과반수 합의에 의존한다. 과반수를 확보하지 못한 구간은 안전하게 진행할 수 없으며, 실제 대기·탈퇴·재가입 동작은 관련 timeout과 exit action 설정의 영향을 받는다. 단순 비동기 복제의 “가장 최신 replica를 골라 승격” 절차를 그대로 적용하지 않는다.

group_replication_force_members로 강제 멤버 구성을 바꾸는 것은 통신 장애 때마다 실행하는 복구 명령이 아니다. 격리된 반대편이 실제로 살아서 정상 과반수 그룹을 구성했다면 인위적인 split-brain을 만들 수 있다. 반대편 멤버가 확실히 중지·격리되었는지 확인하지 못하면 강제 재구성을 보류한다. InnoDB Cluster를 사용한다면 관리 메타데이터까지 일관되게 다루는 지원 절차를 사용한다.

5.3 접속 가능한 서버에서 읽을 수 있는 진단

다음은 비동기 복제 채널의 수신 상태와 worker의 적용 오류를 분리해 보는 조회다. 전체 오류 메시지에는 주소·SQL 등이 포함될 수 있으므로, 먼저 오류 번호와 상태를 좁혀 확인한다.

SELECT CHANNEL_NAME, SERVICE_STATE, LAST_ERROR_NUMBER
FROM performance_schema.replication_connection_status
ORDER BY CHANNEL_NAME;

SELECT CHANNEL_NAME, WORKER_ID, SERVICE_STATE, LAST_ERROR_NUMBER
FROM performance_schema.replication_applier_status_by_worker
ORDER BY CHANNEL_NAME, WORKER_ID
LIMIT 8;

실행 결과(MySQL 8.0.x):

mysql> SELECT CHANNEL_NAME, SERVICE_STATE, LAST_ERROR_NUMBER
    -> FROM performance_schema.replication_connection_status
    -> ORDER BY CHANNEL_NAME;

Empty set (0.00 sec)

mysql> SELECT CHANNEL_NAME, WORKER_ID, SERVICE_STATE, LAST_ERROR_NUMBER
    -> FROM performance_schema.replication_applier_status_by_worker
    -> ORDER BY CHANNEL_NAME, WORKER_ID
    -> LIMIT 8;

Empty set (0.00 sec)

복제를 구성하지 않은 테스트 서버에서는 두 조회 모두 Empty set이다. 이는 “지연 0이며 정상”이 아니라 이 서버에는 관측할 채널·worker가 없다는 결과다. 실제 운영에서는 기대한 채널의 존재부터 확인하고 coordinator 상태, 수신·적용 위치와 오류 로그를 이어서 조사한다. 이 조회만으로 복제 토폴로지 전체가 정상이라고 판정할 수 없다.

Group Replication 멤버 상태는 별도의 관측면이다.

SELECT MEMBER_ID, MEMBER_STATE, MEMBER_ROLE
FROM performance_schema.replication_group_members
ORDER BY MEMBER_ID;

실행 결과(MySQL 8.0.x):

mysql> SELECT MEMBER_ID, MEMBER_STATE, MEMBER_ROLE
    -> FROM performance_schema.replication_group_members
    -> ORDER BY MEMBER_ID;

Empty set (0.00 sec)

독립 서버의 빈 결과는 그룹 전체의 정상이나 장애를 뜻하지 않는다. 구성된 그룹에서도 한 멤버에서 조회한 결과만으로 반대편의 실제 쓰기 가능 상태를 입증할 수 없다. 여러 관측 지점과 제어 시스템의 기록을 함께 사용한다.

중단 조건: 양쪽의 현재 상태가 불명확하거나, 기존 writer의 접근 차단을 입증할 수 없거나, 합의 기반 구성에서 quorum 복구 경계가 불확실하면 쓰기 중단 상태를 유지한다. 복구 속도를 높이기 위해 안전 장치를 제거하는 대신 관측·격리 경로를 복구한다.

6. 증거가 없으면 보류하는 판정 예제

아래 SQL은 replica 승격 검토에 필요한 최소 자료를 가정하여, 필수 증거가 누락되면 검토를 보류하는 예제다. 실제 서버 상태를 수집하거나 fencing·승격을 수행하지 않는다. loss_boundary_reviewed=1은 손실이 없다는 뜻이 아니라, 확인된 범위와 남은 불확실성에 대한 검토·승인이 있었다는 가정이다. 네트워크 장애 사례는 비동기 복제 후보이며 Group Replication의 quorum 판정을 대신하지 않는다.

NULL을 성공으로 취급하지 않고, 필수 조건 중 하나라도 1이 아니면 보류한다. 조건 통과 문구도 REVIEW_ONLY로 두어 자동 쓰기 개방과 구분한다.

WITH evidence AS (
    SELECT 'crash_unfenced' AS scenario, 0 AS old_writer_fenced,
           1 AS candidate_ready, 1 AS loss_boundary_reviewed,
           1 AS capacity_ok
    UNION ALL SELECT 'crash_reviewed', 1, 1, 1, 1
    UNION ALL SELECT 'storage_still_full', 1, 1, 1, 0
    UNION ALL SELECT 'network_unknown', NULL, 1, 1, 1
    UNION ALL SELECT 'apply_error', 1, 0, 1, 1
    UNION ALL SELECT 'loss_unknown', 1, 1, NULL, 1
)
SELECT scenario,
       CASE
         WHEN COALESCE(old_writer_fenced, 0) <> 1 THEN 'HOLD_FENCING'
         WHEN COALESCE(candidate_ready, 0) <> 1 THEN 'HOLD_CANDIDATE'
         WHEN COALESCE(loss_boundary_reviewed, 0) <> 1 THEN 'HOLD_DATA_BOUNDARY'
         WHEN COALESCE(capacity_ok, 0) <> 1 THEN 'HOLD_CAPACITY'
         ELSE 'REVIEW_ONLY'
       END AS decision
FROM evidence
ORDER BY scenario;

실행 결과(MySQL 8.0.x):

mysql> WITH evidence AS (
    ->     SELECT 'crash_unfenced' AS scenario, 0 AS old_writer_fenced,
    ->            1 AS candidate_ready, 1 AS loss_boundary_reviewed,
    ->            1 AS capacity_ok
    ->     UNION ALL SELECT 'crash_reviewed', 1, 1, 1, 1
    ->     UNION ALL SELECT 'storage_still_full', 1, 1, 1, 0
    ->     UNION ALL SELECT 'network_unknown', NULL, 1, 1, 1
    ->     UNION ALL SELECT 'apply_error', 1, 0, 1, 1
    ->     UNION ALL SELECT 'loss_unknown', 1, 1, NULL, 1
    -> )
    -> SELECT scenario,
    ->        CASE
    ->          WHEN COALESCE(old_writer_fenced, 0) <> 1 THEN 'HOLD_FENCING'
    ->          WHEN COALESCE(candidate_ready, 0) <> 1 THEN 'HOLD_CANDIDATE'
    ->          WHEN COALESCE(loss_boundary_reviewed, 0) <> 1 THEN 'HOLD_DATA_BOUNDARY'
    ->          WHEN COALESCE(capacity_ok, 0) <> 1 THEN 'HOLD_CAPACITY'
    ->          ELSE 'REVIEW_ONLY'
    ->        END AS decision
    -> FROM evidence
    -> ORDER BY scenario;

+--------------------+--------------------+
| scenario           | decision           |
+--------------------+--------------------+
| apply_error        | HOLD_CANDIDATE     |
| crash_reviewed     | REVIEW_ONLY        |
| crash_unfenced     | HOLD_FENCING       |
| loss_unknown       | HOLD_DATA_BOUNDARY |
| network_unknown    | HOLD_FENCING       |
| storage_still_full | HOLD_CAPACITY      |
+--------------------+--------------------+
6 rows in set (0.00 sec)

이 예제는 오류 조건의 우선순위 중 하나만 표시한다. 실제 절차서는 모든 미충족 항목과 증거의 관측 시각을 남겨야 한다. 특히 오래된 fencing 확인이나 후보 검증을 계속 재사용하지 않도록 유효 시간을 정하고, 최종 쓰기 개방 직전에 중요한 조건을 다시 확인한다. 입력값을 사람이 1로 바꾸는 행위는 실제 제어 결과를 읽어 검증한 것과 다르다.

7. Aurora MySQL에서는 같은 장애 이름도 제어 대상이 다르다

Aurora는 컴퓨팅 인스턴스와 분산 클러스터 저장소를 분리한다. 따라서 self-managed MySQL의 로컬 datadir 복구나 Group Replication 강제 quorum 절차를 그대로 옮기지 않는다.

Primary 장애: RDS 이벤트, 현재 writer 식별자, 후보 reader와 가용 영역, promotion tier, endpoint 연결 상태를 확인한다. 관리형 복구·장애 조치가 진행 중인지 먼저 확인하고, 별도의 수동 조치를 중첩하지 않는다. cluster endpoint는 현재 primary를 가리키는 연결 이름이지만, 이미 열린 연결의 트랜잭션을 새 writer로 옮겨 주는 장치는 아니다. 클라이언트는 연결을 갱신하고 결과 불명확 요청을 조정해야 한다. 자동 장애 조치의 존재를 애플리케이션 중단 없음이나 고정된 복구 시간 보장으로 해석하지 않는다.

공간 부족: FreeLocalStorage는 인스턴스 로컬 저장 공간이고, AuroraVolumeBytesLeftTotal은 클러스터 볼륨의 남은 공간이다. 둘 다 바이트 단위이지만 대상이 다르다. 로컬 임시 작업 공간이 부족한 문제와 클러스터 볼륨 상한에 접근한 문제는 해결 경로가 다르다. 엔진 버전·인스턴스 구성과 실제 오류를 확인하고, 무조건 reader 승격이나 인스턴스 확대를 적용하지 않는다. 저장소가 자동으로 증가한다고 모든 공간 부족이 사라지는 것도 아니다.

네트워크 장애: 애플리케이션 구간의 연결 실패와 Aurora 내부 writer 상태를 구분한다. RDS 제어 정보, 이벤트, 다중 가용 영역의 접속 결과를 함께 확인한다. 관리형 데이터 복구와 보안 그룹·DNS·연결 풀 복구는 다른 작업이다. 일반적인 cluster 내 장애 조치와 Global Database의 리전 간 재해복구도 별도 절차로 관리한다.

이 절의 설명은 AWS 공식 문서의 동작·지표 정의에 근거한 운영 해석이다. 로컬 SQL 검증으로 Aurora 장애 조치나 저장소 회복을 실험한 것은 아니다.

8. 복구 완료와 되돌리기의 경계를 기록한다

장애 조치 이후 DNS나 프록시를 이전 서버로 되돌리는 것은 단순한 UI 변경처럼 보이지만, 새 writer에서 업무 쓰기가 발생했다면 데이터 이력이 이미 달라졌다. 첫 업무 쓰기 전에는 조건을 재확인하고 전환을 취소할 수 있는 경우가 있지만, 첫 업무 쓰기 이후의 복귀는 데이터 동기화·검증을 포함하는 별도 전환이다. 원래 서버가 다시 켜졌다는 이유만으로 원복하지 않는다.

복구 완료는 DB 접속 성공 시각이 아니라 정해진 범위의 업무가 다시 안전하게 처리되는 상태로 정의한다. 서버 준비 시각, 경로 갱신 시각, 첫 검증 쓰기 시각, 업무 트래픽 회복 시각을 구분해서 남겨야 다음 리허설에서 병목을 찾을 수 있다.

현장 점검표

9. 정리와 참고 문서

Primary crash의 핵심은 복구 진행과 승격 경계를 구별하는 것이고, storage full의 핵심은 파일별 책임과 복구에 필요한 여유를 확보하는 것이다. Network partition의 핵심은 상대가 보이지 않는다는 사실을 상대가 쓰지 못한다는 증거로 바꾸지 않는 것이다. 세 경우 모두 단일 writer, 명시적인 데이터 경계, 결과 불명확 요청 처리라는 공통 조건으로 수렴한다.

다음 단계의 운영 문서는 이 판단 흐름을 실제 topology와 승인 체계에 연결하고, 폐기 가능한 환경에서 각 중단 조건이 작동하는지 시험해야 한다. 문서에 적힌 명령 수보다 잘못된 승격과 성급한 쓰기 재개를 차단하는 증거의 품질이 중요하다.