关于 designing-multi-region-applications
designing-multi-region-applications 是面向 CockroachDB 应用开发者的多区域架构设计技能,帮助根据读写模式选择表区域策略。它还提供延迟考量、拓扑验证方法和演示流程。
主要功能
- 01比较多区域表与分区模式
- 02根据读写模式选择区域策略
- 03权衡 GLOBAL 与 REGIONAL BY ROW
- 04验证租约持有者和区域配置
- 05规划多区域演示与迁移
适用场景
- 01为多区域应用选择数据布局
- 02设计跨区域读写和容灾行为
- 03验证区域配置后的租约分布
- 04准备多区域架构演示或迁移
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ cockroachlabs/ cockroachdb-skills --skill designing-multi-region-applications安装后在 Claude Code 中输入/designing-multi-region-applications确认已加载。
详细介绍
设计多区域应用程序
指导开发者为其 CockroachDB 应用程序选择合适的多区域模式,并通过适当的验证来实现。介绍如何在常规区域表、REGIONAL BY ROW、GLOBAL 表和手动地理分区之间做出选择的决策模型,并提供可用于比较不同方案的实操演示框架。
与其他技能的互补关系: 事务设计模式请参阅 designing-application-transactions。SQL 语法和架构设计请参阅 cockroachdb-sql。
何时使用此技能
- 决定如何在 CockroachDB 中为多区域读写行为建模
- 在主动-主动和主动-被动架构之间做出选择
- 评估
REGIONAL BY ROW与手动地理分区 - 了解
GLOBAL表的行为和权衡 - 设计支持多个区域本地读写的方案
- 构建或展示多区域演示或研讨会
- 验证租约持有者位置和区域配置
- 优化跨区域事务延迟
以下情况请勿使用此技能:问题仅涉及 SQL 语法、索引或通用架构设计,且不涉及多区域决策。
前提条件
- 了解 CockroachDB 范围架构和租约持有者的概念
- 拥有一个多区域集群,其节点使用
--locality=region=...,zone=...启动,并与下方示例中使用的区域匹配。如果区域位置不匹配,DDL 会报错region "..." does not exist,而+region=...之类的约束也不会匹配任何节点。本地快速搭建方式:
对于长期运行的集群,请参阅 setting-up-local-cluster,并在每次调用# 9-node demo with three regions, three AZs each — note --no-example-database cockroach demo --no-example-database --nodes=9 \ --demo-locality=region=NA-NE,az=1:region=NA-NE,az=2:region=NA-NE,az=3:region=NA-MW,az=1:region=NA-MW,az=2:region=NA-MW,az=3:region=EU-DE,az=1:region=EU-DE,az=2:region=EU-DE,az=3cockroach start时添加--locality=region=...,zone=...。 - 了解应用程序的写入模式(单区域或多区域)
模式选择
步骤 1:确定应用程序的写入模型
首先要问:写入主区域是一个还是多个?
- 如果应用程序只有一个主要读写区域,请从主区域/常规区域表模型或手动配置的主动-被动设计入手。
- 如果应用程序需要在多个区域实现低延迟读写,请评估手动地理分区或
REGIONAL BY ROW。 - 如果表主要存储应在各处快速读取的参考数据,且写入路径并非关注重点,可以考虑
GLOBAL表。
步骤 2:选择模式
A. 常规区域表(主动-被动)
适用情况:
- 应用程序只有一个主要读写区域
- 远程区域是次要区域或以读取为主
- 相比在所有区域实现本地写入,更看重简单性
特点:
- 所有租约持有者都留在活跃区域
- 其他区域的副本可提供韧性,并在单个区域故障时维持运行
- 参考延迟:写入约 20 ms,读取约 2~5 ms(本地区域)
建议: 优先采用更高层级的多区域抽象,除非用户明确需要手动控制分区、投票副本和租约偏好。
B. 手动地理分区并指定区域特定的租约持有者
适用情况:
- 应用程序采用主动-主动模式
- 数据模型按区域划分键
- 团队希望拥有明确的运维控制权
- 了解内部机制(分区、投票副本、租约偏好)很重要
特点:
- 区域特定的租约持有者模式可将写入延迟保持在约 20 ms,读取延迟保持在约 2~5 ms
- 应用程序必须确保某个键的读写操作都在同一区域进行
- DDL 和运维负担更重
- 最适合用于讲解内部机制
DDL 示例:
CREATE TABLE accounts_manual (
account_id STRING(40),
owner_id STRING(40) NOT NULL,
status STRING(20) NOT NULL,
region STRING(10) NOT NULL,
CONSTRAINT accounts_manual_pkey PRIMARY KEY (region, account_id)
);
ALTER INDEX accounts_manual_pkey
PARTITION BY LIST (region) (
PARTITION na_ne VALUES IN ('NA-NE'),
PARTITION na_mw VALUES IN ('NA-MW'),
PARTITION na_nw VALUES IN ('NA-NW')
);
ALTER PARTITION na_ne OF INDEX accounts_manual_pkey
CONFIGURE ZONE USING
num_replicas = 5,
num_voters = 5,
voter_constraints = '{+region=NA-NE: 2, +region=NA-MW: 2, +region=NA-NW: 1}',
lease_preferences = '[[+region=NA-NE]]';
C. REGIONAL BY ROW
适用场景:
- 工作负载采用主动-主动模式
- 每行数据天然归属于某个区域
- 团队希望在多个区域实现本地读写,而无需手动管理分区和可用区配置
- 目标是提供面向开发者的多区域抽象
特点:
- 所有已配置的区域都可能成为主区域或租约持有者所在区域
- 参考延迟:写入约 20ms,读取约 2–5ms(本地区域)
- 比地理分区所需的手动配置更少
- 对于区域亲和型应用数据,这是默认推荐方案
DDL 示例:
CREATE DATABASE IF NOT EXISTS example_service_rbr;
ALTER DATABASE example_service_rbr PRIMARY REGION 'NA-NE';
ALTER DATABASE example_service_rbr ADD REGION 'NA-NW';
ALTER DATABASE example_service_rbr ADD REGION 'NA-MW';
ALTER DATABASE example_service_rbr SURVIVE REGION FAILURE;
USE example_service_rbr;
CREATE TABLE accounts_rbr (
account_id STRING(40),
owner_id STRING(40) NOT NULL,
status STRING(20) NOT NULL,
region crdb_internal_region
NOT NULL
DEFAULT gateway_region()::crdb_internal_region,
CONSTRAINT accounts_rbr_pkey PRIMARY KEY (region, account_id)
) LOCALITY REGIONAL BY ROW AS region;
本地分配模式:
WITH candidate AS (
SELECT id, resource_code
FROM resource_pool
WHERE allocated_at IS NULL
AND region = gateway_region()::crdb_internal_region
ORDER BY random()
LIMIT 1
FOR UPDATE
)
UPDATE resource_pool
SET allocated_at = now()
WHERE id = (SELECT id FROM candidate);
D. GLOBAL 表
适用场景:
- 表存储的是全局/参考类数据
- 工作负载主要关注广泛的读取本地性,而不是由区域负责写入
重要限制:GLOBAL 表会优化各处的快速读取。未经官方文档确认具体产品行为时,不要将其描述为“各处均可读写”的模式。
E. 生存目标
根据写入延迟与持久性之间的权衡选择生存目标:
-- Survive any single zone failure (default, 3+ zones required):
ALTER DATABASE mydb SURVIVE ZONE FAILURE;
-- Survive an entire region going down (3+ regions required):
ALTER DATABASE mydb SURVIVE REGION FAILURE;
| 目标 | 要求 | 写入延迟 | 数据安全 |
|---|---|---|---|
| SURVIVE ZONE FAILURE | 3+ 个可用区 | 低(本地共识) | 可承受 1 个可用区中断 |
| SURVIVE REGION FAILURE | 3+ 个区域 | 较高(跨区域共识) | 可承受 1 个区域中断 |
SURVIVE REGION FAILURE 会增加写入延迟,因为 Raft 共识必须跨越多个区域,但即使整个云区域离线,也能保证零数据丢失。
模式对比
| 方面 | 常规区域模式 | 手动地理分区 | REGIONAL BY ROW | GLOBAL |
|---|---|---|---|---|
| 写入模式 | 单个主区域 | 主动-主动,按区域键划分 | 主动-主动,行亲和 | 从主区域写入 |
| 读取本地性 | 主区域本地 | 分区本地 | 行所在区域本地 | 所有区域 |
| 运维负担 | 低 | 高 | 中 | 低 |
| 配置 | 最少 | 显式分区、可用区和租约偏好 | 数据库级抽象 | 表级声明 |
| 最适用场景 | 简单的主区域应用 | 需要完全控制底层机制 | 面向开发者的多区域应用 | 参考数据 |
实时演示设置
在研讨会和技术演示中,使用 9 节点本地演示集群,让多区域本地性直观可见。
集群设置
cockroach demo \
--nodes 9 \
--no-example-database \
--insecure \
--demo-locality=\
region=NA-NE,zone=NA-NE-1:\
region=NA-NE,zone=NA-NE-2:\
region=NA-NE,zone=NA-NE-3:\
region=NA-MW,zone=NA-MW-1:\
region=NA-MW,zone=NA-MW-2:\
region=NA-MW,zone=NA-MW-3:\
region=NA-NW,zone=NA-NW-1:\
region=NA-NW,zone=NA-NW-2:\
region=NA-NW,zone=NA-NW-3
演示流程
推荐的演示顺序:
- 从手动地理分区方案开始
- 展示显式分区和可用区配置
- 运行验证查询并确认租约归属
- 切换到 REGIONAL BY ROW
- 运行 RBR 验证
- 对比运维范围
验证查询
手动分区验证:
SHOW RANGES FROM INDEX accounts_manual_pkey WITH DETAILS;
检查以下内容:
- 所有预期的分区值均已存在
- 租约持有者的本地性与分区区域相符
- 不匹配时返回 FAIL,否则返回 PASS
RBR 验证:
SHOW RANGES FROM TABLE accounts_rbr WITH DETAILS;
检查以下内容:
- 租约持有者的本地性覆盖了所有预期区域
- 不存在非预期的租约区域
演示要点
手动方案:
- 可精准控制分区、投票者、副本和租约偏好
- DDL 更多,运维负担更重
- 最适合讲解内部机制,以及理解数据库底层的工作方式
RBR 方案:
- 让应用意图始终成为关注重点
- 手动配置更少
- 更便于向应用团队讲解
- 仍基于相同的拓扑结构
跨区域延迟指南
当客户端与相关租约持有者/仲裁路径位于不同位置时,事务延迟会增加。
| 客户端位置 | 本地读写延迟 | 跨区域读写延迟 |
|---|---|---|
| 与租约持有者位于同一区域 | ~10-20ms | — |
| 位于其他区域 | — | ~50-150ms+ |
指南:
- 将对延迟敏感的服务部署在靠近其主要数据位置的地方
- 对非关键的展示/报告查询使用跟随者读取
- 有意使用多区域表的本地性和区域配置
- 不要假设“分布式”就意味着“各处延迟都相同”
输出预期
使用此技能给出的优质回答应包括:
- 推荐的模式
- 该模式为何适合此工作负载
- 应用程序必须执行的操作(路由、行亲和性、主区域假设)
- 哪些由 CockroachDB 自动管理,哪些需要手动管理
- 预期的延迟特征或本地性行为
- 用户要求的特性若非所选模式的优化目标,应发出警告
防护准则
- 不要声称常规主区域表可从所有区域实现对称的低延迟写入
- 没有文档支持时,不要声称
GLOBAL能满足所有区域低延迟写入的需求 - 比较手动地理分区与
REGIONAL BY ROW时,明确指出控制力与简易性之间的取舍 - 用户想了解内部机制时,优先先解释手动模型
- 用户想采用最佳默认应用模式时,对于区域亲和型数据,优先推荐
REGIONAL BY ROW - 所有 SQL 中的区域名称和本地性标签保持一致
- 除非明确进行比较,否则不要在同一说明中混用手动方法和抽象方法
- 始终包含验证步骤,而不只是 DDL
多区域迁移检查清单
对于从单区域 PostgreSQL/Oracle 迁移到多区域 CockroachDB 的团队:
- 使用
--locality=region=<region>,zone=<zone>部署节点 - 设置主区域:
ALTER DATABASE <db> PRIMARY REGION '<region>' - 添加区域:
ALTER DATABASE <db> ADD REGION '<region>'(每个区域都执行一次) - 设置生存目标:
ALTER DATABASE <db> SURVIVE ZONE|REGION FAILURE - 对表进行分类:GLOBAL(参考数据)、REGIONAL BY ROW(行亲和型)、REGIONAL BY TABLE(默认)
- 设置本地性:
ALTER TABLE <t> SET LOCALITY <locality> - 在 DB Console 中监控租约持有者分布
- 测试故障转移:关闭一个可用区/区域,并验证生存目标仍能满足
安全注意事项
- 多区域配置变更会影响整个集群中的数据放置
- 在生产环境部署前,先在演示或预发布集群上测试多区域配置
- 配置变更后验证租约持有者的放置情况
- 拓扑变更后,留出时间让范围重新平衡
参考资料
- CockroachDB 多区域概述
- REGIONAL BY ROW 表
- GLOBAL 表
- 跟随者读取文档
- CockroachDB 事务
- 性能最佳实践
- 跨区域延迟对事务的影响
- 使用 CockroachDB 实现查询并行化
- CockroachDB 最佳实践与反模式演示 -- 演示 10 介绍了多区域模式,并提供可运行示例