Incident Library

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 에서 인덱스를 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 조회는 버퍼풀 전체를 훑으므로 버퍼풀이 큰 인스턴스에서는 몇 초씩 걸리고 부하도 준다. 운영 중에는 꼭 필요할 때만 조회한다.

출처

참고 문서

관련 사례

내 클러스터에도 있는지 확인하기

kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이 사례와 같은 상태를 점검합니다. 이 사례의 구성 요소: 데이터베이스, 스키마 마이그레이션. 점검 항목의 근거는 이 사례 같은 공개 보고서입니다.

AI 도구와 스크립트용

API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.