← 스터디 홈
5편 · 약 9분

ZSTD 압축과 8.4 변화점

왜 binlog 크기를 줄여야 하는가

ROW 포맷 binlog는 정확하지만 무겁다. 트랜잭션마다 변경된 행의 before·after 이미지를 전부 기록하기 때문에, 대량 배치 업데이트나 넓은 JSON 컬럼을 가진 테이블에서는 binlog가 소스 데이터보다 더 빠르게 쌓인다.

문제는 세 군데에서 동시에 발생한다.

  • 소스 디스크: 만료 전에 파일이 쌓이는 속도가 빨라 보존 기간을 줄여야 한다는 압박을 받는다.
  • 레플리케이션 네트워크: 소스 → 레플리카 스트리밍이 바이트 그대로 전송되므로 대역폭을 직접 소비한다.
  • 레플리카 디스크: relay log도 마찬가지로 압박을 받는다.

MySQL 8.0.20에서 도입된 binlog 트랜잭션 압축(binary log transaction compression) 은 이 세 가지 문제를 한 번에 완화한다.

ZSTD로 Transaction_payload_event를 만든다

활성화하면 MySQL은 트랜잭션 페이로드 전체를 zstd 알고리즘으로 압축한 뒤, 단일 이벤트인 Transaction_payload_event로 binlog에 기록한다.

-- ZSTD 압축 활성화
SET PERSIST binlog_transaction_compression = ON;

-- 압축 레벨 조정 (1~22, 기본값 3)
SET PERSIST binlog_transaction_compression_level_zstd = 3;

레벨이 높을수록 압축률이 오르지만 CPU·메모리 소비가 늘어난다. 실제로 레벨 증분과 압축률 향상은 선형 관계가 아니며, 기본값 3이 대부분의 워크로드에서 무난한 균형점이다. 레벨 22까지 올려도 효과가 미미하면서 소스 CPU를 크게 소모한다.

압축에서 제외되는 이벤트

모든 이벤트가 압축되는 것은 아니다. 다음은 항상 비압축 상태로 기록된다.

  • GTID 이벤트 (Gtid_log_event, Anonymous_Gtid_log_event)
  • 체크섬: Transaction_payload_event 전체에 대한 체크섬은 별도 추가된다.

GTID는 레플리카가 binlog를 수신할 때 즉시 파싱해야 하므로 압축을 피한다. 실제로 크기에 미치는 영향은 미미하다.

레플리케이션 스트림에서도 압축을 유지한다

소스가 Transaction_payload_event를 레플리카에 전송할 때 레플리카 I/O 스레드는 압축을 풀지 않는다. 그대로 relay log에 기록하고, SQL 스레드가 실행 직전에 압축을 푼다. 덕분에 네트워크와 relay log 모두 압축 이득을 누린다.

압축 효과 모니터링

-- 압축 통계 조회 (binlog_transaction_compression = ON 상태에서만 집계)
SELECT
  log_type,
  compression_type,
  transaction_counter,
  compressed_bytes_counter,
  uncompressed_bytes_counter,
  ROUND(1 - compressed_bytes_counter / uncompressed_bytes_counter, 3) AS ratio
FROM performance_schema.binary_log_transaction_compression_stats;

ratio가 0.6이면 원본 대비 60% 절감을 의미한다. 테이블을 TRUNCATE하면 통계를 초기화해 특정 구간의 효과만 측정할 수 있다.

압축 흐름 다이어그램

Source (MySQL) 트랜잭션 이벤트들 zstd 압축 level 1~22 (기본 3) Transaction_payload _event (압축됨) binlog 파일에 기록 GTID 이벤트는 비압축 별도 기록 replication stream 압축 유지 Replica (MySQL) I/O thread 압축 해제 안 함 relay log (압축 그대로) SQL thread 실행 전 압축 해제 InnoDB 적용 performance_schema binary_log_transaction _compression_stats ratio / counter / log_type TRUNCATE으로 초기화
ZSTD binlog 압축 — 소스에서 레플리카까지 압축 상태 유지

