CockroachDB 논문의 핵심 설계, 지리 분산 트랜잭션 모델, 복제 및 장애 허용, 시계 동기화, SQL 계층과 쿼리 실행, 그리고 교훈을 정리한다.
14 min read
Aug 13, 2024
전 세계 사용자 기반을 가진 조직들은 수백만 사용자를 위한 OLTP 워크로드를 확장하기 위해 레거시 DBMS를 클라우드 기반 시스템으로 교체하고 있다.
CockroachDB는 높은 가용성과 일관성을 유지하면서 글로벌 OLTP 워크로드를 처리하는 확장 가능한 SQL DBMS이다.
이 논문은 CockroachDB의 설계를 제시한다. 범용 하드웨어에서 일관된 지리 분산 트랜잭션을 지원하기 위해 사용되는 트랜잭션 모델과 장애 허용성 문제를 논의한다.
마지막으로, 얻은 교훈을 공유한다.
현실에서 대규모 조직은 전 세계에 걸친 사용자 기반을 갖는다.
예를 들어, 조직은 GDPR을 준수해야 하며 EU 사용자 개인 데이터는 EU 내에 보관되어야 한다. 사용자는 항상 켜져 있는(always-on) 경험을 원하므로 시스템은 장애 허용적이어야 한다. 데이터베이스는 데이터 이상(anomaly)을 피하기 위해 SQL 트랜잭션을 지원해야 한다.
위 요구사항을 모두 고려하여, CockroachDB는 다음 기능에 초점을 맞춘다:
장애 허용성과 고가용성:
CockroachDB는 데이터베이스의 모든 파티션에 대해 최소 3개의 복제본을 다양한 지리적 존에 걸쳐 유지한다. 노드 장애에 대한 자동 복구 메커니즘을 제공한다.
지리 분산 파티셔닝과 복제본 배치:
수평 확장이 가능하다. 노드가 추가되면 데이터를 자동으로 마이그레이션한다.
사용자는 데이터가 노드들 사이에서 어떻게 파티셔닝되는지, 그리고 복제본이 어디에 위치해야 하는지도 제어할 수 있다.
고성능 트랜잭션:
트랜잭션 프로토콜은 여러 파티션에 걸칠 수 있는 고성능 지리 분산 트랜잭션을 지원한다.
직렬화 가능(serializable) 격리를 제공하고, NTP 같은 표준 시계 동기화 메커니즘을 사용하며, 어떤 퍼블릭/프라이빗 클라우드에서도 실행될 수 있다.
3.1 CockroachDB의 아키텍처
CockroachDB는 shared-nothing 아키텍처를 사용한다.
모든 노드는 데이터 저장과 계산 모두에 사용된다. 클러스터는 임의의 개수의 노드로 구성된다.
노드들은 같은 데이터 센터에 함께 위치할 수도 있고 전 세계로 분산될 수도 있다. 클라이언트는 클러스터 내 어떤 노드에든 연결할 수 있다.
노드에는 여러 계층이 있다. 하나씩 살펴보자.
3.1.1 SQL: SQL은 가장 상위 계층이다. 데이터베이스와의 모든 사용자 상호작용을 위한 인터페이스다. 파서, 옵티마이저, SQL 실행 엔진을 포함한다. 이 계층은 고수준 SQL 문을 하위의 키-값(KV) 저장소로의 저수준 read-and-write 요청으로 변환한다.
3.1.2 Transactional KV: 다음 계층이다. SQL 계층의 요청이 이 계층으로 전달되며, 변경의 원자성을 보장하고 데이터베이스의 격리 보장에 대해서도 크게 책임진다.
3.1.3 Distribution: 이 계층은 논리적 키 공간을 추상화한다. 키로 정렬되어 있고 너무 큰 키 공간에서 모든 사용자 데이터와 시스템 메타데이터가 여기서 접근된다.
데이터베이스는 키에 대해 range 파티셔닝을 사용하여 데이터를 약 64 MiB 크기의 연속적이고 정렬된 청크로 나누는데, 이를 Ranges라고 한다.
이 계층은 각 쿼리의 어떤 부분을 어떤 Range가 처리해야 하는지 식별하고, 그 부분들을 적절히 라우팅하는 책임이 있다.
3.1.4 Replication: 기본적으로 각 range는 3중으로 복제되며, 각 복제본은 서로 다른 노드에 저장된다. 이 계층은 합의 기반 복제를 사용해 수정의 내구성을 보장한다.
3.1.5 Storage: 가장 하위 레벨이다. 로컬 디스크 기반 KV 저장소를 나타낸다. 효율적인 쓰기와 range 스캔을 제공한다. 글 작성 당시에는 RocksDB가 이 계층을 구동했다.
3.2 장애 허용성과 고가용성
3.2.1 Raft를 사용한 복제: CockroachDB는 일관된 복제를 위해 Raft 합의 알고리즘을 사용한다.
Range의 Replicas는 Raft group을 이룬다. 각 replica는 Raft group에 대한 모든 쓰기를 조정하는 장수(long-lived) leader이거나 follower이다.
복제의 단위는 command다. 이는 스토리지 엔진에 대한 **저수준 편집(low-level edits)**의 시퀀스를 나타낸다.
Raft는 Range의 replica들 전반에 걸쳐 일관되고 정렬된 업데이트 로그를 유지한다.
3.2.2 멤버십 변경과 자동 부하 (재)밸런싱: 실행 중인 CockroachDB 클러스터에 노드를 추가하거나 제거할 수 있다.
데이터베이스는 대부분의 replica가 가용한 한 단기 장애에 대해 Raft로 매끄럽게 동작한다.
장기 장애의 경우, 데이터베이스는 복제본이 부족한(under-replicated) Range에 대해 자동으로 새 replica를 생성한다.
여기서는 Raft 내부를 다루지 않는다. Extended Raft 논문을 바탕으로 한 내 글에서 자세히 읽을 수 있다.
3.2.3 Replica 배치: CockraochDB는 replica 배치를 제어하기 위한 수동 및 자동 메커니즘을 가진다.
수동 배치의 경우, 사용자는 데이터베이스의 개별 노드에 속성 집합을 설정한다. 이러한 속성은 노드 능력(RAM/CPU) 및/또는 노드 로컬리티를 지정할 수 있다.
자동 배치에서는, 데이터베이스가 다양한 실패 모드의 심각도를 견디기 위해 장애 도메인(failure domain) 전반에 replica를 분산한다.
3.3 데이터 배치 정책
CockraochDB는 매우 다양한 데이터 배치 정책을 허용한다. 아래는 몇 가지 예시 패턴이다:
지리 파티션된 Replicas: 테이블은 접근 위치에 따라 파티셔닝될 수 있으며, 각 파티션을 특정 리전에 고정(pinned)할 수 있다. 이는 빠른 리전 내부 읽기/쓰기와 가용 영역(AZ) 장애에서의 생존에 도움이 된다.
지리 파티션된 Leas: 지리 파티션된 테이블에서 파티션의 leaseholder를 접근 리전에 고정할 수 있다. 나머지 replica는 나머지 리전에 고정된다. 이는 빠른 리전 내부 읽기와 리전 장애에서의 생존에 도움이 된다. 하지만 그 대가로 리전 간 쓰기가 느려진다.
중복된 인덱스: 인덱스는 특정 리전에 고정될 수 있는 Range에 저장된다. 테이블의 인덱스를 복제하고 각 인덱스의 leaseholder를 특정 리전에 고정함으로써, 데이터베이스는 빠른 로컬 읽기를 제공할 수 있다.
CockroachDB 트랜잭션은 전체 키 공간에 걸칠 수 있으며, 즉 분산 클러스터 전반의 데이터를 건드릴 수 있다.
CockroachDB는 직렬화 가능 격리를 제공하기 위해 다중 버전 동시성 제어(MVCC)의 변형을 사용한다.
4.1 개요
SQL 클라이언트가 SQL을 보내면, 클라이언트가 연결된 gateway 노드에서 트랜잭션이 시작된다.
이 노드는 SQL 클라이언트로부터 요청을 받고 응답한다. 이 노드는 트랜잭션 코디네이터 역할을 한다. 코디네이션이란 트랜잭션을 오케스트레이션하고 커밋 또는 롤백을 결정하는 것을 의미한다.
이제 코디네이션 알고리즘을 보자.
4.1.1 트랜잭션 코디네이터에서의 실행:
아래 다이어그램에 나온 알고리즘은 코디네이터 관점에서 트랜잭션의 고수준 단계를 보여준다.
Press enter or click to view image in full size

