cockroachdb的leaseholder不会自动跨locality迁移,仅在副本健康且raft leader可达时做最小代价切换;需显式配置zone constraints、启用lease_preferences并确保locality参数严格一致。

leaseholder 为什么总在同一个节点上不动
leaseholder 不会自动跨 locality 迁移,哪怕你设置了 locality,CockroachDB 默认只在 range 副本健康、raft leader 可达的前提下做最小代价的 leaseholder 切换——它不主动“优化”,只被动响应故障或租约过期。
常见错误现象:SHOW RANGES 显示 leaseholder 长期卡在 us-east-1 节点,即使 us-west-2 有同副本且延迟更低;cockroach node status 显示所有节点都 healthy,但 lease 仍不漂移。
- 确认是否启用了
--locality启动参数(每个节点必须带,且 key/value 要一致,比如--locality=region=us-east,datacenter=dc1) - 检查
kv.raft_leader_lease_renewal_interval和kv.raft_leader_lease_expiration_interval的值,太长(默认 9s/12s)会让 lease 持续更久,掩盖局部延迟问题 - 用
SELECT * FROM [SHOW RANGES WITH DETAILS] WHERE table_name = 'your_table'查看lease_holder和replicas字段,确认目标 locality 是否真有副本(不是只有 learner)
range 副本没按 locality 分布,add replica 失败
副本分布是异步触发的,依赖 rebalancer 工作,而 rebalancer 默认只在集群负载低、空间差异 >5%、且目标节点满足 locality 约束时才行动——它不会立刻响应你刚加的节点。
使用场景:你新增了 --locality=region=eu-central 的节点,想让某个表的 range 快速在欧洲落地副本,但 ALTER TABLE … CONFIGURE ZONE 后半天没变化。
- 手动触发:
cockroach sql -e "SELECT crdb_internal.force_replication_scan()"(仅限 v22.2+,v21.x 用cockroach debug zip后查日志确认 scan 是否运行) - zone config 必须显式指定
constraints,例如:ALTER TABLE t CONFIGURE ZONE USING constraints='[+region=eu-central]',不能只靠启动时的--locality - 注意约束语法:
[+region=us-east]表示“至少一个副本在此 region”,[+region=us-east, +region=us-west]才能保证跨 region;单个[+region=us-west]可能导致无法满足(若当前无副本在该 region)
leaseholder 在跨 region 请求中明显变慢
当 leaseholder 和客户端不在同一 locality,每次写请求都要跨 region 走 raft log 复制 + lease renewal round-trip,延迟直接叠加两段公网 RTT,不是简单“慢一点”而是阶跃式升高。
性能影响:即使你配置了 locality=region=us-west 给客户端节点,CockroachDB 也不会把 lease 自动切过去——它只认节点自身的 --locality,不感知 client 连接来源。
- 强制切换 leaseholder:用
cockroach sql -e "SELECT crdb_internal.force_leadership_transfer('your_table', 1)"(v22.2+),其中 1 是 target store_id,需先从SHOW RANGES查出对应节点的 store_id - 避免依赖自动策略:对延迟敏感的表,用 zone config 锁定
lease_preferences,例如:lease_preferences='[[+region=us-west]]'(注意双括号语法) - 确认
kv.range_lease_preferences.enabled集群设置为 true(默认 true,但某些私有部署可能关掉)
locality key 写错导致副本拒绝加入
CockroachDB 对 locality key 是严格字符串匹配的,region=us-west 和 region=us-west-1 被视为两个完全无关的 locality,rebalancer 不会把前者副本迁去后者,哪怕它们物理上是同一个机房。
容易踩的坑:运维脚本里用不同格式生成 locality(有的带 AZ 后缀,有的不带),或者升级时节点重启漏传 --locality,导致新节点 locality 为空,副本拒绝调度过去。
- 检查所有节点启动命令:必须含
--locality,且 key 名统一(推荐用region/datacenter/rack三级,避免自定义字段如az或zone) - 用
SELECT * FROM crdb_internal.gossip_liveness查每节点上报的 locality 字段,确认无空值、无拼写差异 - 副本数不足时,
ADD REPLICA报错unable to find a store matching constraints,大概率是 locality key 不一致,不是磁盘满或节点 down
locality 不是标签,是调度契约;写错一个字符,整个分布逻辑就失效。最麻烦的不是配不上去,而是配错了还看起来“正常运行”。










