4 minute read

리더 기반 복제의 특징은 웹 애플리케이션과 유사하다.

  • 쓰기 작업은 드물다.
  • 읽기 작업이 대부분이다.

이러한 패턴이 리더 기반 복제에 잘 맞는 이유는 리더의 부하가 경감되고 팔로워 복제본에서 읽기 요청을 처리할 수 있기 때문이다.

읽기 확장 아키텍처의 단점

  • 팔로워를 더 추가하는 접근 방식은 비동기 복제에서만 잘 작동한다.
  • 모든 팔로워에 동기 복제를 시도할 경우 단일 노드 장애 또는 네트워크 중단으로 인해 전체 시스템이 쓰기 기능을 사용할 수 없게 된다.
  • 노드가 많을수록 한 노드가 다운될 가능성이 높아지므로 완전 동기식 구성은 매우 불안정할 수 있다.
  • 애플리케이션이 비동기 팔로워에서 읽는 경우, 팔로워가 뒤처진 경우 오래된 정보를 볼 수 있다.

최종 일관성 (eventual consistency)

리더와 팔로워에 대해 동일한 쿼리를 동시에 실행하면 모든 쓰기가 팔로워에 반영되지 않아서 일시적 불일치가 발생란다. 이 때, 데이터베이스에 대한 쓰기를 중단하고 잠시 기다리면 팔로워가 결국 따라잡아 리더와 일치하게 된다. 이러한 현상을 최종 일관성(eventual consistency)이라고 한다.

“최종”(eventual)이라는 용어는 모호한 표현이다. 일반적으로 복제본이 얼마나 뒤처질 수 있는지에 대한 제한은 없다. 정상 작동 시, 리더에서 쓰기가 발생하고 팔로워에 반영되기까지의 지연(복제 지연)은 1초에 불과하며 실제로는 눈에 띄지 않을 수 있다.

그러나 시스템이 거의 용량에 가깝게 작동하거나 네트워크에 문제가 있는 경우 지연이 몇 초 또는 몇 분으로 쉽게 늘어날 수 있다.

지연이 너무 크면 이로 인해 발생하는 불일치는 애플리케이션에 실질적인 문제가 된다.

자신이 쓴 글을 읽을 수 있을까

비동기 복제는 내가 쓴 글을 읽을 수 없다.

새 데이터가 제출되면 리더에게 보낸다. 사용자가 데이터를 볼 때는 팔로워가 데이터를 읽을 수 있다. 이는 데이터를 자주 보지만 가끔씩만 작성하는 경우에 특히 적합하다.

비동기 복제를 사용하면 사용자가 쓰기 직후에 데이터를 볼 경우 새 데이터가 아직 복제본에 도달하지 않았을 수 있다는 문제가 있다. 사용자 입장에서는 자신이 제출한 데이터가 손실된 것처럼 보인다.

읽기 후 쓰기 일관성

이러한 상황에서는 읽기 후 쓰기 일관성(read-after-write consistency)이 필요하며, 읽기-쓰기 일관성(read-your-writes consistency)이라고도 한다. 이는 사용자가 페이지를 다시 로드할 때 항상 자신이 제출한 모든 업데이트를 볼 수 있도록 보장하는 것이다.

읽기 후 쓰기 일관성 구현하기

나의 데이터는 리더에서 읽고, 다른 사람의 데이터는 팔로워에서 읽는다.

사용자가 수정했을 수 있는 내용을 읽을 때는 리더로부터 읽고, 그렇지 않은 경우에는 팔로워로부터 읽는다.

예를 들어, SNS의 사용자 프로필 정보는 다른 사람이 아닌 프로필 소유자만 수정할 수 있다. 항상 리더로부터는 사용자 자신의 프로필을, 팔로워로부터는 다른 사용자의 프로필을 읽는 것이다.

1분간은 리더로부터 읽기

위 방법은 사용자가 대부분의 데이터를 편집할 수 있다면 유용하지 않다. 대부분의 항목을 리더로부터 읽어야 하므로 읽기 확장의 이점이 무효화되기 때문이다.

이 경우, 마지막 업데이트 시간을 추적하고 마지막 업데이트 후 1분 동안은 리더에서 모든 읽기를 수행한다.

최근 기록된 타임스탬프 사용하기

클라이언트는 가장 최근 쓰기의 타임스탬프를 기억할 수 있다. 시스템에서 해당 사용자의 모든 읽기를 제공하는 복제본이 적어도 해당 타임스탬프까지 업데이트를 반영하도록 보장할 수 있다. 복제본이 충분히 최신 상태가 아닌 경우 다른 복제본에서 읽기를 처리하거나 복제본이 따라잡을 때까지 쿼리를 기다릴 수 있다.

동일한 사용자가 랩탑과 모바일을 모두 사용한다면 ?