Execution at the transaction coordinator
코디네이터는 트랜잭션 처리 동안 SQL 계층으로부터 요청된 KV operations의 연속을 받는다. 해당 operations는 2행의 for loop로 표현되어 있다.
우리는 SQL 클라이언트가 다음 operation을 시작하기 전에 현재 operation에 대한 응답을 필요로 한다는 것을 모두 이해한다.
CockroachDB는 operation을 복제한다. 이 복제 동안 다른 트랜잭션이 **정지(stall)**되는 것은 원치 않는다.
이를 달성하기 위해 코디네이터는 두 가지 중요한 최적화를 사용한다: write pipelining과 parallel commits. 먼저 이를 이해해 보자.
Write Pipelining:
아주 단순히 말하면, write pipelining은 현재 operation을 복제할 때까지 기다리지 않고 결과를 반환할 수 있게 해준다.
코디네이터는 어떻게 그렇게 할까?
코디네이터는 아직 완전히 복제되지 않았을 수도 있는 operation들을 추적한다. 또한 현재 시간으로 초기화된 트랜잭션 타임스탬프를 유지하는데, 이는 알고리즘의 1행에서 수행된다.
간단히 상기하자면: CockroachDB는 MVCC를 사용하므로, 트랜잭션 타임스탬프는 트랜잭션이 읽기 또는 쓰기 operation을 수행하는 시점의 타임스탬프다.
각 operation은 읽거나 업데이트해야 하는 key를 포함한다. 또한 트랜잭션이 현재 operation에 커밋해야 하는지 여부를 나타내는 metadata도 포함해야 한다.
알고리즘의 어려운 부분인 6행을 이해해보자. 여기서는 operation이 커밋을 시도하지 않는 경우다. 이전 operation들과의 오버랩이 없다면, 즉시 실행할 수 있다.
이렇게 해서 서로 다른 key에 대한 여러 operation이 파이프라인된다. 이제 코디네이터는 실행을 위해 **operation(s)**을 leaseholder로 보내고, 9행에서처럼 응답을 기다린다.
가능한 경우는 두 가지다. 응답에 증가된 타임스탬프가 포함될 수도 있고 아닐 수도 있다. 포함되지 않는다면 SQL 계층으로 바로 보낼 수 있다.
타임스탬프가 증가한다면, 10행의 다른 경우처럼 추가 작업이 필요하다.
이제 코디네이터는 operation에서 사용된 key가 현재 표시된 트랜잭션 타임스탬프와 증가된 타임스탬프 사이의 range에서 변경되지 않았음을 검증해야 한다. 이는 11행에 주어진다. 이는 시스템의 일관성을 보장한다.
검증에 따라, 충돌하는 변경이 없다면 트랜잭션 타임스탬프가 업데이트되고, 그렇지 않으면 트랜잭션은 실패로 표시된다.
Parallel Commits
다시 단순히 말하면, parallel commits는 커밋 operation과 write pipeline이 병렬로 복제되도록 한다.
다시 질문은 코디네이터가 어떻게 그렇게 하느냐이다.
전형적인 구현은 직관적이다. 먼저 모든 쓰기가 복제되었는지 검증한 다음, 트랜잭션을 커밋한다.
Parallel Commits 프로토콜은 새로운 staging 트랜잭션 상태를 만든다. 진짜 상태는 모든 쓰기가 복제되었는지 여부에 조건부로 달려 있다.
코디네이터는 다음 두 가지를 병렬로 수행할 수 있다:
둘 다 성공하면, 코디네이터는 SQL 계층에 즉시 트랜잭션이 커밋되었다고 확인(acknowledge)할 수 있다.
또한 코디네이터는 트랜잭션 상태가 명시적으로 커밋되었음을 비동기로 기록한다.
4.1.2 Leaseholder에서의 실행
이제 leaseholder에서 실행되는 경우를 이해해보자. 아래 다이어그램에 나와 있다:
Press enter or click to view image in full size

