LLM WikiAccess-protected knowledge portal

WIKI

MariaDB 12.3 InnoDB 기반 바이너리 로그: 10년 된 2PC를 없애고 쓰기 커밋 경로를 다시 그은 방식

왜 지금 봐야 하나 MySQL과 MariaDB에서 높은 쓰기 부하를 다루는 DBA가 필연적으로 마주치는 두 가지 파라미터가 있다. sync binlog=1 과 innodb flush log at trx commit=1 다. 둘 다 데이터 안전성을 위해 필요하지만, 둘을 함께 켜면 트랜잭션 커밋마다 최소 두 번의 fsync가 발생한다. 하나는 바이너리 로그, 하나는 InnoDB redo log를 위해서다. 이 두 번의 fsync

경로human/study/content/database-frontier/47-mariadb-12-3-binlog-innodb-2pc-elimination.md
카테고리Study
태그#2pc #binlog #elimination #innodb #mariadb #mysql #study

왜 지금 봐야 하나

MySQL과 MariaDB에서 높은 쓰기 부하를 다루는 DBA가 필연적으로 마주치는 두 가지 파라미터가 있다. sync_binlog=1innodb_flush_log_at_trx_commit=1다. 둘 다 데이터 안전성을 위해 필요하지만, 둘을 함께 켜면 트랜잭션 커밋마다 최소 두 번의 fsync가 발생한다. 하나는 바이너리 로그, 하나는 InnoDB redo log를 위해서다.

이 두 번의 fsync는 단순한 설계 선택이 아니다. XA 두 단계 커밋(2PC) 프로토콜의 구조적 결과다. 바이너리 로그와 InnoDB는 서로 독립된 트랜잭션 관리자이기 때문에, 커밋의 일관성을 보장하려면 두 레이어가 준비 단계와 완료 단계를 각각 거쳐야 한다. 이 설계는 MySQL 5.0 시절부터 이어져온 것이다.

MariaDB 12.3은 2026년 5월 28일 12.3.2 LTS 버전으로 출시되면서 이 구조를 근본적으로 바꿨다. 바이너리 로그를 InnoDB 엔진 내부에 저장하는 InnoDB 기반 바이너리 로그를 도입해, binlog와 InnoDB 사이의 2PC를 제거했다. 커밋 경로에서 fsync 횟수가 절반으로 줄고, 별도의 sync_binlog 설정 없이도 crash-safe 상태가 된다.

이 글은 기존 2PC의 구조와 문제, 새 바이너리 로그의 커밋 경로, 설정 방법, 그리고 운영에서 확인해야 할 경계를 다룬다.


기존 2PC와 새 InnoDB 기반 바이너리 로그 커밋 경로 비교

MariaDB 커밋 경로: 기존 XA 2PC vs InnoDB 기반 바이너리 로그 기존 XA 두 단계 커밋 (2PC) binlog ↔ InnoDB 각각 별도 트랜잭션 관리자 ① BEGIN — InnoDB: undo log 기록 ② InnoDB: XA PREPARE (redo log에 prepare 기록) ③ 바이너리 로그 파일(.binlog)에 이벤트 쓰기 sync_binlog=1 → fsync() ← 첫 번째 fsync ④ InnoDB: COMMIT (redo log에 commit 기록) innodb_flush_log_at_trx_commit=1 → fsync() ← 두 번째 fsync 결과: 커밋당 2회 fsync binlog fsync + InnoDB redo fsync → 높은 커밋 지연 · IOPS 소모 실측 커밋 지연 (5K 짧은 트랜잭션 배치) 기존 방식: 약 12ms sync_binlog=1 + innodb_flush_log_at_trx_commit=1 Crash 안전성 딜레마 sync_binlog=0 이면 binlog가 비일관될 수 있음 sync_binlog=1 이면 성능 희생 필수 InnoDB 기반 바이너리 로그 (MariaDB 12.3) binlog 이벤트 = InnoDB redo log 내 단일 write ① BEGIN — InnoDB: undo log 기록 ② InnoDB: binlog 이벤트 + 데이터 변경을 단일 redo log write 바이너리 로그 이벤트가 InnoDB redo log와 원자적으로 기록됨 ③ InnoDB: COMMIT (redo log fsync) innodb_flush_log_at_trx_commit=1 → fsync() ← 단 하나의 fsync 결과: 커밋당 1회 fsync InnoDB redo log만 — binlog 별도 fsync 없음 sync_binlog 설정 불필요 (무시됨) 실측 커밋 지연 (동일 조건) InnoDB 기반 binlog: 약 7ms 12ms → 7ms (약 42% 감소) Crash 안전성: 설정 없이 기본 보장 binlog 이벤트가 InnoDB crash recovery에 포함됨 innodb_flush_log_at_trx_commit=0 이어도 일관성 유지 재시작 후 binlog ↔ 테이블 상태가 자동으로 일치 복제 일관성도 crash recovery와 함께 복원됨
MariaDB 12.3 InnoDB 기반 바이너리 로그: 2PC 제거 전후 커밋 경로 비교

