Zettelkasten

스냅샷에서 복원한 RDS의 ReadLatency 수십 ms는 IOPS 부족이 아니라 S3 lazy loading이다

·수정 1회

요약

  • 스냅샷 복원은 데이터를 다 내려받고 시작하지 않는다. 빈 볼륨과 블록 지도만 만들어 인스턴스를 띄우고, 처음 읽는 블록마다 그때 S3에서 당겨온다. AWS는 이걸 lazy loading이라 부른다.
  • 그래서 복원 직후 ReadLatency가 gp3 정상치(1ms 안팎) 대신 수십 ms로 뜨고, ReadThroughput은 프로비저닝 값의 10%대에 머문다. 프로비저닝 성능은 모든 블록이 내려온 뒤에야 나온다.
  • 이때 ReadIOPS가 프로비저닝의 30% 수준인 것은 여유가 있다는 뜻이 아니라 지연이 길어서 못 올라간 결과다. IOPS를 더 사도 안 빨라진다.

본문

볼륨은 로컬에 있고, 내용물이 아직 S3에 있다

EBS 스냅샷은 계정에서 안 보이는 AWS 내부 S3에 블록 단위로 올라가 있다. RDS 스냅샷 복원·시점 복구·읽기 복제본 생성이 모두 이 구조를 쓴다.

복원 시 AWS가 하는 일은 세 가지다. 빈 볼륨을 만들고, "이 블록은 S3의 이 조각"이라는 지도를 붙이고, 인스턴스를 띄운다. 825GB를 실제로 복사한다면 수십 분이 걸릴 일이 몇 분 만에 끝나는 이유다.

그래서 "볼륨이 S3에 있다"는 표현은 부정확하다. 볼륨은 로컬 SSD에 있고, 원본 데이터가 아직 S3에 있어서 건드릴 때마다 하나씩 끌어온다. RDS 문서 표현: "If you access data that hasn't been loaded yet, the DB instance immediately downloads the requested data from Amazon S3, and then continues loading the rest of the data in the background."

읽기 경로가 두 갈래로 갈린다.

  • 이미 당겨온 블록 → 로컬 SSD 읽기, 1ms 안팎
  • 아직 안 당겨온 블록 → S3 왕복 후 로컬에 쓰고 반환, 수십 ms

관찰 사례 (실측)

gp3 825GB, 12,000 IOPS, 500 MB/s로 프로비저닝된 복원 직후 인스턴스에서:

지표 값 프로비저닝 대비
ReadLatency 36~41ms 정상치의 40배
ReadThroughput 최대 57.9 MB/s 11%
ReadIOPS 약 3,500 30%

세 수치가 따로 노는 게 아니라 하나의 원인에서 나온다. 프로비저닝한 12,000 IOPS와 500 MB/s는 초기화가 끝난 볼륨의 한도이고, S3에서 끌어오는 구간은 그 한도와 무관하게 느리다. EBS 문서도 "Full volume performance is achieved only once all storage blocks have been downloaded and written to the volume"이라고 못 박는다. Provisioned IOPS 볼륨은 초기화 중 기대치의 50% 아래로 떨어져 I/O Performance 상태 검사에 warning이 뜨는 것까지 정상 동작으로 문서화돼 있다.

IOPS 30%는 여유가 아니라 결과다 (산수 확인)

Little's law로 평균 동시 요청 수 = IOPS × 지연이다. 3,500 × 0.036초 ≈ 126. 항상 126개가 S3 응답을 기다리는 중이라는 뜻이다. 동시 요청 수는 MySQL의 I/O 스레드 수와 커넥션 수로 위가 막혀 있으므로, 요청 하나가 36ms를 먹는 한 IOPS는 저기서 더 못 올라간다.

즉 순서가 반대다. IOPS 한도에 부딪혀서 느린 게 아니라, 느려서 IOPS가 못 오른 것이다. 스토리지 설정을 키우는 대응은 여기서 효과가 없다.

완화 (RDS 문서 기준)

RDS 문서가 제시하는 방법은 하나뿐이다. SELECT * 같은 풀 테이블 스캔을 미리 돌려서 서비스 트래픽이 오기 전에 블록을 당겨놓는 것.

진행률은 DescribeDBInstances 응답의 StorageOperationStatus와 StorageOperationPercentProgress로 본다. 초기화 중에는 StorageOperationStatus가 Initializing이고, 끝나면 두 필드가 아예 사라진다.

EBS 볼륨을 직접 만들 때 쓰는 두 가지 — fast snapshot restore(생성 시점에 완전 초기화), volume initialization rate(100~300 MiB/s 지정) — 는 RDS 복원 문서에 안내되지 않는다. RDS가 EBS 볼륨을 직접 다루게 해주지 않기 때문이다.

풀 스캔은 클러스터형 인덱스(= 데이터 페이지)만 훑는다. 보조 인덱스 페이지는 InnoDB에서 별도 페이지에 있으므로, 인덱스까지 데우려면 커버링 인덱스만 읽는 쿼리를 따로 돌려야 한다. (추론 — 문서로 확인한 내용 아님)

틀리기 쉬운 진단

  • "IOPS가 30%밖에 안 쓰이니 스토리지는 여유롭다" → 위 산수대로 낮은 IOPS는 긴 지연의 결과다. 지연을 먼저 본다.
  • "처리량이 11%니 gp3 처리량을 더 사자" → 프로비저닝 값은 초기화 끝난 볼륨에만 적용된다. 초기화 중에는 돈으로 못 올린다.
  • "ReadLatency가 높으니 버퍼풀이 부족하다" → 버퍼풀 미스가 늘면 ReadIOPS가 같이 오른다. 여기선 IOPS는 낮은데 건당 지연만 길다. 복원 시점을 확인하면 갈린다.

이 증상은 복원 직후에만 나오고, 블록이 다 당겨지면 저절로 사라진다. 다만 그 사이 사용자가 느린 응답을 겪으므로, 프로덕션 트래픽을 받을 복원본이면 붙이기 전에 미리 훑는 편이 낫다.

관련 노트

참고