데이터 중심 애플리케이션 설계.05.복제
05.Replication
개요
- 이 문서는 [[Designing-Data-Intensive-Applications]]책의 5장을 공부하며 메모한 것입니다.
- 이 문서는 메모일 뿐이니 자세한 내용은 교재를 참고해야 합니다.
복제
네트워크로 연결된 여러 장비에 동일한 데이터의 복사본을 유지하는 것.
- 복제하는 이유
- 사용자와 지리적 거리를 좁혀 지연 시간을 줄인다.
- 시스템 일부에 장애가 발생해도 지속적으로 동작할 수 있게 해 가용성을 높인다.
- 읽기 질의를 제공하는 장비의 수를 확장해 읽기 처리량을 늘린다.
이번 장에서 알아볼 세 가지 복제 알고리즘
- 단일 리더(single-leader)
- 다중 리더(multi-leader)
- 리더 없는(leaderless)
리더와 팔로워(Leaders and Followers)
- 복제 서버(replica): DB의 복사본을 저장하는 각 노드.
- 리더 기반 복제(leader-based replication)
- active/passive 복제라고도 한다.
- master/slave 복제라고도 한다.
리더 기반 복제를 수행하는 방법은 다음과 같다.
- 복제 서버 중 하나를 리더(leader, 또는 master, primary)로 정한다.
- 다른 복제 서버는 팔로워(follower, read replica, slave, secondary, hot standby)로 정한다.
- 클라이언트가 DB에 쓰기 요청을 리더에게 보낸다.
- 리더는 로컬 저장소에 신규 데이터를 기록한다.
- 리더가 신규 데이터를 기록할 때마다 변경 사항을 복제 로그(replication log)나 변경 스트림(change stream)의 일부로 팔로워에게 전송한다.
- 각 팔로워는 리더로부터 로그를 받아, 리더가 처리한 것과 동일한 순서로 모든 쓰기를 적용한다.
읽기는 리더/팔로워 아무에게나 질의할 수 있다.
그러나 쓰기는 리더에게만 허용한다.
동기식 대 비동기식 복제
동기식 복제의 장점
- 팔로워와 리더가 일관성 있게 최신 데이터 복사본을 가지는 것을 보장한다.
- 리더가 작동하지 않아도 데이터는 팔로워에서 계속 사용할 수 있음.
동기식 복제의 단점
- 팔로워가 응답이 없으면 쓰기가 처리되지 않는다.
- 리더는 모든 쓰기를 차단(block)하고, 복제 서버를 다시 사용할 수 있을 때까지 기다려야 한다.
따라서 모든 팔로워를 동기식으로 사용하는 것은 곤란하다.
- 일반적으로 팔로워 하나는 동기식으로 하고, 나머지는 비동기식으로 한다.
- 동기식 팔로워가 느려지거나 사용할 수 없게 되면 비동기식 팔로워 중 하나가 동기식이 된다.
- 이렇게 하면 적어도 2개의 노드에 데이터의 최신 복사본이 있는 것을 보장할 수 있다.
- 이런 설정을 반동기식(semi-synchronous)라 부른다.
새로운 팔로워 설정
새로운 팔로워가 리더의 데이터 복제본을 정확히 갖고 있는지 어떻게 보장하는가?
- DB의 쓰기를 잠그고 복제한다면, 일관성은 획득하나, 고가용성은 희생하게 된다.
중단시간 없이 팔로워를 설정하려면 다음과 같이 한다.
- DB를 잠그지 않고, 리더의 DB 스냅샷을 가져온다.
- 스냅샷을 새로운 팔로워 노드에 복사한다.
- 팔로워를 리더에 연결하여 스냅샷 이후 발생한 모든 데이터 변경을 요청한다.
- 팔로워가 스냅샷 이후 데이터 변경을 모두 처리하면 "따라잡았다(caught up)"고 한다.
노드 중단 처리(Handling Node Outages)
중단 시간 없이 개별 노드를 재부팅할 수 있다는 점은 운영과 유지보수에 큰 장점.
개별 노드의 장애에도 전체 시스템이 동작하게끔 유지하고 노드 중단의 영향을 최소화하는 것이 목표.
리더 기반 복제에서 고가용성은 어떻게 달성하는가?
팔로워 장애 : 따라잡기 복구
팔로워 복구는 쉽다.
- 결함 발생 전에 처리한 마지막 트랜잭션을 알아낸다.
- 리더에 연결해 팔로워 연결이 끊어진 동안 발생한 데이터 변경을 모두 요청한다.
- 변경이 모두 적용되면 리더를 따라잡게 된다.
리더 장애 : 장애 복구
리더 장애 처리는 어렵다.
자동 장애 복구 기능이 있더라도, 수동으로 장애 복구를 하는 쪽을 선호하는 경우도 많다.
- 장애 복구(failover) 과정
- 팔로워 중 하나를 새로운 리더로 삼아야 한다.
- 클라이언트는 새로운 리더로 쓰기를 전송해야 하므로 재설정이 필요.
- 다른 팔로워는 새로운 리더를 바라봐야 한다.
복제 로그 구현
리더 기반 복제의 동작을 알아본다.
구문 기반 복제
- 리더는 모든 쓰기 요청(statement, 구문)을 기록하고,
- 쓰기를 실행한 다음,
- 구문 로그를 팔로워에게 전송한다.
RDB라면
- 모든
INSERT
,UPDATE
,DELETE
구문을 팔로워에게 전달하고, - 팔로워는 SQL 구문을 파싱하고 실행한다.
이 방법의 문제점들
- 구문에서
NOW()
,RAND()
같은 비결정적 함수를 호출하는 경우. - auto increment 칼럼을 쓰거나 DB의 데이터에 의존하는 구문이라면 각 복제 서버에서 정확히 같은 순서로 실행해야 함.
- 부수 효과를 가진 구문(트리거, 스토어드 프로시저, 사용자 정의 함수 등)으로, 각 복제 서버에서 다른 부수 효과가 발생할 수 있음.
문제점의 대안은
- 리더는 구문을 기록할 때, 모든 비결정적 함수 호출을 고정 값을 반환하게끔 한다.
쓰기 전 로그 배송
완전히 동일한 로그를 사용해 다른 노드에서 복제 서버를 구축할 수 있다.
- 리더는 디스크에 로그를 기록하고, 팔로워에게 네트워크로 로그를 전송한다.
- 팔로워가 전송받은 로그를 처리하면 리더와 동일한 데이터 구조의 복제본이 만들어짐.
주의점
- 로그가 제일 저수준의 데이터를 기술하고 있으므로,
- 저장소 엔진 의존성이 생긴다.
- 리더와 팔로워의 DB 버전을 다르게 하면 안됨.
- 버전 업데이트시, 팔로워를 먼저 업데이트하고, 리더를 나중에 업데이트.
- 저장소 엔진 의존성이 생긴다.
논리적(로우 기반)로그 복제
- 복제 로그를 저장소 엔진과 분리하기 위한 대안
-
비 의존적인 로그 형식(logical log, 논리적 로그)을 사용한다.
- 삽입된 로우의 로그는 모든 칼럼의 새로운 값을 포함한다.
- 삭제된 로우의 로그는 로우를 고유하게 식별하는 데 필요한 정보를 포함한다.
- 갱신된 로우의 로그는 로우를 고유하게 식별하는 데 필요한 정보와 모든 칼럼의 새로운 값을 포함한다.
트리거 기반 복제
- 트리거는 애플리케이션 코드를 등록할 수 있게 한다.
- 데이터베이스 시스템에서 데이터가 변경되면(쓰기 트랜잭션) 자동으로 실행된다.
- 트리거 기반 복제는 다른 복제 방식보다 많은 오버헤드가 있다.
복제 지연 문제
읽기 확장(read-scaling)
- 대부분이 읽고 요청이고 쓰기 비율이 작으면 많은 팔로워를 만들어 읽기 요청을 분산.
- 비동기식 복제에서만 동작한다.
최종적 일관성
- 팔로워가 리더에 비해 뒤쳐진 경우(복제 지연) 불일치가 발생한다.
- 최종적 일관성 : 잠시 기다리면 팔로워가 결국 따라잡아 리더와 일치하게 된다.
자신이 쓴 내용 읽기
- 복제 지연이 일어났을 때
- 사용자가 쓰기를 수행하고,
- 곧바로 사용자가 데이터를 확인하면,
- 팔로워에 아직 적용이 안 되어 데이터가 유실된 것으로 생각할 수 있다.
위와 같은 상황에서는 "쓰기 후 일관성(read-after-write consistency)"이 필요하다.
- 사용자가 페이지를 재로딩했을 때, 자신이 제출한 모든 갱신을 볼 수 있음을 보장하는 기능.
- 다른 사용자에 대해서는 보장하지 않는다.
쓰기 후 일관성 구현 방법
- 사용자가 수정한 내용을 읽을 때는 리더에서 읽는다. 그 외에는 팔로워에서 읽는다.
- 예: SNS에서 사용자 프로필 정보는 항상 리더에서만 읽고, 다른 사용자는 팔로워에서 읽는다.
- 마지막 갱신 후 1분 동안은 리더에서 모든 읽기를 수행한다.
- 복제 지연을 모니터링해 리더보다 1분 이상 늦은 모든 팔로워에 대한 질의를 금지하는 방법.
- 복제 서버가 따라잡지 못했다면, 다른 복제 서버가 읽기를 처리한다.
- 또는 따라잡을 때까지 질의를 대기시킨다.
- 한 사용자가 여러 디바이스를 사용하는 경우, 디바이스 간 쓰기 후 읽기 일관성(cross-device read-after-write consistency)가 제공되어야 한다.
단조 읽기(Monotonic Reads)
비동기식 팔로워 방식에서 읽을 때, 사용자가 "시간이 거꾸로 흐르는 현상"을 목격할 수 있음.
- 단조 읽기(monotonic read)는 이런 종류의 이상 현상의 방지를 보장한다.
- 단조 읽기는 강한 일관성보다는 덜한 보장이지만, 최종적 일관성보다는 강한 보장이다.
- 즉, 새로운 데이터를 읽은 후에는 예전 데이터를 읽지 않는다.
단조 읽기를 구현하는 방법
- 각 사용자의 읽기가 항상 동일한 복제 서버에서 수행되게끔 한다.
- 다른 사용자는 다른 복제서버에서 읽는다.
- 예를 들어, 사용자 ID의 해시값을 기반으로 복제 서버를 선택한다.
일관된 순서로 읽기(Consistent Prefix Reads)
일련의 쓰기가 특정 순서로 발생한다면 이 쓰기를 읽는 모든 사용자는 같은 순서로 쓰여진 내용을 보게 됨을 보장.
이 문제는 뒤에서 따로 다룬다.
복제 지연을 위한 해결책
복제 지연이 몇 분, 몇 시간 정도로 증가한다면?
복제가 비동기식으로 동작하지만 동기식으로 동작하는 척 하는 것이 문제 해결 방안.
- 그러나 애플리케이션 코드에서는 이 문제를 다루기엔 어렵다.
- 트랜잭션 사용.
- 트랜잭션은 애플리케이션이 더 단순해지기 위해 DB가 더 강력한 보장을 제공하는 방법.
다중 리더 복제(Multi-Leader Replication)
지금까지 다룬 싱글 리더 복제에는 다음과 같은 문제점이 있다.
- 리더가 하나만 있고, 모든 쓰기는 리더를 거쳐야 한다.
- 리더에 연결할 수 없는 상태라면 DB에 쓰기를 할 수 없다.
해결책
- 다중 리더 설정 : 쓰기를 허용하는 노드를 하나 이상 두는 것으로 확장할 수 있다.
- 각 리더는 동시에 다른 리더의 팔로워 역할도 한다.
다중 리더 복제의 사용 사례
- 다중 데이터센터 운영
- 다중 리더 설정에서는 각 데이터센터마다 리더가 있을 수 있다.
- 각 데이터 센터 내에는 보통의 리더-팔로워 복제를 사용.
- 데이터 센터 간에는 각 데이터 센터의 리더가 다른 데이터 센터의 리더에게 변경 사항을 복제한다.
단일 리더 설정 | 다중 리더 설정 | |
---|---|---|
성능 | 모든 쓰기는 인터넷을 통해 리더가 있는 데이터센터로 이동.(지연 시간 높음) | 모든 쓰기는 로컬 데이터센터에서 처리한 다음, 비동기 방식으로 다른 데이터센터에 복제한다.(네트워크 지연은 사용자에게 숨겨짐) |
데이터센터 중단 내성 | 리더가 있는 데이터센터가 고장나면 다른 데이터센터의 팔로워를 리더로 승진. | 다른 데이터센터와 독립적으로 동작하고, 고장난 데이터센터가 온라인으로 돌아왔을 때 복제를 따라잡는다. |
네트워크 문제 내성 | 데이터센터 내 연결의 쓰기는 동기식이라 네트워크 연결 문제에 매우 민감. | 비동기 복제를 사용하므로 네트워크 문제에 잘 견딘다. (일시적인 네트워크 중단에도 쓰기 처리는 진행되기 때문) |
다중 리더 복제의 큰 단점
- 동일한 데이터를 다른 두 개의 데이터 센터에서 동시에 변경할 수 있다.
- 이런 쓰기 충돌 문제는 나중에 다룬다…
- 미묘한 설정상의 실수나 다른 DB와의 문제가 발생할 수 있음.
쓰기 충돌 다루기
다중 리더 복제에서 발생하는 가장 큰 문제.
다음과 같은 방법들로 충돌 문제를 해결한다.
- 충돌 감지
- 충돌 회피(conflict avoidance)
- 일관된 상태 수렴(converging toward a consistent state)
등등.
다중 리더 복제 토폴로지(Multi-Leader Replication Topologies)
복제 토폴로지(replication topology)는 쓰기를 한 노드에서 다른 노드로 전달하는 통신 경로를 설명한다.
- 원형 토폴로지
- 별 모양 토폴로지
- 전체 연결 토폴로지
리더 없는 복제
노드가 다운됐을 때 데이터베이스에 쓰기
복제 서버 중 하나를 사용할 수 없는 상황에서
- 리더 기반 설정에서 쓰기 처리를 계속하려면 장애 복구를 실행해야 한다.
- 리더 없는 설정에서는 장애 복구가 필요하지 않다.
문제의 노드가 다시 온라인 상태가 되었을 때, 오래된 값을 얻는 것을 방지하려면
- 클라이언트가 DB에서 읽을 때 하나의 복제 서버로 요청을 보내지 않고,
- 읽기 요청을 병렬로 여러 노드로 전송한다.
- 여러 노드에서 응답을 받은 다음, 버전을 비교해 가장 최신 내용을 보여준다.
정족수 일관성의 한계
느슨한 정족수와 암시된 핸드오프
동시 쓰기 감지
Links
- [[Designing-Data-Intensive-Applications]]