새벽에 갑자기 "디스크 100%" 알람이 울리고 MySQL이 쓰기를 거부합니다. 데이터는 그대로인데 /var/lib/mysql 아래 mysql-bin.000xxx 파일이 수백 GB를 차지하고 있다면, 범인은 십중팔구 바이너리 로그(binlog) 입니다. binlog는 데이터 변경(INSERT/UPDATE/DELETE)을 순서대로 기록하는 파일로, 복제(replication)와 시점 복구(PITR)에 필수지만, 정리 정책이 없으면 무한히 쌓입니다.
먼저 현황을 본다
SQL
SHOW BINARY LOGS; -- 로그 파일 목록과 각 크기
SHOW VARIABLES LIKE 'log_bin'; -- binlog 활성 여부(ON/OFF)
SHOW VARIABLES LIKE 'binlog_expire_logs_seconds';
SHOW BINARY LOGS의 합계가 디스크를 압박하는 크기라면 정리 대상입니다. 다만 무작정 rm으로 파일을 지우면 안 됩니다. MySQL이 인식하는 인덱스(mysql-bin.index)와 어긋나 복제가 깨집니다.
보존 기간을 정하는 기준
| 환경 | 권장 보존 | 이유 |
|---|---|---|
| 복제(replica) 있음 | 복제 지연 최대치 * 2배 이상 | replica가 따라잡기 전에 지우면 복제 단절 |
| PITR 백업 운영 | 마지막 풀백업 주기 + 여유 | 백업 시점부터 현재까지 재생 가능해야 함 |
| 단독 서버, 복구 불필요 | 1~3일 | 디스크 절약 우선 |
핵심은 "이 로그를 아직 읽어야 할 소비자(replica·백업)가 있는가"입니다. 소비자가 다 읽은 로그만 지우는 게 안전합니다.
안전하게 정리하는 순서
- 수동 즉시 정리 — 특정 파일 이전을 한 번에 비웁니다. replica가 있다면 모든 replica가 읽은 파일명까지만 지정합니다.
SQL
PURGE BINARY LOGS TO 'mysql-bin.000120';
-- 또는 날짜 기준
PURGE BINARY LOGS BEFORE '2027-12-10 00:00:00';
- 자동 만료 설정 — MySQL 8.0은 초 단위 변수를 씁니다. 아래는 7일 보존 예시입니다.
SQL
SET PERSIST binlog_expire_logs_seconds = 604800; -- 7일
SET PERSIST는 재시작 후에도 유지됩니다. 설정 파일에도 함께 박아두면 확실합니다.
로컬 터미널
# /etc/mysql/my.cnf
[mysqld]
binlog_expire_logs_seconds = 604800
- 복제 상태 먼저 확인 — replica가 어디까지 읽었는지 보고 그 이전만 지웁니다.
SQL
SHOW REPLICA STATUS\G -- Relay_Source_Log_File 확인
요점 정리
- 디스크 폭증의 흔한 범인은 binlog.
SHOW BINARY LOGS로 먼저 크기를 확인한다. rm으로 직접 지우지 말고PURGE BINARY LOGS또는 만료 변수를 쓴다.- 보존 기간은 복제 지연·백업 주기를 기준으로 정한다. replica가 안 읽은 로그는 절대 지우지 않는다.
- MySQL 8.0은
binlog_expire_logs_seconds(초 단위)를 쓰며,SET PERSIST로 영구 적용한다.
binlog 정리와 복제·시점 복구를 직접 설정하며 확인하는 실습은 데이터베이스 트랙에서 회원가입 없이 무료로 할 수 있습니다.