Execution at the Leaseholder
leaseholder는 코디네이터로부터 operation을 받는다.
첫 단계는 2행에 나온 것처럼 lease가 여전히 유효한지 확인하는 것이다.
다음으로 3행에 나온 것처럼, op의 key들과 op가 의존하는 모든 operation에 대해 latch를 획득한다.
그 다음 4행에 나온 것처럼, op가 의존하는 operation들이 성공했는지 검증한다.
leaseholder가 operation을 **평가(evaluate)**하는 흥미로운 경우를 논의해보자.
leaseholder는 스토리지 엔진에서 어떤 데이터 수정이 필요한지 결정한다. 이는 검증 단계라는 점에 유의하라. 지금은 적용(apply)하지 않는다.
나머지 케이스들은 단순하다.
operation이 커밋이 아니라면, 10행에 나온 것처럼 복제를 기다리지 않고 코디네이터에 응답을 보낸다.
operation이 쓰기라면, 12행에 나온 것처럼 command를 복제하고 로컬 스토리지 엔진에 적용한다.
leaseholder는 이 시점에서 latch를 해제한다.
operation이 커밋이라면, 15행에 나온 것처럼 코디네이터 노드에 응답을 반환한다.
4.2 원자성 보장
CockroachDB는 커밋 시점 이전의 모든 쓰기를 **잠정(provisional)**으로 간주함으로써 트랜잭션의 원자적 커밋을 달성한다.
잠정 쓰기 값은 write intents라고 불린다. intent는 선행 메타데이터를 가진 KV 쌍이다. 메타데이터는 뒤따르는 것이 intent임을 알려준다.
메타데이터는 트랜잭션 레코드를 가리킨다. 이 레코드는 트랜잭션당 **특수한 키(트랜잭션마다 유일)**로, pending, staging, committed, aborted 같은 상태를 표현한다.
리더(reader)가 intent를 만나면, 리다이렉트를 따라가 상태를 읽는다.
상태가 committed이면, 리더는 intent를 일반 값처럼 간주한다.
상태가 aborted이면, 리더는 intent를 무시한다.
상태가 pending이면, 리더는 이를 블록한다.
상태가 staging이면, 리더는 확신할 수 없고 트랜잭션을 중단(abort)하려 시도한다.
4.3 동시성 제어
CockraochDB는 MVCC 시스템이다. 각 트랜잭션은 커밋 타임스탬프를 가진다.
이렇게 해서 시스템 내 모든 트랜잭션에 대한 전순서(total ordering)를 갖게 된다. 이는 직렬화 가능한 실행을 나타낸다.
트랜잭션 간 충돌이 존재할 수 있으며, 이 경우 커밋 타임스탬프 조정이 필요하다. 이러한 충돌을 논의해보자.
4.3.1 Write-read 충돌: 리더는 커밋되지 않은 intent를 만나면 라이터(writer)와 충돌한다. intent의 타임스탬프가 더 낮다면 읽기는 대기하고, 그렇지 않으면 intent를 무시한다.
4.3.2 Read-write 충돌: 타임스탬프 ta에서 어떤 key에 대한 쓰기는, 동일 key에 대해 더 높은 타임스탬프 tb(ta보다 크거나 같음)에서 이미 읽기가 있었다면 수행될 수 없다. CockraochDB는 이 쓰기 트랜잭션이 커밋 타임스탬프를 tb보다 뒤로 진행시키도록 강제한다.
4.3.2 Write-write 충돌: 라이터는 커밋되지 않은 intent를 만나면 다른 라이터와 충돌한다. intent의 타임스탬프가 더 낮다면 현재 쓰기는 이전 쓰기가 커밋될 때까지 기다린다. intent의 타임스탬프가 더 높다면 현재 쓰기는 자신의 타임스탬프를 그보다 뒤로 진행시킨다. 이러한 상황에서 데드락이 발생할 수 있으며, CockroachDB는 분산 데드락 탐지 알고리즘을 사용해 그중 하나를 중단(abort)한다.
4.4 Read Refreshes
앞선 충돌 시나리오에서, 경우에 따라 커밋 타임스탬프를 앞으로 진행해야 함을 보았다.
팀은 직렬화 가능성을 유지해야 하므로, 읽기 타임스탬프도 커밋 타임스탬프에 맞추어 진행되어야 한다.
아주 단순히 말하면, 트랜잭션의 읽기 타임스탬프를 ta에서 tb로 진행시키는 것은, 트랜잭션이 ta에서 읽었던 어떤 데이터도 구간 **(ta, tb ]**에서 업데이트되지 않았음을 증명할 수 있을 때만 가능하다.
Medium에 무료로 가입하여 이 작성자의 업데이트를 받아보세요.
더 빠른 로그인을 위해 나를 기억하기
CockroachDB는 이를 해결하기 위해 트랜잭션의 read set에 있는 key들을 유지한다.
CockroachDB는 NTP 또는 Amazon Time Sync Service를 사용해 노드들의 시계를 동기화하여, 어떤 퍼블릭/프라이빗 클라우드에서도 실행될 수 있다. Google Spanner는 같은 목적을 위해 특수 하드웨어를 사용한다.
5.1 하이브리드-논리 시계
클러스터 내 각 노드는 하이브리드 논리 시계(HLC)를 유지한다.
이 시계는 물리 시간과 논리 시간을 결합한 타임스탬프를 제공한다.
물리 시간은 노드의 시스템 시계를 기반으로 하고, 논리 시간은 Lamport 시계를 기반으로 한다.
클러스터 내 어떤 두 노드 사이에서도 HLC 오프셋에는 허용 가능한 최대치가 있다. 기본값은 500 ms이다.
HLC는 다음과 같은 중요한 성질을 제공한다:
5.2 불확실성 구간
CockroachDB는 정상 조건에서 읽기와 쓰기에 대해 단일 키 선형화 가능성(single-key linearizability)을 만족한다.
이는 주어진 key에 대한 모든 operation이 원자적으로 보인다는 뜻이다. 또한 그 operation들의 실시간 순서(real-time ordering)와 일치하는 어떤 전체 선형 순서(total linear order)가 존재한다.
중요한 점 하나는 CockroachDB가 **엄격한 직렬화 가능성(strict serializability)**을 지원하지 않는다는 것이다. 서로 겹치지 않는(disjoint) key 집합을 건드리는 트랜잭션들이 실시간에서의 순서와 반드시 일치한다는 보장은 없다.
위 사실은, 클라이언트 간 매우 저지연의 통신 채널이 있는 경우가 아니라면 현실에서는 문제가 되지 않는다. 그런 경우는 극히 드물다.
그렇다면 CockroachDB는 단일 키 선형화 가능성 속성을 어떻게 달성할까?
데이터베이스는 각 트랜잭션에 대해 uncertainty interval을 추적한다.
이 구간 내에서는 두 트랜잭션 간 인과적 순서가 불확정(indeterminate)하다고 간주된다.
트랜잭션이 생성될 때, provision time commit_ts가 주어진다. 값은 HLC에서 온다. uncertainty interval은[commit_ts, commit_ts + max_offset]이다.
트랜잭션은 클러스터의 max_offset만큼 더 이른 잠정 커밋 타임스탬프를 받을 수 있다.
트랜잭션이 어떤 key에서 자신의 잠정 커밋 타임스탬프보다 위에 있지만 uncertainty interval 내에 있는 타임스탬프의 값을 만나면, 잠정 커밋 타임스탬프(하한)를 불확실한 값보다 위로 이동시킨다.
트랜잭션은 uncertainty interval의 상한은 고정한 채로 유지한다는 점에 유의하라.
5.3 시계 스큐 하에서의 동작
처리해야 할 중요한 포인트가 하나 더 있다.
만약 시계 스큐가 최대 시계 오프셋보다 크다면 어떻게 될까?
단일 range(그 안의 값들)에서는 Raft를 통해 일관성이 유지된다.
Raft는 시계에 의존하지 않으므로, 시계 스큐와 무관하게 변경의 순서는 선형화 가능하게 유지된다.
문제는 Range lease가 Raft를 거치지 않고 leaseholder에서 읽기를 제공할 수 있게 할 때 발생한다.
CockroachDB는 이러한 상황이 트랜잭션 격리에 영향을 주지 않도록 두 가지 안전장치를 사용한다.
CockroachDB는 일부 확장을 포함하여 ANSI 표준 SQL의 PostgreSQL 방언 대부분을 지원한다.
SQL 데이터 모델과 그것이 아래 계층에 어떻게 매핑되는지 이해해보자.
6.1 SQL 데이터 모델
모든 SQL 테이블과 인덱스는 하나 이상의 Range에 저장된다.
모든 사용자 데이터는 하나 이상의 정렬된 인덱스에 저장된다. 그중 하나가 기본 인덱스(primary index)다.
기본 인덱스는 기본 키(primary key)를 기준으로 키가 지정되며, 다른 모든 컬럼은 값(value)에 저장된다(즉 KV 저장소가 된다).
보조 인덱스(secondary index)는 index 키를 기준으로 키가 지정된다. 보조 인덱스는 기본 키 컬럼과 인덱스 스키마에 의해 지정된 추가 컬럼을 저장한다.
6.2 쿼리 옵티마이저
Cascades 스타일의 쿼리 옵티마이저는 200개 이상의 변환 규칙을 사용해 SQL 쿼리 플래닝을 수행한다.
CockroachDB는 쿼리 변환을 위한 DSL인 Optgen을 사용한다. Optgen은 변환 규칙을 CockroachDB 코드베이스의 나머지 부분과 통합하기 위해 Go 프로그래밍 언어로 컴파일된다.
CockroachDB는 데이터베이스의 지리 분산 및 파티션 특성에 특화된 일부 변환 규칙을 사용한다.
6.3 쿼리 계획 및 실행
SQL 쿼리는 다음 두 모드 중 하나로 실행된다:
논문 작성 당시에는 읽기 전용 쿼리를 distributed mode로 실행할 수 있다.
분산 여부 결정은 네트워크를 통해 전송되어야 하는 데이터 양을 추정하는 휴리스틱을 사용한다.
분산 쿼리 계획을 생성하기 위해, CockroachDB는 물리 플래닝 단계를 수행하여 쿼리 옵티마이저의 계획을 물리적 SQL operators의 방향성 비순환 그래프(DAG)로 변환한다.
물리 플래닝은 논리적 스캔 operation을 여러 TableReader operator로 분할한다.
각 operator는 스캔이 읽는 Range를 포함한 노드에 지정된다.
논리 operator들은 TableReader들과 같은 노드에 스케줄된다. 이는 필터, 조인, 집계를 물리 데이터 가까이로 푸시다운하는 데 도움이 된다.
Press enter or click to view image in full size