기존 XA 2PC 구조: 왜 두 번 쓰고 두 번 기다렸나

MySQL과 MariaDB는 바이너리 로그와 InnoDB를 별도의 트랜잭션 관리자로 취급해왔다. 하나의 커밋이 두 레이어 모두에 반영되어야 일관된 상태가 된다. 이를 보장하기 위해 XA 2PC(두 단계 커밋)를 사용한다.

준비 단계(PREPARE)에서 InnoDB가 redo log에 prepare 레코드를 남긴다. 이후 바이너리 로그에 이벤트를 쓰고 fsync로 디스크에 내린다. 완료 단계(COMMIT)에서 InnoDB redo log에 commit 레코드를 쓰고 다시 fsync한다.

crash 시 복구는 이 두 레이어의 상태를 비교해 판단한다. InnoDB에 prepare만 있고 binlog에 없으면 롤백, 둘 다 있으면 커밋으로 결론짓는다. 이 구조가 안전하지만 두 번의 fsync가 불가피하다.

sync_binlog=0으로 설정하면 binlog fsync를 생략할 수 있지만, crash 시 binlog가 테이블 상태와 불일치할 위험이 있다. 복제 환경에서 이 불일치는 replication 오류로 이어진다. 결국 실제 운영에서는 sync_binlog=1을 유지하는 경우가 많았고, 이것이 성능 병목이 됐다.


InnoDB 기반 바이너리 로그의 동작 방식

MariaDB 12.3에서 binlog_storage_engine=innodb를 설정하면 바이너리 로그 구현이 완전히 바뀐다.

바이너리 로그 이벤트가 별도 파일이 아닌 InnoDB 테이블스페이스 내부에 저장된다. 파일 확장자는 .ibb(InnoDB Binlog Binary)다. 파일 크기는 max_binlog_size(기본 1GB)로 사전 할당된다. InnoDB의 페이지 기반 구조로 관리되므로 InnoDB crash recovery의 일부로 자동 처리된다.

커밋 경로의 핵심 변화는 바이너리 로그 이벤트 기록이 InnoDB redo log write와 원자적으로 결합된다는 점이다. binlog 이벤트는 이제 InnoDB 트랜잭션의 일부로 redo log에 함께 기록된다. 별도의 2PC 없이 InnoDB의 단일 커밋 경로에 합쳐지므로, fsync도 InnoDB redo log의 한 번으로 끝난다.

sync_binlog는 더 이상 의미가 없다. 이 설정은 새 구현에서 무시된다. innodb_flush_log_at_trx_commit=0으로 설정해도 crash 후 binlog와 InnoDB 상태가 일관되게 복구된다. 두 레이어가 같은 물리 파일에 있기 때문이다.


설정 방법

기존 설정에서 두 줄을 변경한다.

# my.cnf / mariadb.conf

# 바이너리 로그 활성화 (기존과 동일)
log_bin = /var/lib/mysql/mysql-bin

# InnoDB 기반 바이너리 로그 활성화 (신규)
binlog_storage_engine = innodb

# sync_binlog 설정은 더 이상 효과 없음 — 제거하거나 남겨도 무방
# sync_binlog = 1   ← 이제 무시됨

