0Pricing
SQL Academy · 강의

재해 복구 계획

RPO, RTO 및 런북입니다

재해 복구 계획은(는) CoddyKit의 무료 SQL Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 SQL Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. SQL Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

재해 복구란 무엇인가요

재해 복구(DR)는 자연재해 또는 인재가 발생한 후 핵심 기술 인프라와 시스템을 복구할 수 있도록 설계된 정책, 도구 및 절차의 집합입니다.

데이터베이스의 맥락에서 재해 복구 계획은 하드웨어 고장, 실수로 인한 데이터 삭제, 랜섬웨어 공격 또는 데이터 센터 중단과 같은 사건 이후에도 데이터를 안전하게 유지하고 시스템을 허용 가능한 시간 내에 다시 온라인으로 전환할 수 있도록 보장합니다.

복구 시점 목표(RPO)

RPO는 시간으로 측정한 허용 가능한 최대 데이터 손실량을 정의합니다. RPO가 1시간이라면 재해가 발생한 시점보다 최소 1시간 전까지의 데이터를 복구할 수 있어야 합니다.

RPO가 짧을수록 더 자주 백업하거나 지속적으로 복제해야 합니다. 백업 이력을 조회하여 RPO 목표를 충족하고 있는지 확인할 수 있습니다.

-- Check the last backup time and calculate data loss window
SELECT
  backup_id,
  backup_type,
  started_at,
  finished_at,
  EXTRACT(EPOCH FROM (NOW() - finished_at)) / 3600 AS hours_since_backup
FROM backup_log
WHERE status = 'SUCCESS'
ORDER BY finished_at DESC
LIMIT 5;

복구 시간 목표(RTO)

RTO는 재해 발생 후 시스템이 오프라인 상태로 있어도 되는 최대 시간을 정의합니다. RTO가 4시간이라면 데이터베이스가 장애 발생 후 4시간 이내에 완전히 작동해야 합니다.

RTO는 대기 서버, 장애 조치 자동화 및 복원 절차에 관한 결정을 좌우합니다. 시간에 따른 복원 소요 시간을 추적하면 RTO를 충족할 수 있을지 예측하는 데 도움이 됩니다.

-- Track restore durations to validate RTO compliance
SELECT
  restore_id,
  triggered_at,
  completed_at,
  EXTRACT(EPOCH FROM (completed_at - triggered_at)) / 60 AS restore_minutes,
  CASE
    WHEN EXTRACT(EPOCH FROM (completed_at - triggered_at)) / 3600 <= 4
    THEN 'WITHIN RTO'
    ELSE 'RTO BREACHED'
  END AS rto_status
FROM restore_log
ORDER BY triggered_at DESC;

RPO와 RTO — 핵심 차이

이 두 지표는 자주 혼동됩니다. 다음과 같이 기억하면 가장 간단합니다:

  • RPO = 감수할 수 있는 데이터 손실량은 얼마인가요? (과거 지향적이며 재해 이전 시간을 기준으로 측정)
  • RTO = 시스템을 얼마나 오래 중단 상태로 둘 수 있나요? (미래 지향적이며 재해 이후 시간을 기준으로 측정)

두 지표는 함께 복구 시간 범위를 정의하며 백업 빈도, 복제 전략 및 인프라 예산에 직접적인 영향을 줍니다.

-- Store RPO and RTO targets per database in a DR configuration table
CREATE TABLE dr_config (
  db_name       VARCHAR(100) PRIMARY KEY,
  rpo_minutes   INT NOT NULL,
  rto_minutes   INT NOT NULL,
  tier          VARCHAR(20) CHECK (tier IN ('CRITICAL', 'HIGH', 'MEDIUM', 'LOW')),
  updated_at    TIMESTAMP DEFAULT NOW()
);

INSERT INTO dr_config (db_name, rpo_minutes, rto_minutes, tier) VALUES
  ('orders_db',    15,   60, 'CRITICAL'),
  ('analytics_db', 120, 240, 'MEDIUM'),
  ('archive_db',   480, 480, 'LOW');

백업 유형

