클라우드

읽기 복제본, 나눠 읽으면 오래된 값을 읽는다

저장에 성공했는데 예전 이름이 보이는 이유를 두 사본으로 따라가 봐요. 읽기 복제본과 자동 장애 전환 구성의 차이도 함께 살펴봐요.

이 글의 목차저장 성공과 복사 완료는 다른 순간이에요5
  1. 저장 성공과 복사 완료는 다른 순간이에요
  2. 읽기를 어디로 보낼지 정해야 해요
  3. 복제본이 바빠도 뒤처질 수 있어요
  4. 장애 전환 이야기는 구성을 구별해서 봐요
  5. 제 경우에는 복제본이 없었어요

도서관 본관의 대출 장부를 분관에도 복사해 두면 두 곳에서 책을 찾을 수 있어요. 그런데 본관에서 방금 빌려 간 책이 분관 장부에는 아직 남아 있을 수 있겠죠. 장부를 더 두면 일을 나눌 수 있지만, 복사하는 동안에는 서로 다른 답이 나와요.

데이터베이스의 읽기 복제본도 이런 사본이에요. RDS는 원본의 변경을 복제본에 비동기로 전달해 읽기 부하를 나눠요. 비동기라는 말은 원본의 저장과 사본의 반영이 같은 순간에 끝나지 않는다는 뜻이에요. 이 글에서 따라갈 질문은 하나예요. 저장에 성공했는데 왜 화면에는 예전 값이 보일까요?

조회 대상에 따른 저장 직후 값 저장 직후 원본을 읽으면 새 값이 보이지만 복제 적용 전의 복제본은 이전 값을 돌려준다. 개념 도해 조회 대상에 따른 저장 직후 값 저장 직후 요청 경로 앱 요청 ① 저장 요청 ② 원본 반영 ③ 즉시 조회 ④ 복제본 읽기 반영 전 ⑤ 이전 값 복제 경로 비동기 전달 복제 적용 조회 대상별 값의 최신성 즉시 조회 복제 적용 완료선 원본 새 값 복제본 이전 값 새 값 저장 이후 시간 저장 직후 원본을 읽으면 새 값이 보이지만 복제 적용 전의 복제본은 이전 값을 돌려준다. SOSHIN · DEV NOTES
쓰고 나서 곧바로 읽으면 방금 쓴 것이 아직 도착하지 않았을 수 있어요.

저장 성공과 복사 완료는 다른 순간이에요

프로필 이름을 ‘민수’에서 ‘지수’로 바꾼다고 해 볼게요. 쓰기를 맡은 원본이 새 이름을 저장한 뒤 앱에 성공을 알려 줘요. 앱이 곧바로 프로필을 다시 읽는데, 이번 요청이 아직 변경을 받지 못한 복제본으로 가면 ‘민수’가 돌아올 수 있어요.

이때 저장이 취소된 것은 아니에요. 새 이름이 있는 원본과 예전 이름이 남은 사본을 차례로 본 거예요. 각각의 요청에 오류가 없어도 사용자에게는 저장이 풀린 것처럼 보일 수 있죠. 아래에서는 복제가 반영되는 시점을 직접 눌러 보며 두 값을 비교할 수 있어요.

저장한 이름이 두 곳에 보이기까지

이름을 저장한 뒤, 복제본에 반영되는 순간을 나눠 보세요.

원본민수저장하는 곳
복제본민수나눠 읽는 곳

처음에는 두 곳 모두 ‘민수’예요. 원본에 ‘지수’를 저장해도 복제본은 아직 ‘민수’일 수 있어요. 변경이 복제본에 적용되면 두 곳 모두 ‘지수’를 보여 줘요.

실제 서버 연결 없이 복제 순서만 보여 줘요. 기다리는 길이는 실제 지연 시간을 뜻하지 않아요.

변경 한 묶음을 트랜잭션이라고 불러요. 실제 데이터베이스에서는 그 묶음을 전달하고 적용하는 데 시간이 걸려요. 그 뒤처짐이 복제 지연(replica lag)이에요. RDS의 모니터링 문서는 이 지연을 볼 수 있는 지표를 설명해요. 다만 지표 계산 방식은 데이터베이스 엔진마다 달라서 숫자 하나를 모든 구성에 똑같이 해석하면 안 돼요.

읽기를 어디로 보낼지 정해야 해요

읽기 요청을 모두 복제본으로 보내면 원본의 부담은 줄어요. 하지만 결제 내역이나 방금 수정한 프로필처럼 새 값이 바로 보여야 하는 화면도 있죠. 이런 경로는 저장 완료를 기다린 뒤 원본에서 읽게 할 수 있어요. 반면 잠깐 늦어도 되는 통계 화면은 복제본을 쓰기 더 편해요.

‘상세 화면은 원본, 목록은 복제본’처럼 화면 이름으로만 나누면 빈틈이 생겨요. 사용자가 방금 추가한 항목이 목록에 나타나길 기대할 수도 있잖아요. 화면 종류보다 직전 행동의 결과를 바로 확인해야 하는지가 더 좋은 기준이에요.