binlog_storage_engine=innodb는 MariaDB 12.3에서 처음 도입된 파라미터다. 기본값은 기존 파일 기반(file)으로 유지되므로, 명시적으로 설정해야 새 구현이 적용된다.

서버 재시작 후 데이터 디렉터리에 .ibb 확장자 파일이 생성되면 정상 적용된 것이다.

-- 현재 binlog 저장 엔진 확인
SHOW VARIABLES LIKE 'binlog_storage_engine';

-- 생성된 binlog 파일 목록 확인
SHOW BINARY LOGS;

복제와의 관계

복제 관점에서 바이너리 로그의 내용(이벤트 포맷)은 바뀌지 않는다. replica는 기존과 동일하게 mysqlbinlog나 복제 스레드를 통해 이벤트를 읽는다. .ibb 파일은 물리 저장 포맷의 변화이며, 복제 프로토콜 수준에서는 동일한 Row/Statement/Mixed 포맷 이벤트가 전달된다.

반드시 확인해야 할 경계: GTID 기반 복제 환경에서 primary를 12.3으로 업그레이드할 때, replica가 여전히 기존 MariaDB 버전이라면 복제 자체는 정상 작동한다. 단, primary를 12.3으로 교체한 직후 replica에서 SHOW SLAVE STATUS를 통해 복제 지연과 오류 여부를 확인해야 한다. 이벤트 내용은 동일하지만 내부 저장 경로가 바뀐 만큼, 처음 몇 분간 모니터링이 필요하다.

도입 전 확인
MariaDB 12.3.2 LTS 이상인지 확인 (12.3.2는 2026-05-28 출시)
기존 .binlog 파일 백업 완료 여부 확인
sync_binlog, innodb_flush_log_at_trx_commit 현재값 문서화
replica 버전과 복제 상태 확인
설정 변경
my.cnf에 binlog_storage_engine=innodb 추가
sync_binlog=1 제거 또는 주석 처리
서버 재시작 후 .ibb 파일 생성 확인
SHOW BINARY LOGS로 새 파일 목록 확인
도입 후 검증
커밋 지연 측정 (before/after sysbench 또는 PT-query-digest)
SHOW SLAVE STATUS로 복제 지연 확인
Crash 시뮬레이션(스테이징) — 재시작 후 binlog ↔ 테이블 일관성 검증
mysqlbinlog으로 .ibb 파일 이벤트 정상 출력 확인
MariaDB 12.3 InnoDB 바이너리 로그 도입 운영 체크리스트

다른 변화: MariaDB 12.3 LTS의 추가 기능

InnoDB 기반 binlog 외에도 MariaDB 12.3에서 주목할 변화가 있다.

네이티브 XML 타입 (MDEV-37261): XML 컬럼 타입을 지원한다. JSON과 유사하게 스키마 내부에 반정형 XML 문서를 저장하고 XPath 함수로 쿼리할 수 있다.

암호화 키 패스프레이즈: 키 관리 파일에 패스프레이즈 기반 보호를 추가해 at-rest 암호화 운영을 강화했다.

연관 배열 (DECLARE TYPE ... TABLE OF ... INDEX BY): PL/SQL 스타일 연관 배열을 저장 프로시저 내부에서 선언할 수 있어, Oracle에서 MariaDB로 마이그레이션하는 경우 코드 호환성이 높아진다.

Galera Cluster 패키징 개선: mariadb-server-galera 패키지로 Galera 관련 의존성이 분리되어 클러스터 배포가 명확해졌다.


운영 고려사항

마이그레이션 순서

신규 서버에서 바로 binlog_storage_engine=innodb를 쓰는 것이 가장 안전하다. 기존 서버를 12.3으로 업그레이드하는 경우, 기존 .binlog 파일을 보존하고 업그레이드 후 설정을 변경하면 된다. 기존 파일과 새 .ibb 파일은 공존 가능하며, 교체 시점 이전의 이벤트는 여전히 기존 파일에서 읽을 수 있다.

LTS 지원 기간

MariaDB 12.3은 LTS 릴리스로 2029년 6월까지 지원된다. 12.2(non-LTS)를 사용 중인 팀은 12.3으로 이전할 명분이 생겼다.

Open question


References