속도와 저장 공간 사이의 균형을 이루는 세 가지 주요 백업 전략이 있습니다:

  • 전체 백업: 전체 데이터베이스의 완전한 스냅샷입니다. 생성 속도는 가장 느리지만 복원 속도는 가장 빠릅니다.
  • 차등 백업: 마지막 전체 백업 이후의 변경 사항만 저장합니다. 생성과 복원 모두 속도가 중간 정도입니다.
  • 증분 백업: 종류와 관계없이 마지막 백업 이후의 변경 사항만 저장합니다. 생성 속도는 가장 빠르지만 복원 속도는 가장 느립니다(여러 파일이 필요함).

대부분의 재해 복구 전략은 RPO와 저장 비용의 균형을 위해 주간 전체 백업과 일일 증분 백업을 결합합니다.

-- Log each backup with its type for audit and recovery planning
CREATE TABLE backup_log (
  backup_id   SERIAL PRIMARY KEY,
  db_name     VARCHAR(100) NOT NULL,
  backup_type VARCHAR(20) CHECK (backup_type IN ('FULL', 'DIFFERENTIAL', 'INCREMENTAL')),
  started_at  TIMESTAMP NOT NULL,
  finished_at TIMESTAMP,
  size_mb     NUMERIC(12, 2),
  status      VARCHAR(20) DEFAULT 'IN_PROGRESS'
);

INSERT INTO backup_log (db_name, backup_type, started_at, finished_at, size_mb, status) VALUES
  ('orders_db', 'FULL',        '2024-06-01 01:00:00', '2024-06-01 02:15:00', 45200, 'SUCCESS'),
  ('orders_db', 'INCREMENTAL', '2024-06-02 01:00:00', '2024-06-02 01:08:00',   320, 'SUCCESS'),
  ('orders_db', 'INCREMENTAL', '2024-06-03 01:00:00', '2024-06-03 01:07:00',   290, 'SUCCESS');

시점 복구(PITR)

시점 복구를 사용하면 마지막 백업 시점뿐 아니라 특정 시점으로 데이터베이스를 복원할 수 있습니다. 기본 백업 위에 트랜잭션 로그(PostgreSQL의 WAL)를 재생하여 이를 수행합니다.

PITR은 알려진 시점에 발생한 실수로 인한 데이터 손상이나 삭제에서 복구해야 할 때 필수적입니다. 손상을 일으킨 사건이 발생하기 직전으로 복원할 수 있습니다.

-- Record WAL archive events for PITR tracking
CREATE TABLE wal_archive_log (
  segment_name  VARCHAR(200) PRIMARY KEY,
  archived_at   TIMESTAMP DEFAULT NOW(),
  size_bytes    BIGINT,
  storage_path  TEXT
);

-- Find all WAL segments archived within a recovery window
SELECT
  segment_name,
  archived_at,
  ROUND(size_bytes / 1024.0 / 1024.0, 2) AS size_mb
FROM wal_archive_log
WHERE archived_at BETWEEN '2024-06-03 09:00:00' AND '2024-06-03 11:00:00'
ORDER BY archived_at;

대기 데이터베이스와 복제

대기(복제본) 데이터베이스는 별도의 하드웨어에서 실행되며 주 데이터베이스를 지속적으로 업데이트하는 사본입니다. 재해 복구에서는 다음 두 가지 목적으로 사용됩니다:

  • 핫 대기: 읽기 쿼리를 처리할 수 있고 수 초 안에 장애 조치가 이루어집니다(거의 0에 가까운 RTO).
  • 웜 대기: 동기화된 상태로 유지되지만 트래픽을 처리하지 않으며 장애 조치에 몇 분이 걸립니다.

복제 지연을 모니터링하는 것은 매우 중요합니다 — 지연되는 복제본은 실제 RPO가 예상보다 나쁘다는 뜻입니다.

-- Monitor replication lag on a PostgreSQL primary
SELECT
  client_addr,
  application_name,
  state,
  sent_lsn,
  replay_lsn,
  (sent_lsn - replay_lsn) AS lag_bytes,
  EXTRACT(EPOCH FROM (NOW() - reply_time)) AS seconds_since_reply
