IL-0451 Daangn · 2026-10-06 (게시일)databaseaws
Aurora MySQL 에서 인덱스를 INVISIBLE 로 바꿀 때마다 Reader 3대의 버퍼풀이 무효화돼 CPU 와 ReadIOPS 가 튀었다
당근의 한 서비스는 Writer 1대와 Reader 3대로 이루어진 Aurora MySQL 3.10.x 클러스터를 쓴다. 이 클러스터의 한 테이블에는 인덱스가 20개 넘게 달려 있었다. DB팀은 performance_schema.table_io_waits_summary_by_index_usage 의 스냅샷을 일주일 간격으로 두 번 떠서, 4개 노드 모두에서 2주 동안 읽기가 0 이었던 인덱스 6개를 골랐다. 팀은 바로 DROP 하지 않고 먼저 INVISIBLE 로 바꿔 며칠 지켜볼 생각이었다. INVISIBLE 은 메타데이터만 바꾸는 작업이라 DB 에 부하가 없다고 여겼다.
인덱스를 INVISIBLE 로 바꿀 때마다 Reader 3대에서 CPU 와 ReadIOPS 가 함께 튀었고 Writer 는 조용했다. INNODB_BUFFER_PAGE 를 보니 Reader 버퍼풀의 페이지 수는 그대로인데 IS_STALE 이 YES 인 페이지가 테이블 전체에서 94~98% 로 늘었다. Aurora 의 Reader 는 Writer 와 같은 스토리지를 쓰지만 버퍼풀은 따로 가지며, Writer 의 redo 로그로 캐시 페이지를 갱신한다. 인덱스 DDL 은 Reader 에서 그 테이블의 캐시 페이지를 통째로 무효화했고, 그 뒤의 읽기는 스토리지에서 다시 가져와야 했다. DDL 종류별로 재현해 보니 INSTANT DDL 과 rebuild 없는 INPLACE DDL 은 영향이 없었다. tablespace 가 바뀌는 DDL 은 예상대로 캐시가 사라졌다. tablespace 가 바뀌지 않는 CREATE INDEX, DROP INDEX, RENAME INDEX 와 INVISIBLE 은 예상과 달리 테이블 전체를 무효화했다.
DB팀은 재현 결과를 붙여 AWS 기술 지원에 문의했다. Aurora MySQL 서비스팀은 인덱스 DDL 이 Reader 의 버퍼풀을 무효화한 것이 맞다고 확인했다. 원인은 3.08.0 에서 기능 개선의 하나로 들어온 동작이 metadata-only DDL 에까지 의도와 달리 너무 넓게 적용된 엔진 결함이었다. 수정은 Aurora MySQL 3.14 에 들어가며, 그 이전 버전으로 백포트할 계획은 없다. 결함이 있는 버전은 3.08.0 부터 3.14 직전까지다. DB팀은 LTS 버전인 3.10.x 를 쓰고 있어 3.14 로 바로 올리기 어렵다. 그래서 수정이 들어간 다음 LTS 버전을 기다리고 있다.
- 심각도
- –
- 영향 범위
- All three readers of one service's Aurora MySQL cluster: each index DDL invalidated the table's cached pages, raising ReadIOPS from a few hundred to 3.1K and CPU from 30% to 50-60%
- 영향 사용자
- –
- 지역
- –
- 감지까지
- –
- 복구까지
- –
증상
미사용 인덱스를 INVISIBLE 로 바꾸는 ALTER 문을 실행할 때마다 Aurora MySQL 클러스터의 Reader 3대에서 CPU 와 ReadIOPS 가 동시에 튀었다. 같은 시각 Writer 의 지표는 평소와 같았다.
CloudWatch 에서 보니 ALTER INDEX INVISIBLE 을 실행한 세 번과 Reader 스파이크 세 번이 정확히 하나씩 맞물렸다. ReadIOPS 는 평소 수백에서 3.1K 로, CPU 는 30% 에서 50~60% 로 올라갔고 BufferCacheHitRatio 는 순간적으로 떨어졌다. Writer 는 ReadIOPS, CPU, BufferCacheHitRatio 모두 변화가 없었다.
DB팀은 버퍼풀의 데이터 페이지가 한순간에 빠져나가 스토리지에서 다시 읽어 오고 있다고 의심했다. 그래서 DDL 직전과 직후에 Reader 에서 information_schema.INNODB_BUFFER_PAGE 를 조회해 인덱스별 캐시 페이지 수를 비교했다. 그러나 그 테이블의 페이지 수는 511,866 에서 511,847 로 거의 줄지 않았다.
같은 뷰의 IS_STALE 컬럼을 보자 차이가 드러났다. 인덱스 하나를 INVISIBLE 로 바꾼 직후 Reader 에서 PRIMARY 인덱스의 252,656 페이지 가운데 245,625 페이지, 곧 97.2% 가 stale 이 됐다. INVISIBLE 로 바꾸지 않은 다른 인덱스도 94~98% 가 stale 이 됐다. 페이지는 버퍼풀에 남아 있었지만 더 이상 유효하지 않은 상태였다. 무효화는 인덱스 하나가 아니라 테이블 전체에 걸쳤다. 같은 시각 Writer 의 stale 페이지는 0개였다.
테스트 테이블에서 DDL 일곱 가지를 실행해 보니 ADD COLUMN 같은 INSTANT DDL 과 rebuild 없는 INPLACE DDL 은 Reader 버퍼풀에 영향이 없었다. COPY DDL 과 rebuild 가 따르는 INPLACE DDL 은 tablespace 가 바뀌므로 캐시가 사라졌는데, 이는 예상한 대로였다. tablespace 가 그대로인 CREATE INDEX, DROP INDEX, RENAME INDEX 는 INVISIBLE 과 똑같이 그 테이블의 캐시 페이지를 거의 전부 stale 로 만들었다.
증상 캐시 적중률 하락
원인
원인 소프트웨어 결함
- 촉발
- DB팀이 미사용 인덱스를 정리하려고 Aurora MySQL 3.10.x 클러스터의 Writer 에서 인덱스를 하나씩 시간 간격을 두고 ALTER INDEX ... INVISIBLE 로 바꿨다.
감지
CloudWatch 에서 ALTER INDEX INVISIBLE 을 실행한 세 번의 시각에 Reader 의 CPU 와 ReadIOPS 스파이크가 하나씩 정확히 겹치는 것을 보고 알아챘다.
조치
–
후속 조치
- Aurora MySQL 3.14 로 바로 올리기는 어려우므로, 이 수정이 들어간 다음 LTS 버전이 나오면 그 버전으로 업그레이드한다.
- 그 전까지 인덱스 DDL 은 트래픽이 적은 시간대에 실행한다.
- 인덱스 여러 개를 바꿀 때는 한 ALTER 문으로 묶어 Reader 버퍼풀 무효화를 N 번에서 1 번으로 줄인다.
교훈
Aurora MySQL 에서 인덱스를 INVISIBLE 로 바꾸는 작업은 메타데이터만 바꾸므로 부하가 없다는 생각은 Writer 에서만 맞았다. 3.08.0 부터 3.14 이전 버전에서는 인덱스 DDL 을 Reader 버퍼풀을 비우는 작업으로 보고 운영한다. 행이 많고 트래픽이 높은 테이블일수록 버퍼풀이 다시 채워지는 동안 ReadIOPS 와 CPU 가 크게 오를 수 있다.
미사용 인덱스를 고를 때는 performance_schema.table_io_waits_summary_by_index_usage 를 모든 노드에서 확인한다. 노드마다 쿼리 패턴이 달라서, Writer 에서 count_read 가 0 인 인덱스를 어떤 Reader 는 자주 쓸 수 있다. INNODB_BUFFER_PAGE 조회는 버퍼풀 전체를 훑으므로 버퍼풀이 큰 인스턴스에서는 몇 초씩 걸리고 부하도 준다. 운영 중에는 꼭 필요할 때만 조회한다.
출처
참고 문서
관련 사례
IL-0385큰 MySQL 테이블의 스키마 마이그레이션 마지막 단계에서 읽기 복제본 다수가 semaphore deadlock 에 걸려 GitHub 핵심 서비스가 2시간 50분 저하됐다GitHub · 2021같은 원인 · 공통 데이터베이스, 스키마 마이그레이션
같은 원인 · 공통 데이터베이스
IL-0281PostHog US 리전 Logs 제품의 ClickHouse 클러스터가 S3 에 둔 로그 데이터를 거의 다 지워 3일보다 오래된 로그가 사라졌다PostHog · 2026같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0150DynamoDB DNS 자동화의 경쟁 조건이 us-east-1 리전 엔드포인트의 DNS 레코드를 비워 DynamoDB 와 EC2 인스턴스 시작이 실패했고, 그 여파로 EKS, ECS, Fargate 의 컨테이너 시작과 클러스터 스케일링이 14시간 넘게 막혔다Amazon Web Services · 2025같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0527OpenStreetMap.org 의 복제 diff 생성이 invalid memory alloc request size 오류로 16시간 멈춤OpenStreetMap Foundation · 2025같은 원인 · 공통 데이터베이스
IL-0329Postgres 17 업그레이드 뒤 다시 켠 PGAudit 가 마이그레이션 중 락을 쥔 채 멈춰, 서비스 전반이 느려지고 데이터베이스가 2분 동안 내려갔다incident.io · 2025같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0024무거운 API 요청이 MongoDB 에 과부하를 걸고 취소되지 않은 요청이 쌓여 Hugging Face Hub 가 사흘 동안 세 번 멈췄다Hugging Face · 2024같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0196Redis Operator 로 레플리카를 늘리면서 메모리 한도를 낮추자 데이터를 가진 유일한 Redis 파드가 재시작됐고, Sentinel 이 빈 레플리카를 마스터로 올려 데이터가 모두 지워졌다.Palark · 2020같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0388Redis 고가용 클러스터의 primary 노드가 내려간 뒤 Discord API 가 느려지고 길드 일부가 오프라인으로 보이며 접속이 실패했다Discord · 2017같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
내 클러스터에도 있는지 확인하기
AI 도구와 스크립트용
- 이 사례의 JSON: https://incidentlib-api.benchlet.com/cases/IL-0451
- 가장 비슷한 사례들: https://incidentlib-api.benchlet.com/cases/IL-0451/similar
- MCP 서버(Streamable HTTP, 키 없음):
https://incidentlib-mcp.benchlet.com/mcp
API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.