요약
- 버퍼풀을 줄이면 ReadIOPS는 늘어나는데 ReadLatency가 오히려 내려가는 현상이 관찰될 수 있다.
- ReadLatency는 쿼리 지연이 아니라 디스크 I/O 1건당 평균 시간이라서, 싸고 빠른 read가 분모에 대량 추가되면 평균이 희석된다 (selection bias).
- 시스템이 실제로 빨라진 게 아니므로, 성능 판단은 쿼리 레벨 지표로 해야 한다.
본문
현상: RDS 버퍼풀(innodb_buffer_pool_size)을 줄였더니 ReadIOPS는 증가했는데 CloudWatch ReadLatency는 감소했다.
핵심: ReadLatency의 분모가 바뀐 것이다
CloudWatch ReadLatency는 디스크 read I/O 1건당 평균 소요 시간이다. 평균 지표는 분모(I/O 건수)의 구성이 바뀌면 개별 I/O가 빨라지지 않아도 값이 움직인다.
- 버퍼풀이 클 때: 디스크까지 내려가는 read는 버퍼풀이 못 잡은 어려운 read(랜덤 single-page, cold 데이터)만 남는다. 분모가 작고 비싼 read 위주 → 평균이 높게 나온다.
- 버퍼풀을 줄이면: 이전엔 버퍼풀이 흡수하던 hot page read가 대량으로 디스크로 내려간다. 그런데 이 read들은 성격이 좋다:
- 자주 읽히는 페이지라 스토리지 계층 캐시(EBS 캐시 등)에 거의 항상 올라가 있어 빠르다
- 순차 스캔성이면 InnoDB read-ahead가 묶어서 가져와 건당 비용이 낮다
- 결과: 비싼 read의 절대 개수는 그대로인데, 빠른 read가 분모에 잔뜩 추가되면서 평균이 내려간다.
즉 read latency 하락은 개선이 아니라 평균의 희석이다. (ReadLatency가 per-I/O 평균이라는 것은 문서화된 사실이고, 희석이 주원인이라는 해석은 정황 기반 추론 — 아래 검증 지표로 확인 필요)
부차적으로 가능한 요인 (환경에 따라)
innodb_flush_method=O_DIRECT가 아니면 버퍼풀에서 해제된 메모리가 OS 페이지 캐시로 가서 file read가 메모리에서 처리됨 (RDS 기본은 O_DIRECT라 보통 해당 없음)- 매우 큰 버퍼풀에서의 LRU/free list 스캔, 뮤텍스 경합 감소 — 보통은 미미함
- 프로비저닝 IOPS 한도 내라면 IOPS가 늘어도 queue가 안 쌓여 per-op latency가 안정적일 수 있음
진짜 성능을 판단하는 지표
평균 디스크 latency 대신 다음을 본다:
- 쿼리 단 latency: 애플리케이션 p99, slow query 추이 — 버퍼풀을 줄였으면 보통 나빠지거나 그대로
- ReadIOPS × ReadLatency = 총 read I/O 시간: 이게 늘었다면 디스크 부담은 실제로 증가한 것
- Performance Insights에서
io/file/innodb/innodb_data_filewait 비중 변화
일반화: 평균 기반 지표는 분모 구성이 바뀌는 변경(캐시 크기 조정, 트래픽 mix 변화) 전후 비교에 취약하다. 변경의 효과는 평균이 아니라 분포(p99)나 총량으로 판단한다.
관련 노트
- RDS 다운사이징 전에 buffer pool을 점진적으로 낮춰 핫셋이 작은 pool에 맞는지 실측한다
- RDS 메모리 다운사이징 가능 여부는 데이터가 커도 ReadIOPS가 낮은지로 판별한다
- ReadIOPS는 논리 읽기 요청이 아니라 디스크 물리 읽기를 센다
- ReadIOPS는 절대값이 아니라 프로비저닝 IOPS 대비 사용률과 read-write 비율로 판단한다
참고
- https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-metrics.html — CloudWatch ReadLatency 정의
- https://dev.mysql.com/doc/refman/8.0/en/innodb-performance-read_ahead.html — InnoDB read-ahead