Notice
Recent Posts
Recent Comments
Link
«   2026/06   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

ssuperjun 님의 블로그

[장애 이력 자동 작성 도구 15] MySQL 시행착오 본문

인턴

[장애 이력 자동 작성 도구 15] MySQL 시행착오

ssuperjun 2026. 3. 12. 15:36

시행착오

마스터 디스크 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]으로 감지하고 원인은 수동으로 확인하면 됨