FROM pg_stat_replication
ORDER BY lag_bytes DESC;

운영 절차서: 복구 절차 문서화

운영 절차서는 재해 복구 상황에서 운영자가 따르는 단계별 지침을 문서화한 것입니다. 운영 절차서가 없으면 숙련된 데이터베이스 관리자도 압박을 받는 상황에서 큰 비용이 드는 실수를 저지를 수 있습니다.

좋은 재해 복구 운영 절차서에는 연락할 사람, 영향을 받는 시스템, 실행할 정확한 명령어, 각 단계에서 예상되는 결과 및 복구에 실패했을 때의 되돌리기 절차가 포함됩니다. 운영 절차서 메타데이터를 데이터베이스에 저장하면 버전 관리와 사용 감사 추적에 도움이 됩니다.

-- Store runbook metadata in the database for audit tracking
CREATE TABLE runbook (
  runbook_id   SERIAL PRIMARY KEY,
  title        VARCHAR(200) NOT NULL,
  scenario     VARCHAR(100),
  version      VARCHAR(20) DEFAULT '1.0',
  last_tested  DATE,
  owner        VARCHAR(100),
  doc_url      TEXT
);

INSERT INTO runbook (title, scenario, version, last_tested, owner, doc_url) VALUES
  ('Full Database Restore from S3', 'total_loss',     '2.1', '2024-05-15', 'dba_team', 'https://wiki.internal/dr/full-restore'),
  ('Failover to Hot Standby',       'primary_down',   '1.4', '2024-04-20', 'dba_team', 'https://wiki.internal/dr/failover'),
  ('PITR to Specific Timestamp',    'data_corruption','1.2', '2024-03-10', 'dba_team', 'https://wiki.internal/dr/pitr');

운영 절차서 실행 기록

운영 절차서는 실제 재해 상황에서든 훈련 중에서든 실행할 때마다 기록해야 합니다. 실행 기록을 사용하면 실제 복구에 걸리는 시간(RTO 충족 여부)을 측정하고, 느리거나 오류가 발생하기 쉬운 단계를 찾아내며, 감사 담당자에게 규정 준수 사실을 입증할 수 있습니다.

-- Log each runbook execution for RTO validation and audit
CREATE TABLE runbook_execution (
  execution_id  SERIAL PRIMARY KEY,
  runbook_id    INT REFERENCES runbook(runbook_id),
  triggered_by  VARCHAR(100),
  is_drill      BOOLEAN DEFAULT FALSE,
  started_at    TIMESTAMP NOT NULL,
  completed_at  TIMESTAMP,
  outcome       VARCHAR(20) CHECK (outcome IN ('SUCCESS', 'PARTIAL', 'FAILED'))
);

-- Report average restore time per runbook
SELECT
  r.title,
  COUNT(*) AS executions,
  ROUND(AVG(EXTRACT(EPOCH FROM (e.completed_at - e.started_at)) / 60), 1) AS avg_minutes,
  MAX(EXTRACT(EPOCH FROM (e.completed_at - e.started_at)) / 60) AS max_minutes
FROM runbook_execution e
JOIN runbook r ON r.runbook_id = e.runbook_id
WHERE e.outcome = 'SUCCESS'
GROUP BY r.title;

재해 복구 테스트: 정기 훈련

한 번도 테스트하지 않은 재해 복구 계획은 계획이 아니라 희망 사항입니다. 팀이 정의된 RTO 내에 실제로 운영 절차서를 실행하고 백업을 제대로 복원할 수 있도록 정기 훈련을 반드시 실시해야 합니다.

데이터베이스에서 훈련 일정을 예약하고 추적하면 감사 추적 기록이 생성되고 테스트 기한이 지난 운영 절차서를 찾는 데 도움이 됩니다.

-- Find runbooks that have not been drilled in over 90 days
SELECT
  r.runbook_id,
  r.title,
  r.scenario,
  MAX(e.completed_at) AS last_drill,
  CURRENT_DATE - MAX(e.completed_at::DATE) AS days_since_drill
