𝗗𝟭 𝗥𝗲𝗮𝗱 𝗥𝗲𝗽𝗹𝗶𝗰𝗮𝘀 𝗛𝗮𝗱 𝟲 𝗦𝗲𝗰𝗼𝗻𝗱𝘀 𝗼𝗳 𝗟𝗮𝗴

도쿄에 있는 D1 읽기 복제본(read replica)이 북미에서 발생한 쓰기 작업보다 6.1초 뒤처졌습니다.

잘못된 노출(impression)을 제한하는 트래커를 통해 이 사실을 알게 되었습니다. 문서는 최종 일관성(eventual consistency)을 언급하지만, 계획을 세울 수 있는 구체적인 시간은 명시하지 않습니다.

실제 수치를 확인하기 위해 데이터 신선도(staleness) 프로브를 구축했습니다. 이 프로브는 UUID와 epoch를 포함한 행을 작성합니다. 그 후 해당 행이 나타날 때까지 복제본을 폴링(poll)하며, 지연 시간을 기록합니다.

아시아 지역에서 200번의 프로브를 실행한 결과:

프라이머리(primary)가 북미에 있고 사용자가 아시아에 있다면 지연 시간이 매우 높습니다.

스키마 오류도 겪었습니다. 프라이머리에서 마이그레이션이 실행된 후 Worker가 재시작되었습니다. 그런데 첫 번째 요청들이 새로운 테이블이 반영되기 전에 복제본에 도달했습니다. 오류 메시지에는 테이블이 존재하지 않는다고 나왔습니다. 테이블은 분명히 있었지만, 복제본이 뒤처져 있었던 것입니다.

저는 지연과 싸우는 대신, 지연을 우회하는 방식으로 이 문제를 해결했습니다.

설계 방식은 다음과 같습니다:

  1. 작성자(writer)는 행에 written_at epoch를 추가합니다.
  2. 작성자는 응답에 X-D1-Written-At 헤더를 추가합니다.
  3. 읽기 작업(reader)은 해당 헤더를 복제본의 데이터와 비교합니다.
  4. 복제본 데이터가 헤더보다 오래되었다면, 읽기 작업은 KV로 폴백(fallback)합니다.

KV는 동일 지역 내에서 500ms 미만으로 실행됩니다. 하루 최대 1,000만 건의 읽기까지 무료입니다. 이는 중요한 플래그(flag)에 대해 최신 데이터를 가져올 수 있는 저렴한 방법입니다.

복제본이 뒤처져 있는 짧은 시간 동안에만 KV를 사용하게 됩니다. 복제본이 동기화되면 대부분의 읽기 요청은 정상적으로 D1을 통해 처리됩니다.

상세 포스트에서 전체 스크립트와 마이그레이션 패턴을 공유했습니다.

출처: https://dev.to/riversea/d1-read-replicas-returned-stale-data-for-6-seconds-heres-what-i-measured-and-how-i-designed-mme