CockroachDB Multi-Region Guide: Table Locality, Latency, and Resilience Tradeoffs

数据库

CockroachDB can run a SQL database across regions, but a multi-region database is not magic. It improves resilience and can reduce latency when data is placed near users. It can also add write latency, transaction conflicts, operational complexity, and data-residency decisions that must be designed explicitly.

This guide focuses on the practical choices behind a CockroachDB multi-region design: which regions to add, how to choose table locality, when to use regional-by-row tables, when global tables make sense, and what to verify before production.

Useful references:

The Main Design Question

Before changing SQL, decide what your application needs most:

Goal Design direction Tradeoff
Low-latency reads for regional users Keep data near the region that reads it most Cross-region writes may still cost more
Data residency Use regional placement and explicit region ownership Schema and routing must be disciplined
Global reference data Use global tables for read-mostly data Writes are usually more expensive
Regional failure tolerance Choose the right survival goal and topology More replicas and coordination can increase latency
Active users in many regions Route traffic to nearby regions and model data ownership Conflicting writes still need application handling

The best multi-region setup starts from access patterns, not from geography alone.

Core Concepts

CockroachDB's multi-region abstractions are built around a few terms:

  • Cluster region: A region assigned to nodes at startup using locality settings.
  • Database region: A region added to a database. One region is the primary region.
  • Primary region: The default region used by the database unless table locality says otherwise.
  • Table locality: How CockroachDB optimizes placement and access for a table.
  • Survival goal: How many failures the database is designed to survive.
  • Secondary region: A failover-related region for supported configurations.

These settings affect both performance and availability. Do not treat them as deployment labels only.

Basic Multi-Region Setup

A multi-region cluster starts with node locality. Each node should know its region and zone.

cockroach start \
  --locality=region=us-east-1,zone=us-east-1a \
  --certs-dir=certs \
  --join=node1:26257,node2:26257,node3:26257

Then configure database regions.

ALTER DATABASE global_app SET PRIMARY REGION "us-east-1";
ALTER DATABASE global_app ADD REGION "eu-west-1";
ALTER DATABASE global_app ADD REGION "ap-southeast-1";

SHOW REGIONS FROM DATABASE global_app;

This does not automatically make every query fast everywhere. It creates the regional foundation. Table locality and application routing decide most of the user-visible behavior.

Choose Table Locality

Table locality controls where data is placed and optimized.

Locality Best for Notes
Regional by table Data mostly owned by one region Simple for region-specific tables
Regional by row Rows owned by different regions Useful for user, tenant, or account data
Global Small read-mostly reference data Good for reads, more careful for writes

Regional By Table

Use regional-by-table when the entire table belongs mostly to one region.

CREATE TABLE eu_tax_rules (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    country STRING NOT NULL,
    rule JSONB NOT NULL
) LOCALITY REGIONAL BY TABLE IN "eu-west-1";

This is a good fit for regional configuration, legal rules, local catalogs, or operational data tied to one geography.

Regional By Row

Use regional-by-row when each row has a home region. This is common for user or tenant data.

CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    email STRING NOT NULL,
    home_region crdb_internal_region NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
) LOCALITY REGIONAL BY ROW;

The application must set and preserve the correct home region. Do not treat the region column as an incidental field. It is part of the data model.

Global Tables

Use global tables for small, read-heavy data needed everywhere.

CREATE TABLE countries (
    code STRING PRIMARY KEY,
    name STRING NOT NULL
) LOCALITY GLOBAL;

Good candidates include country codes, feature flags that rarely change, public configuration, and other reference data. Avoid using global tables for high-frequency transactional writes unless you have tested the latency and conflict behavior.

Route Traffic Intentionally

Database placement is only half the design. Application traffic should usually be routed to the nearest healthy region.

Check:

  • Which app region handles each user request.
  • Whether connection pools connect to local database nodes.
  • Whether read traffic follows the user's data home.
  • Whether writes are sent to the region that owns the row or tenant.
  • Whether failover sends traffic to a region that can safely serve the workload.

If a user in Europe talks to an app server in Europe, but that app server writes rows homed in the United States, the database cannot hide all latency.

Handle Transaction Conflicts

Multi-region does not remove the need to design write ownership. If two regions update the same row frequently, you can still see retries and contention.

Reduce conflict risk by:

  • Assigning each tenant, account, or document a clear write owner.
  • Avoiding hot global counters.
  • Using idempotent commands and retry-safe transaction logic.
  • Keeping transactions short.
  • Splitting high-write records into smaller ownership units.
  • Moving read-heavy shared data into reference tables.

Serializable isolation is valuable, but the application still needs a retry strategy.

Data Residency

For residency requirements, document what must stay in which geography:

  • User profile data.
  • Payment or billing data.
  • Logs and audit records.
  • Backups.
  • Derived analytics data.
  • Search indexes and caches.

It is not enough to place the primary table correctly. Copies, exports, logs, backups, and downstream systems must follow the same policy.

Survival Goals

Survival goals define what failures a database is designed to tolerate. Higher resilience usually requires more careful topology and may affect latency.

Ask:

  • Do you need to survive a zone failure or a full region failure?
  • How many regions and zones are available?
  • Which tables must remain writable during a failure?
  • Which features are incompatible with your table locality choices?
  • Has failover been tested with real application traffic?

Do not write an RTO or RPO promise in architecture docs until you have tested it under your deployment model.

Production Checklist

Before production, verify:

  • Regions and zones are configured consistently at node startup.
  • Database primary and secondary regions are intentional.
  • Table locality is selected per access pattern.
  • Regional-by-row tables have reliable region assignment.
  • Application routing matches data ownership.
  • Transaction retry logic is implemented.
  • Backups and downstream systems respect residency rules.
  • Schema changes are run from an appropriate region.
  • Observability covers latency, retries, leaseholder movement, and unavailable ranges.
  • Failover drills are documented and repeated.

Common Mistakes

Making Every Table Global

Global tables are useful, but they are not a default. Use them for small, read-mostly data. For high-write business data, test carefully.

Ignoring The Application Layer

If app traffic is not routed by region, database locality cannot fully solve latency.

Missing Retry Logic

Distributed SQL systems expect applications to handle retryable transaction errors. Make retries explicit and idempotent.

Treating Residency As A Single Table Setting

Residency includes backups, logs, analytics, search, and exports. Audit the whole data flow.

Skipping Failure Tests

A multi-region design should be tested under node, zone, and region failure scenarios. Do not assume the diagram matches production behavior.

Summary

CockroachDB multi-region design is about tradeoffs: placing data near users, meeting residency rules, surviving failures, and keeping write paths understandable. Start with access patterns and data ownership. Then choose table locality, configure regions, implement retries, and test failover.

The goal is not "active-active everywhere." The goal is predictable behavior under normal traffic and during regional failure.

Try these browser-local tools — no sign-up required →

#CockroachDB多区域#多活数据库#全球分布式#Geo分区#2026#数据库