ssuperjun 님의 블로그
[장애 이력 자동 작성 도구 15] MySQL 시행착오 본문
시행착오
마스터 디스크 full 장애 연출 당시 디스크 full 유발에 실패함
1트
# 1. 50G짜리 더미 파일 생성 (약 몇 초 소요)
fallocate -l 50G /home1/irteam/dummy_fill.img
# 2. 디스크 여유 공간 확인 (얼마 안 남았는지 확인)
df -h /home1/irteam/mysql/data
# 3. MySQL에서 쓰기 작업 유발 (binlog 쓰기 트리거)
/home1/irteam/mysql/base/bin/mysql \
-S /home1/irteam/mysql/run/mysql.sock \
-u root -p'비밀번호' \
-e "CREATE DATABASE IF NOT EXISTS test_disk;
USE test_disk;
CREATE TABLE IF NOT EXISTS t (id INT AUTO_INCREMENT PRIMARY KEY, v VARCHAR(255));
INSERT INTO t (v) SELECT REPEAT('x', 255) FROM information_schema.tables LIMIT 100;"
# 4. 로그 확인
tail -20 /home1/irteam/mysql/log/mysql.err
=> 6G가 안 차서 실패
2트(1G만 남기고 디스크 full 유발)
# 5G 추가 생성 (1G만 남기기)
fallocate -l 5G /home1/irteam/dummy_fill2.img
df -h /home1/irteam/mysql/data
# MySQL 쓰기 유발 (대량 INSERT)
/home1/irteam/mysql/base/bin/mysql \
-S /home1/irteam/mysql/run/mysql.sock \
-u root -p'비밀번호' \
-e "USE test_disk;
INSERT INTO t (v) SELECT REPEAT('x', 255) FROM information_schema.tables a, information_schema.tables b LIMIT 10000;"
tail -20 /home1/irteam/mysql/log/mysql.err
=> 실패
3트(100M만 남기기)도 실패
4트: dd로 디스크를 채우면서, 동시에 MySQL 지속 쓰기 작업 실행
터미널 1 (디스크 채우기):
dd if=/dev/zero of=/home1/irteam/dummy_real.img bs=1M count=55000
터미널 2 (MySQL 지속 쓰기, 터미널 1 실행 직후):
while true; do
/home1/irteam/mysql/base/bin/mysql \
-S /home1/irteam/mysql/run/mysql.sock \
-u root -p'비밀번호' \
-e "USE test_disk;
INSERT INTO t (v) SELECT REPEAT('x', 255)
FROM information_schema.tables a, information_schema.tables b LIMIT 1000;" \
2>&1
sleep 0.5
done
터미널2 에러 시 로그 확인
tail -10 /home1/irteam/mysql/log/mysql.err
=> 실패: 디스크가 98%까지 찬 상황에서 dd 명령이 멈춰버림
7트
# 1. 남은 공간 한번에 채우기 (oflag=direct로 캐시 우회, 빠르게 채움)
df -h / && \
fallocate -l 53G /home1/irteam/dummy1.img && \
df -h /
# 2. 디스크 채워진 것 확인 후 MySQL 쓰기 유발
/home1/irteam/mysql/base/bin/mysql \
-S /home1/irteam/mysql/run/mysql.sock \
-u root -p'비밀번호' \
-e "USE test_disk;
INSERT INTO t (v) SELECT REPEAT('x', 255)
FROM information_schema.tables a,
information_schema.tables b,
information_schema.tables c LIMIT 500000;"
# 3. 로그 확인
tail -10 /home1/irteam/mysql/log/mysql.err
디스크 full은 발생하지 않았지만 디스크 full 직전 증상인 redo log 병목 증상 발생
=> 캐시 우회 쓰기가 주효함을 확인
redo log 병목이 발생 배경
redo log를 새로 쓰려는데 기존 redo log를 checkpoint로 비워야 하고, checkpoint를 하려면 디스크에 dirty page를 flush해야 하는데 디스크가 꽉 차서 flush를 못하는 상황 발생
8트
# 1. my.cnf에 O_DIRECT 추가 (캐시 우회 쓰기)
echo "innodb_flush_method=O_DIRECT" >> /home1/irteam/mysql/my.cnf
# 2. MySQL 재시작
kill $(cat /home1/irteam/mysql/run/mysql.pid)
sleep 3
nohup /home1/irteam/mysql/base/bin/mysqld_safe \
--defaults-file=/home1/irteam/mysql/my.cnf > /dev/null 2>&1 &
sleep 5
# 3. 설정 확인
/home1/irteam/mysql/base/bin/mysql \
-S /home1/irteam/mysql/run/mysql.sock \
-u root -p'비밀번호' \
-e "SHOW VARIABLES LIKE 'innodb_flush_method';"
# 4. 페이지 캐시 다시 비우기
sync && echo 3 | sudo tee /proc/sys/vm/drop_caches
# 5. 대량 INSERT + 실시간 로그 모니터링 (별도 터미널에서)
tail -f /home1/irteam/mysql/log/mysql.err
# 별도 터미널에서 INSERT 실행
/home1/irteam/mysql/base/bin/mysql \
-S /home1/irteam/mysql/run/mysql.sock \
-u root -p'비밀번호' \
-e "USE test_disk;
INSERT INTO t (v) SELECT REPEAT('x', 255)
FROM information_schema.tables a,
information_schema.tables b,
information_schema.tables c LIMIT 500000;"
=> 에러 메시지가 잘림 -> 디스크가 꽉 차서 로그 파일 자체도 못 쓰는 상황. 디스크 full 장애 연출 성공!
최종 확인
# 1. mysqld 프로세스 살아있는지 확인
ps aux | grep mysqld | grep -v grep
# 2. 로그 전체 마지막 부분
tail -10 /home1/irteam/mysql/log/mysql.err
# 3. dmesg에서 디스크 관련 에러 확인
sudo dmesg | tail -20
결론
| 항목 | 결과 |
| 디스크 Full 직전 증상 | [MY-014084] redo log 병목 → 수집 가능 |
| 디스크 Full 직접 에러 | [MY-000??] 로그가 잘려서 메시지 코드 확인 불가 |
| 로그 기록 자체 | 디스크 Full이면 로그도 못 씀 |
디스크 full이면 로그가 잘리는 상황이므로 로그 내용을 수집할 수 없음
간단한 오류 수정
정상화가 완료됐음에도 정상화 시각 이후 이벤트가 제외되지 않고 타임라인에 그대로 출력됨
-> 정상화 시각까지의 내용만 타임라인에 출력되도록 수정
복제 구성 장애 시작 감지 로직 변경
기존: [CONN_LOST]만 장애 시작으로 판단
변경: [CONN_LOST] 또는 [RECONNECTING] 중 먼저 나타나는 것을 장애 시작으로 판단
근거: 네트워크 차단(REJECT/DROP) 시 [CONN_LOST] 없이 [RECONNECTING]부터 찍히는 패턴이 확인됨
처음 계획과 달라진 부분
원래는 [INNODB_ASSERT] 태그도 감지하려 했음 -> [ABORTING]으로 포괄하기로 수정
[INNODB_ASSERT]: InnoDB 오류 (Assertion/Corruption)란?
InnoDB Assertion/Corruption 설명
Assertion failure ([MY-013183])
- InnoDB 내부 코드에 박혀 있는 assert(조건) 검사가 실패한 경우 오류 발생
- "이 시점에서 이 값은 반드시 X여야 한다"는 가정이 깨졌을 때 MySQL이 스스로 비정상 종료
- 주로 버그, 메모리 오염, 또는 예상치 못한 내부 상태에서 발생
Corruption ([MY-012262])
- InnoDB 테이블스페이스(.ibd 파일) 또는 redo log의 데이터가 손상된 경우 오류 발생
- 디스크 불량, 강제 종료(전원 차단 등), 또는 OS 레벨 파일시스템 오류가 원인인 경우가 많음
- 장애 연출이 까다롭고, 실제 운영 환경에서 흔한 장애 아니라 판단해 이번 프로젝트 범위에서는 제외
- 대신 [ABORTING] 태그로 포괄함
- Assertion failure든 Segfault든 MySQL이 비정상 종료할 때는 항상 Aborting 메시지가 함께 찍히기 때문에, Assertion/Corruption은 별도 태그 없이 [ABORTING]으로 감지하고 원인은 수동으로 확인하면 됨
'인턴' 카테고리의 다른 글
| [장애 이력 자동 작성 도구 17] 최종 발표 자료 (0) | 2026.03.12 |
|---|---|
| [장애 이력 자동 작성 도구 16] Redis, MySQL 추가 고민 (0) | 2026.03.12 |
| [장애 이력 자동 작성 도구 14] MySQL 장애 연출 (0) | 2026.03.12 |
| [장애 이력 자동 작성 도구 13] MySQL 최종 정리 (0) | 2026.03.12 |
| [장애 이력 자동 작성 도구12] Redis 스크립트 추가 고도화 (0) | 2026.03.10 |