FROM runbook r
LEFT JOIN runbook_execution e
  ON e.runbook_id = r.runbook_id
  AND e.is_drill = TRUE
  AND e.outcome = 'SUCCESS'
GROUP BY r.runbook_id, r.title, r.scenario
HAVING MAX(e.completed_at) IS NULL
    OR CURRENT_DATE - MAX(e.completed_at::DATE) > 90
ORDER BY days_since_drill DESC NULLS FIRST;

백업 보존 정책

보존 정책은 백업을 얼마나 오래 유지할지 정의합니다. 모든 백업을 영구적으로 보관하면 저장 공간이 낭비되고, 너무 빨리 삭제하면 RPO와 규정 준수 요구 사항을 위반하게 됩니다.

일반적인 정책은 일일 증분 백업을 7일간, 주간 전체 백업을 4주간, 월간 전체 백업을 12개월간 보관하는 것입니다. 백업 기록을 대상으로 SQL 쿼리를 실행하여 보존을 적용하고 감사할 수 있습니다.

-- Identify backups that are outside their retention window and ready to purge
SELECT
  backup_id,
  db_name,
  backup_type,
  finished_at,
  CURRENT_DATE - finished_at::DATE AS age_days,
  CASE backup_type
    WHEN 'INCREMENTAL' THEN 7
    WHEN 'DIFFERENTIAL' THEN 28
    WHEN 'FULL'         THEN 365
  END AS retention_days,
  CASE
    WHEN (CURRENT_DATE - finished_at::DATE) >
         CASE backup_type
           WHEN 'INCREMENTAL' THEN 7
           WHEN 'DIFFERENTIAL' THEN 28
           WHEN 'FULL'         THEN 365
         END
    THEN 'PURGE'
    ELSE 'KEEP'
  END AS action
FROM backup_log
WHERE status = 'SUCCESS'
ORDER BY finished_at;

빠른 확인

RPO와 RTO의 정의를 얼마나 이해했는지 확인해 보세요.

요약: 재해 복구 계획

이 레슨에서는 데이터베이스 재해 복구 계획의 기초를 살펴보았습니다.

  • RPO는 시간 기준으로 허용 가능한 최대 데이터 손실량을 정의합니다. RPO가 짧을수록 더 자주 백업하거나 지속적으로 복제해야 합니다.
  • RTO는 시스템을 얼마나 신속하게 복원해야 하는지 정의합니다. RTO가 짧을수록 핫 스탠바이와 자동 장애 조치가 필요합니다.
  • 백업 유형인 전체, 차등, 증분 백업은 각각 저장 공간, 생성 속도, 복원 속도 사이에서 서로 다른 절충점을 제공합니다.
  • PITR(특정 시점 복구)은 트랜잭션 로그를 사용해 원하는 정확한 시점으로 복원하므로, 실수로 변경한 내용을 보호할 수 있습니다.
  • 운영 절차서에는 복구 절차의 모든 단계가 기록됩니다. 실행 기록을 남기면 실제로 RTO를 달성할 수 있는지 검증할 수 있습니다.
  • 정기적인 DR 훈련만이 백업을 복원할 수 있는지, 그리고 실제 압박 속에서 팀이 RPO와 RTO 목표를 충족할 수 있는지 확인하는 방법입니다.
  • 보존 정책은 저장 비용과 규정 준수 및 복구 요구 사항 사이의 균형을 맞춥니다.

충분히 검증된 DR 계획은 데이터베이스 팀이 할 수 있는 가장 가치 있는 투자 중 하나입니다.

자주 묻는 질문

“재해 복구 계획” 강의는 무료인가요?

네 — “재해 복구 계획” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 SQL Academy 강의 전체를 잠금 해제할 수 있습니다. SQL Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“재해 복구 계획”에서 뭘 배우나요?

RPO, RTO 및 런북입니다 브라우저에서 직접 실행하는 실습 코드로 SQL Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

SQL Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 SQL Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“재해 복구 계획” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 SQL Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 SQL Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 논리적 백업과 물리적 백업
  2. 특정 시점 복구
  3. 복원 테스트하기
  4. 재해 복구 계획
← SQL Academy(으)로 돌아가기