MySQL InnoDB 엔진의 Redo Log가 당신의 시작을 구했을 때

발행: (2025년 12월 7일 오후 12:07 GMT+9)
7 min read
원문: Dev.to

Source: Dev.to

등대지기 비유

InnoDB의 redo log를 등대지기의 일지라고 생각해 보세요.

현대 GPS가 나오기 전, 등대지기들은 꼼꼼히 일지를 기록했습니다:

  • “오후 3시 15분 — 북쪽으로 선박이 지나감.”
  • “오후 4시 22분 — 안개 때문에 등대 점등.”
  • “오후 5시 03분 — 바람이 서쪽으로 전환.”

뭔가 문제가 생기면 조사관들은 일지를 읽어 무슨 일이 있었는지 재구성할 수 있었습니다.

InnoDB도 같은 방식으로 동작합니다. 어떤 작업을 바꾸기 전에 먼저 redo log에 기록합니다:

“테이블 users의 행 47을 업데이트하려고 합니다. 여기서 바뀌는 내용은 …”

write‑ahead logging (WAL) 은 크래시, 전원 장애, 그리고 RAM의 비트를 뒤집는 우주선까지도 대비하는 안전망입니다.

Note: 등대지기가 병목이 될 수 있습니다.

우리를 거의 죽음에 이르게 한 트랜잭션 패턴

우리 애플리케이션은 금융 트랜잭션을 빠르게 처리했습니다—피크 시 초당 ~5,000 건의 쓰기 작업을 수행했습니다.

전형적인 트랜잭션은 다음과 같았습니다:

-- 초당 수천 번 실행
START TRANSACTION;

UPDATE accounts 
SET balance = balance - 100 
WHERE user_id = ?;

INSERT INTO transaction_log 
(user_id, amount, timestamp) 
VALUES (?, 100, NOW());

UPDATE user_metadata 
SET last_transaction = NOW() 
WHERE user_id = ?;

COMMIT;

겉보기엔 무해해 보이죠? 틀렸습니다. 이 패턴이 우리 redo log 시스템을 조용히 질식시키고 있었습니다.

Redo Log: 기술적 깊이 탐구 (지루한 부분 제외)

InnoDB 내부에서 일어나는 일을 시각화하면:

┌─────────────────────────────────────────────────────┐
│  Transaction Flow                                    │
├─────────────────────────────────────────────────────┤
│  1. Client: "UPDATE accounts..."                     │
│          │                                          │
│          ▼                                          │
│  2. InnoDB: Write to REDO LOG (on disk)              │
│          [Sequential write - fast! ⚡]              │
│          │                                          │
│          ▼                                          │
│  3. InnoDB: Update buffer pool (in RAM)              │
│          [Random access - still fast! 💨]          │
│          │                                          │
│          ▼                                          │
│  4. Client: "COMMIT"                                 │
│          │                                          │
│          ▼                                          │
│  5. InnoDB: Flush redo to disk (fsync)               │
│          [This is where we wait... 🐌]             │
└─────────────────────────────────────────────────────┘

핵심 인사이트: Redo 쓰기는 순차적(빠름)인데 fsync는 매우 느림—특히 부하가 클 때. 초당 5,000 건의 트랜잭션마다 디스크 플러시가 필요했으니, 저장소에 초당 5,000 개의 동기식 작업을 요구한 셈이며, 이는 SSD조차 싫어하는 상황이었습니다.

조사 결과: 모든 것을 바꾼 네 가지 변수

1. innodb_flush_log_at_trx_commit

-- 가장 안전하지만 가장 느림
SET GLOBAL innodb_flush_log_at_trx_commit = 1;

-- OS 캐시 사용, 더 빠름
SET GLOBAL innodb_flush_log_at_trx_commit = 2;

-- 위험하지만 가장 빠름
SET GLOBAL innodb_flush_log_at_trx_commit = 0;
설정내구성성능사용 사례
1완전 ACID가장 느림금융 데이터
2OS 캐시빠름웹 애플리케이션
0위험가장 빠름분석 작업

우리는 2 로 전환했고, 10배의 처리량 향상을 얻었습니다.

2. innodb_log_file_size

redo log는 원형 버퍼입니다:

[Checkpoint] ---> ███████ write position ---> (wrap)

쓰기 포인터가 체크포인트에 도달하면 정체가 발생합니다.

SHOW VARIABLES LIKE 'innodb_log_file_size';

우리는 파일 크기를 48 MB에서 2 GB × 2 파일 = 4 GB 로 늘렸습니다.
경험 법칙: 피크 쓰기를 ≈ 1시간 정도 버틸 수 있을 만큼 크게 잡으세요.

3. innodb_flush_method

SET GLOBAL innodb_flush_method = 'O_DIRECT';

이 설정은 이중 캐싱을 방지하고 I/O 대기 시간을 30 % 줄였습니다.

4. 커밋을 배치하세요

이전:

5000 commits/sec → 5000 fsync calls

배치 후:

100 commits/sec → 100 fsync calls

결과: 디스크 작업이 50배 감소했습니다.

읽기 전용 트랜잭션 비밀 무기

START TRANSACTION READ ONLY;

SELECT SUM(balance)
FROM accounts
WHERE region = 'US-WEST';

COMMIT;

InnoDB는 이후:

  • redo 로그 기록을 건너뜀
  • 락을 건너뜀
  • 트랜잭션 ID 생성을 건너뜀

결과: 보고 쿼리에서 ≈ 4배 빠르게 동작합니다.

Redo Log 모니터링

SELECT 
  'Redo Log Usage' AS metric,
  ROUND(
    (SELECT VARIABLE_VALUE 
     FROM performance_schema.global_status 
     WHERE VARIABLE_NAME = 'Innodb_os_log_written') / 1024 / 1024,
    2
  ) AS value
UNION ALL
SELECT 
  'Log Waits',
  (SELECT VARIABLE_VALUE 
   FROM performance_schema.global_status 
   WHERE VARIABLE_NAME = 'Innodb_log_waits')
UNION ALL
SELECT 
  'Checkpoint Age',
  ROUND(
    (SELECT VARIABLE_VALUE 
     FROM performance_schema.global_status 
     WHERE VARIABLE_NAME = 'Innodb_checkpoint_age') / 1024 / 1024,
    2
  );

Innodb_log_waits > 0이면 → redo log가 너무 작다는 의미입니다.

프로덕션 최적화 플레이북

  1. 최적화 전 프로파일링

    SET GLOBAL slow_query_log = 1;
    SET GLOBAL long_query_time = 0.1;
    SET GLOBAL log_slow_extra = 1;
  2. Redo Log 적정 크기 설정
    일일 메트릭을 활용해 피크 시간의 ≈ 2배 크기로 로그 파일을 잡으세요.

  3. 벤치마크로 내구성 설정 테스트
    innodb_flush_log_at_trx_commit 값을 1, 2, 0 으로 비교합니다.

  4. 보고 및 분석에는 읽기 전용 트랜잭션 사용.

교훈

  • redo log는 안전망이자 병목입니다.
  • 모든 내구성 보장은 성능 비용을 동반합니다.
  • 로그 파일 크기 조정은 미션 크리티컬합니다.
  • 읽기 전용 트랜잭션은 크게 활용되지 않고 있습니다.
  • 쓰기 배치는 대규모 환경에서 가장 강력한 최적화 중 하나입니다.

추가 읽을거리

  • MySQL InnoDB Documentation: Redo Log
  • Percona: Tuning InnoDB Redo Logging
  • High Performance MySQL (O’Reilly)

Tags: #mysql #database #performance #devops

Back to Blog

관련 글

더 보기 »