원본을 읽는다고 모든 최신성이 자동으로 해결되는 것도 아니에요. 저장이 끝나기 전에 조회를 시작하거나, 같은 트랜잭션 안에서 이전 시점의 스냅샷을 읽거나, 앱의 캐시가 옛 응답을 돌려주면 결과는 여전히 어긋날 수 있어요. 읽는 위치와 요청 순서를 함께 봐야 하는 이유예요.

복제본이 바빠도 뒤처질 수 있어요

복제본은 조회만 받는 컴퓨터가 아니에요. 원본에서 온 변경을 자기 데이터에 적용하는 일도 해야 해요. 큰 갱신이 이어지거나 무거운 통계 조회가 자원을 오래 쓰면 그 일이 밀릴 수 있어요. RDS Multi-AZ DB 클러스터 설명은 이런 복제 지연의 원인을 다뤄요.

읽기 부담을 덜려고 옮긴 조회가 복제를 늦출 수 있다는 점이 헷갈리기 쉬워요. 예를 들어 보고서 하나가 큰 범위를 훑는 동안 다른 사용자의 새 글이 사본에 늦게 나타날 수 있어요. 조회 속도만 보면 보고서는 잘 끝났는데, 다른 화면의 데이터는 오래된 상태인 거예요.

장애 전환 이야기는 구성을 구별해서 봐요

여기서 이름이 비슷한 구성을 나눠 둘 필요가 있어요. 별도로 만드는 일반 RDS 읽기 복제본과, 여러 가용 영역에 쓰기 인스턴스 하나와 읽기 인스턴스 둘을 두는 Multi-AZ DB 클러스터는 같지 않아요. 가용 영역은 장애를 나눠 견디도록 분리한 데이터센터 묶음이에요. 클러스터의 읽기 인스턴스는 원본에 문제가 생겼을 때 쓰기 역할을 넘겨받는 후보이기도 해요.

Multi-AZ DB 클러스터의 복제 지연과 전환 RDS Multi-AZ DB 클러스터는 승격 전에 미적용 변경을 처리한다. 대기 범위는 엔진에 따라 다르다. 개념 도해 Multi-AZ DB 클러스터의 복제 지연과 전환 장애 조치 경로 ① 장애 감지 ② 미적용분 따라잡기 ③ 쓰기 승격 ④ 연결 전환 ⑤ 서비스 재개 미적용 변경 처리 시차와 전환 시간의 관계 전환 시간 장애 순간의 시차 승격·연결 기준 시간 전체 전환 시간 따라잡기 시간 시차 작음 시차 큼 RDS Multi-AZ DB 클러스터는 승격 전에 미적용 변경을 처리한다. 대기 범위는 엔진에 따라 다르다. SOSHIN · DEV NOTES
RDS Multi-AZ DB 클러스터에서는 미적용 변경을 처리한 뒤 승격해요. 기다리는 범위는 엔진에 따라 달라요.

위 문서에 나오는 ‘복제 지연을 해소한 뒤 승격한다’는 설명은 이 Multi-AZ DB 클러스터에 관한 것이에요. 일반 읽기 복제본을 하나 추가했다고 동일한 자동 장애 전환이 생기지는 않아요. 클러스터에서도 MySQL과 PostgreSQL이 전환 전에 기다리는 복제본 범위가 달라요.

AWS가 이 클러스터의 복제 지연 경보를 따로 안내하는 이유도 여기에 있어요. 뒤처짐은 화면의 오래된 값뿐 아니라, 쓰기 역할을 넘겨받기까지의 시간에도 영향을 줄 수 있어요. 쓰기에 제동을 걸어 복제가 따라오게 하는 흐름 제어는 그 대가로 쓰기 처리 속도를 낮춰요.

선택얻는 것감수할 점
저장 후 원본에서 읽기자신의 변경을 확인하기 쉬움원본에 읽기 부하가 남음
오래됨을 허용하는 조회 분리원본의 읽기 부담 완화사본의 반영이 늦을 수 있음
지원되는 구성에서 흐름 제어복제가 계속 뒤처지는 상황 완화쓰기도 느려질 수 있음

제 경우에는 복제본이 없었어요

제가 만드는 앱은 아직 읽기를 나눌 필요가 없어요. 그런데 저장 뒤에 예전 값이 보이는 증상은 겪었어요. 살펴보니 저장 응답이 오기 전에 목록 조회가 먼저 출발하고 있었어요.

복제 지연은 아니었지만, 화면만 보면 구별하기 어려웠어요. 그 뒤로는 저장이 안 됐다고 단정하기 전에 언제 저장을 마쳤고 어느 결과를 읽었는지부터 따라가요. 복제본을 배운 덕분에 요청 두 개의 순서도 더 꼼꼼히 보게 됐어요.

소신을 상징하는 까마귀 목판화 일러스트
작성자소신 · Soshin

웹과 서버를 만들고, 개발하며 배운 것들을 글로 남깁니다.

좌우로 움직여 보세요