동일한 사용자가 데스크톱 웹 브라우저와 모바일 앱 등 여러 디바이스에서 서비스에 접속하는 경우 또 다른 복잡성이 발생한다. 이 경우 장치 간 읽기 후 쓰기 일관성을 제공해야 한다.

  • 사용자의 마지막 업데이트 타임스탬프를 기억해야 하는 접근 방식은 한 디바이스에서 실행되는 코드가 다른 디바이스에서 어떤 업데이트가 있었는지 알 수 없다. 이 메타데이터는 중앙 집중화되어야 한다.
  • 복제본이 여러 데이터센터에 분산되어 있는 경우, 서로 다른 디바이스의 연결이 동일한 데이터센터로 라우팅된다는 보장이 없다. 예를 들어, 사용자의 데스크톱 컴퓨터는 가정용 광대역 연결을 사용하고 모바일 디바이스는 셀룰러 데이터 네트워크를 사용하는 경우, 디바이스의 네트워크 경로가 완전히 다를 수 있다. 접근 방식에 리더의 읽기가 필요한 경우 먼저 모든 사용자 디바이스의 요청을 동일한 데이터센터로 라우팅해야 할 수 있다.

단조로운 읽기

애플리케이션이 비동기 팔로워로부터 읽을 때 발생할 수 있는 또 다른 문제는 사용자가 시간을 거꾸로 거슬러 올라가는 것을 볼 수 있다는 것이다. 이는 사용자가 서로 다른 복제본에서 여러 번 읽기를 수행할 때 발생할 수 있다.

단조로운 읽기는 이러한 종류의 이상 현상이 발생하지 않는다는 것을 보장한다. 이는 강력한 일관성(strong consistency)보다는 덜 보장하지만, 최종 일관성(evntual consistency)보다는 더 강력하다. 데이터를 읽을 때 오래된 값이 표시될 수 있는데, 단조로운 읽기는 한 사용자가 여러 번 연속해서 읽어도 이전 데이터를 읽지 않는다.

단조로운 읽기를 달성하는 한 가지 방법은 각 사용자가 항상 동일한 복제본에서 읽도록 하는 것이다. 예를 들어, 복제본은 무작위가 아닌 사용자 ID의 해시를 기반으로 선택할 수 있다. 그러나 해당 복제본이 실패하면 사용자의 쿼리는 다른 복제본으로 다시 라우팅되어야 한다.

일관된 접두사 읽기

일관된 접두사 읽기는 일련의 쓰기가 특정 순서로 발생하면 해당 쓰기를 읽는 모든 사람이 동일한 순서로 표시되도록 하는 것이다. 이는 분할(샤드) 데이터베이스에서 특히 문제가 된다.

데이터베이스가 항상 같은 순서로 쓰기를 적용하면 읽기에 항상 일관된 접두사가 표시되므로 비정상적인 현상이 발생할 수 없다. 그러나 많은 분산 데이터베이스에서는 서로 다른 파티션이 독립적으로 작동하므로 쓰기 순서가 전역적으로 정해져 있지 않아 사용자가 데이터베이스에서 읽을 때 데이터베이스의 일부가 이전 상태로 표시되고 일부는 최신 상태로 표시될 수 있다.

한 가지 해결책은 서로 인과 관계가 있는 모든 쓰기가 동일한 파티션에 쓰여지도록 하는 것이지만, 일부 애플리케이션에서는 그렇게 하는 것이 효율적이지 않을 수 있다.

복제 지연에 대한 해결책

일관된 시스템으로 작업할 때 복제 지연이 몇 분 또는 몇 시간으로 늘어날 경우 애플리케이션이 어떻게 작동하는지 고민해야 한다. 사용자에게 좋지 경험을 제공하려면, 읽기 후 쓰기와 같이 더 강력한 보장 기능을 제공하도록 시스템을 설계하는 것이 중요하다. 복제가 실제로는 비동기식인데 동기식인 것처럼 꾸미는 것은 나중에 문제가 발생할 수 있다.

앞서 설명한 것처럼 애플리케이션이 기본 데이터베이스보다 더 강력한 보장을 제공할 수 있는 방법이 있다. 예를 들어, 리더에 대해 특정 종류의 읽기를 수행하는 것이다. 그러나 애플리케이션 코드에서 이러한 문제를 처리하는 것은 복잡하고 잘못하기 쉽다.

애플리케이션 개발자가 미묘한 복제 문제에 대해 걱정할 필요 없이 데이터베이스가 “올바른 일을 할 것”이라고 믿을 수 있어야 한다. 이것이 바로 트랜잭션이 존재하는 이유다. 트랜잭션은 데이터베이스가 더 강력한 보증을 제공하여 애플리케이션을 더 단순하게 만들 수 있는 방법이다.