MySQL 8.4의 주요 변화점

MySQL 8.4는 2024년 4월 출시된 LTS(Long-Term Support) 릴리스다. binlog와 복제 영역에서 예전부터 쌓아온 변화들이 이 버전에서 최종 정리됐다.

1. binlog_format 폐기(deprecated)

항목내용
상태Deprecated (8.4), 미래 버전에서 제거 예정
기본값ROW (이미 8.0 기본값)
의미STATEMENT·MIXED 포맷은 사실상 레거시 경로로 취급

8.4부터는 binlog_format을 명시적으로 설정하면 경고가 발생한다. ROW만 남기겠다는 공식 신호다.

2. MASTER/SLAVE 명령 완전 제거

8.0.23에서 경고가 붙었던 구형 문법이 8.4에서 완전히 사라졌다.

구형 (8.0 이전)신형 (8.4+)
SHOW MASTER STATUSSHOW BINARY LOG STATUS
SHOW SLAVE STATUSSHOW REPLICA STATUS
CHANGE MASTER TOCHANGE REPLICATION SOURCE TO
START SLAVESTART REPLICA
STOP SLAVESTOP REPLICA
RESET SLAVERESET REPLICA

자동화 스크립트나 모니터링 쿼리에 구형 문법이 남아 있으면 8.4 업그레이드 후 오류가 발생한다.

3. binlog_row_value_options = PARTIAL_JSON

JSON 컬럼을 JSON_SET() / JSON_REPLACE() / JSON_REMOVE()로 부분 업데이트하면, 전체 JSON을 before·after 이미지로 다시 기록하는 대신 변경된 경로만 binlog에 기록한다.

-- JSON 부분 업데이트 최적화 활성화
SET PERSIST binlog_row_value_options = PARTIAL_JSON;

JSON 컬럼이 크고 업데이트가 잦은 테이블에서 binlog 크기와 복제 부하를 크게 줄인다. 단, binlog_row_image = FULL이라면 before 이미지에는 전체 JSON이 여전히 기록되므로, MINIMAL과 함께 쓸 때 효과가 극대화된다.

4. 멀티스레드 레플리카 의존성 정보 개선

8.4에서는 멀티스레드 레플리카(Replica Worker Threads)를 사용할 때 소스가 항상 writeset 기반으로 트랜잭션 간 의존성 정보를 binlog에 기록한다. 이전에는 binlog_transaction_dependency_tracking 설정에 따라 동작이 달라졌는데, 8.4에서 해당 변수가 제거되고 writeset이 단일 기준이 됐다.

변화 요약

8.4는 binlog를 "ROW 포맷만 지원하는 압축 가능한 스트림"으로 수렴시키는 방향성을 명확히 했다.

  • ZSTD 압축: 저장·전송 비용 절감, 기본 설정이면 CPU 부담 미미
  • PARTIAL_JSON: JSON 워크로드 특화 최적화
  • 용어 통일: SOURCE/REPLICA로 완전 전환, 자동화 코드 점검 필요
  • binlog_format 폐기: ROW 외 포맷에 의존하는 구성은 지금부터 제거해야 한다

References

  • https://dev.mysql.com/doc/refman/8.4/en/binary-log-transaction-compression.html
  • https://dev.mysql.com/doc/relnotes/mysql/8.4/en/news-8-4-0.html
  • https://dev.mysql.com/doc/refman/8.4/en/performance-schema-binary-log-transaction-compression-stats-table.html
  • https://dev.mysql.com/doc/refman/8.4/en/replication-options-binary-log.html
  • https://dev.mysql.com/blog-archive/mysql-terminology-updates/
  • https://mysql.wisborg.dk/2020/05/07/mysql-compressed-binary-logs/
  • https://readyset.io/blog/mysql-8-4-what-is-new