예시: 분산 해시 조인을 위한 물리 계획
위 다이어그램은 3-노드 클러스터에서 두 테이블 a와 b의 기본 인덱스에 대해 분산 해시 조인을 수행하는 예시를 보여준다.
CockraochDB는 입력 카디널리티와 계획 복잡도에 따라 Row-at-a-time과 Vectorized라는 두 가지 서로 다른 실행 엔진을 사용한다.
6.4 스키마 변경
CockroachDB에는 스키마 변경을 위한 프로토콜이 있다.
이 프로토콜은 스키마 변경 동안에도 테이블이 온라인 상태를 유지할 수 있게 하며, 서로 다른 노드들이 비동기적으로 서로 다른 시점에 새 테이블 스키마로 전환할 수 있게 한다.
이는 Google F1이 사용한 솔루션을 구현한다. 이 프로토콜은 각 스키마 변경을 점진적 변경들의 시퀀스로 분해한다.
7.1 Raft를 실제로 운영하기
팀은 초기에 합의 알고리즘으로 Raft를 선택했다.
실제로는 지나친 chatter와 한 번에 단일 노드만 추가되는 문제 같은 몇 가지 이슈를 발견했다.
팀은 atomic replication changes라는 새로운 알고리즘을 개발했다. 이는 Joint Consensus라고도 불린다.
7.2 스냅샷 격리 제거
데이터베이스는 초기에는 SNAPSHOT과 SERIALIZABLE이라는 두 가지 격리 수준을 제공했다.
현재는 SERIALIZABLE만 지원한다.
7.3 Postgres 호환성
팀은 PostgreSQL의 SQL 방언과 네트워크 프로토콜을 채택하기로 했다.
Google Spanner는 가장 강한 격리 수준과 엄격한 직렬화 가능성을 가진 SQL 시스템이다.
Calvin, FaunaDB, SLOG 또한 엄격한 직렬화 가능성을 제공한다. 이들의 결정적 실행 프레임워크는 read/write set을 사전에 요구한다.
H-Store와 VoltDB는 직렬화 가능 격리를 지원하는 메인 메모리 데이터베이스다.
Slicer는 해시된 키에 대해 range 파티셔닝을 수행하고 부하에 따라 range를 분할/병합한다.
TiDB는 MySQL wire protocol과 호환되며 HTAP 워크로드를 지원하도록 설계된 오픈 소스 분산 SQL DBMS다.
CockroachDB는 오픈 소스이자 확장 가능한 SQL 데이터베이스다.
트랜잭션 프로토콜은 특수 하드웨어 없이도 규모 확장 하에서 직렬화 가능 격리를 달성한다.
합의 기반 복제는 장애 허용성, 고가용성, 그리고 성능 최적화를 제공한다.
CockroachDB의 SQL 계층은 사용자에게 SQL에 대한 유연성과 친숙함을 제공한다.
다가오는 릴리스에는 완전히 재설계된 스토리지 계층과 지리 인지(geo-aware) 쿼리 최적화가 포함될 예정이다.
Slicer: Auto-sharding for data center applications
Volley: Automated data placement for geo-distributed cloud services
MonetDB/X100: Hyper-Pipelining Query Execution
Serializable Isolation for Snapshot Databases
Adapting to Access Locality via Live Data Migration in Globally Distributed Datastores
FoundationDB Record Layer: A Multi-Tenant Structured Datastore
PNUTS: Yahoo!’s hosted data serving platform
G-store: a scalable data store for transactional multi-key access in the cloud
Logical physical clocks and consistent snapshots in globally distributed databases
Ocean vista: gossip-based visibility control for speedy geo-distributed transactions
How fast can a distributed transaction commit?
Linearizability: A correctness condition for concurrent objects
H-store: a high-performance, distributed main memory transaction processing system
Riak core: Building distributed applications without shared state
MDCC: Multi-data center consistency
Time, clocks, and the ordering of events in a distributed system
Towards a non-2pc transaction management in distributed database systems
Low-latency multi-datacenter databases using replicated commit
Serializable snapshot isolation in PostgreSQL
SLOG: serializable, low-latency, geo-replicated transactions
Clay: Fine-grained adaptive partitioning for general database schemas
Wren: Nonblocking reads in a partitioned transactional causally consistent data store
E-store: Fine-grained elastic partitioning for distributed transaction processing systems
Calvin: fast distributed transactions for partitioned database systems
Implementation of Cluster-wide Logical Clock and Causal Consistency in MongoDB
Spanstore: Cost-effective geo-replicated storage spanning multiple cloud services
Carousel: low-latency transaction processing for globally distributed data
Solar: towards a shared-everything database on distributed log-structured storage