Разбор CockroachDB с примерами кода: от основ до практического использования

Практическое руководство по CockroachDB с примерами SQL и Go кода. Статья объясняет ключевые концепции распределенной SQL БД, демонстрирует создание таблиц, выполнение распределенных транзакций, настройку размещения данных и работу с changefeeds. Рассмотрены как сильные стороны, так и компромиссы при использовании CockroachDB.
CockroachDB — это распределенная SQL-база данных с открытым исходным кодом, разработанная для обеспечения высокой устойчивости, согласованности и горизонтальной масштабируемости. Ее архитектура вдохновлена Google Spanner, и она позиционирует себя как «база данных, которую невозможно убить». Давайте разберем ее ключевые концепции и посмотрим, как она работает на практике, через призму кода.

В основе CockroachDB лежит концепция «монолитной» реплицированной ключ-значение хранилки (RockSDB от Facebook), поверх которой реализован совместимый с PostgreSQL SQL-слой. Данные автоматически шардируются (разбиваются) на диапазоны (ranges) размером около 64 МБ, каждый из которых реплицируется (по умолчанию в 3 копии) across different nodes and even geographic regions. Распределенный протокол согласия Raft обеспечивает консенсус между репликами каждого диапазона.

Давайте начнем с простейшего SQL-взаимодействия. Подключимся к кластеру (например, к локальному одноузловому кластеру, запущенному через `cockroach demo`) и создадим таблицу.

CREATE DATABASE bank;

USE bank;

CREATE TABLE accounts (
 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
 balance DECIMAL NOT NULL DEFAULT 0,
 currency STRING NOT NULL,
 last_updated TIMESTAMP DEFAULT now()
);

Этот SQL будет знаком любому, кто работал с PostgreSQL. CockroachDB поддерживает большинство типов данных и функций Postgres. Теперь вставим данные.

INSERT INTO accounts (balance, currency) VALUES (1000.50, 'USD'), (750.00, 'EUR');

Теперь рассмотрим одну из сильнейших сторон — распределенные транзакции с гарантированной согласованностью (Serializable isolation). Допустим, мы хотим перевести деньги с одного счета на другой. В CockroachDB это делается стандартным SQL, но база гарантирует, что даже если строки `accounts` находятся на разных физических серверах (нодах), транзакция будет атомарной и согласованной.

BEGIN;
SELECT balance FROM accounts WHERE id = '...id1...' FOR UPDATE;
-- Приложение проверяет достаточность средств
UPDATE accounts SET balance = balance - 100.00 WHERE id = '...id1...';
UPDATE accounts SET balance = balance + 100.00 WHERE id = '...id2...';
COMMIT;

Ключевая фраза `FOR UPDATE` блокирует строки, предотвращая условия гонки. CockroachDB использует метод MVCC (Multiversion Concurrency Control) и временные метки (HLC — Hybrid Logical Clocks) для ordering транзакций в распределенной среде.

Теперь посмотрим на шардирование и расположение данных. CockroachDB автоматически создает первичный ключ как ключ шардирования по умолчанию. Но мы можем управлять этим с помощью `PARTITION BY`. Более важной является возможность настройки локали данных (Data Placement), например, для соответствия GDPR.

ALTER TABLE accounts CONFIGURE ZONE USING
 num_replicas = 5,
 constraints = '{"region": "eu-west-1"}',
 lease_preferences = '[[+region=eu-west-1]]';

Этот код (упрощенно) указывает, что реплики таблицы `accounts` должны размещаться в регионе `eu-west-1`. CockroachDB будет автоматически перемещать диапазоны для соблюдения этих ограничений.

Еще одна мощная функция — это Change Data Capture (CDC) и создание материализованных представлений. CockroachDB может отправлять изменения в Kafka или облачный storage.

CREATE CHANGEFEED FOR TABLE accounts INTO 'kafka://broker:9092' WITH updated, resolved = '10s';

Это создаст поток изменений в реальном времени. Для аналитических запросов полезны индексы и инвертированные индексы для работы с JSONB.

CREATE INDEX idx_currency ON accounts(currency, balance DESC);
SELECT id, balance FROM accounts WHERE currency = 'USD' ORDER BY balance DESC LIMIT 10;

CockroachDB оптимизирует выполнение этого запроса, возможно, используя только индекс (covering index scan), даже в распределенном кластере.

При программировании на Go (родной язык для CockroachDB) взаимодействие выглядит стандартно, но с учетом retry-логики для транзакций из-за возможных конфликтов.

import (
 "database/sql"
 "fmt"
 _ "github.com/lib/pq"
)
func transferMoney(db *sql.DB, from, to string, amount float64) error {
 tx, err := db.Begin()
 if err != nil { return err }
 // Рекомендуется использовать конструкцию WHERE ... = $1 для безопасности
 _, err = tx.Exec("UPDATE accounts SET balance = balance - $1 WHERE id = $2", amount, from)
 if err != nil {
 tx.Rollback()
 return err
 }
 _, err = tx.Exec("UPDATE accounts SET balance = balance + $1 WHERE id = $2", amount, to)
 if err != nil {
 tx.Rollback()
 return err
 }
 return tx.Commit()
}

Важно помнить, что в высоконагруженных сценариях CockroachDB рекомендует использовать подготовленные выражения и, возможно, паттерн «транзакции с перезапуском при ошибке сериализации».

В заключение, CockroachDB предлагает мощную абстракцию «просто SQL» над сложным распределенным кластером. Ее сила — в автоматическом управлении данными, репликацией и отказоустойчивостью. Однако за это приходится платить: операции, затрагивающие несколько шардов, могут иметь большую latency, чем в локальной БД, а требования к ресурсам (CPU, память, диск) для каждого узла значительны. Правильное проектирование схемы (выбор первичного ключа, индексы, географическое размещение) критически важно для производительности.
137 2

Комментарии (7)

avatar
zckruhnwyg 27.03.2026
Попробовал развернуть тестовый кластер по вашим примерам. Всё сработало, спасибо за четкие инструкции!
avatar
piqsryhwoyp 28.03.2026
Интересно, как CockroachDB справляется с геораспределенностью в реальных продакшн-кейсах? Есть ли подводные камни?
avatar
m88xl4vy7olk 28.03.2026
Для стартапа, который планирует глобальный рост, такая БД выглядит очень перспективно. Спасибо за структурированное введение!
avatar
l2i3byv28 29.03.2026
Жду продолжения про сравнение производительности с Postgres в сценариях с высокой конкурентной нагрузкой.
avatar
l2i3byv28 30.03.2026
Архитектура, вдохновленная Spanner, это мощно, но не слишком ли сложна настройка кластера для небольшого проекта?
avatar
zex7n8xglti8 30.03.2026
Статья хорошая, но хотелось бы больше глубины в разделе про выбор ключей шардирования — это критично для перфоманса.
avatar
ss3ongwzj 31.03.2026
Отличный разбор! Особенно полезны примеры кода, сразу видно, как работать с распределенными транзакциями на практике.
Вы просмотрели все комментарии