5.2 集群与高可用:因果一致性与读写路由


文档摘要

5.2 集群与高可用:因果一致性与读写路由 本节摘要:单机的天花板有两个:读写吞吐与硬件故障。Neo4j 的因果集群用"单主写 + 多从读 + 因果一致性"回答两者:写永远落在主库,读按路由分散到从库,书签机制保证"读到自己的写入"。本节拆解角色分工、路由协议、故障转移的表现,以及"什么时候真的需要集群"的冷静判断。 4.1 节埋了一个伏笔:书签机制为什么只在集群上才显出价值。本节把它接到底层数据流上。 一、角色分工:单主写,多从读 因果集群(Causal Cluster)的核心设计是只有一个主库(System)承担写,其余从库(Read Replica)异步复制并扩展读: 为什么写要收敛到单主?因为多主写会立刻撞上"同一条关系被两个主同时改"的合并难题。

5.2 集群与高可用:因果一致性与读写路由

本节摘要:单机的天花板有两个:读写吞吐与硬件故障。Neo4j 的因果集群用"单主写 + 多从读 + 因果一致性"回答两者:写永远落在主库,读按路由分散到从库,书签机制保证"读到自己的写入"。本节拆解角色分工、路由协议、故障转移的表现,以及"什么时候真的需要集群"的冷静判断。

4.1 节埋了一个伏笔:书签机制为什么只在集群上才显出价值。本节把它接到底层数据流上。

一、角色分工:单主写,多从读

因果集群(Causal Cluster)的核心设计是只有一个主库(System)承担写,其余从库(Read Replica)异步复制并扩展读:

集群拓扑(典型三核 + 两副本): core-1(主) ←── 选举与复制(Raft) ──→ core-2、core-3 │ 异步事务日志流 ├──→ replica-1(只读) └──→ replica-2(只读) 写请求:任意入口进来,最终都路由到当前主库 读请求:按负载均衡散到各从库(或主库)

为什么写要收敛到单主?因为多主写会立刻撞上"同一条关系被两个主同时改"的合并难题。单主 + Raft 复制把一致性换算成了多数派确认:写事务在多数核成员落盘后才算提交——代价是写吞吐的上限就是主库的上限。

二、因果一致性:书签的底层含义

"因果"指的是事件之间的先后关系:你的写入是因,紧随其后的读取是果,系统承诺果不见到因就不算发生。机制上就是 4.1 的书签:

时间线: t1 客户端写入(主库提交) → 服务器返回书签 B7 t2 客户端带 B7 发起读 → 驱动检查:哪个实例的复制进度已越过 B7? → 只有越过的实例才有资格服务这次读 → 可能是主库,可能是已追上的从库

不带书签的读呢?驱动按负载均衡随便挑一台——你可能读到三秒前的数据。这在"用户刚改完头像,刷新却看到旧头像"的场景里就是工单。要因果就传书签,要吞吐就裸读,两个都想要就分级:写后立刻读的路径传书签,普通浏览页裸读。

图:书签如何约束读路由

图:书签如何约束读路由

三、故障转移:应用侧会看到什么

主库宕机时,核成员重新选举(秒级)。应用侧的表现不是"全部报错",而是一小段时间内的可重试错误:

故障转移时间线: t0 主库失联 t0+1s 核成员选举完成,新主产生 └─ 期间写入收到 TransientError(会话过期/无可用主库) t0+2s 驱动刷新路由表,重试自动命中新主 t0+3s 一切恢复 —— 前提:写入都在托管事务里(4.1 的重试纪律)

这正是 3.2 与 4.1 反复强调"事务短小 + 重试幂等"的最后一层理由:故障转移的秒级抖动,靠应用层的重试机制吸收。任何"事务里做外部调用"(发邮件、调第三方接口)的写法,都会让这段抖动变成事故。

四、冷静判断:你真的需要集群吗

集群引入运维复杂度与授权成本,先过四道检验再决定:

检验项 单机够用 考虑集群
读吞吐 单机扛得住 读 QPS 明显超出单机
数据量 页缓存装得下 装不下且无法裁剪
可用性要求 分钟级可接受 秒级故障转移是刚需
写吞吐 写入洪峰可控 注意:集群不提升写吞吐

最后一行值得强调:因果集群不是写扩展方案——写永远收敛单主。写瓶颈的正确出路是分库(按业务域拆多个集群)或写入批优化,不是加从库。

五、从库读的多与少:路由策略怎么配

驱动侧的读路由有讲究,默认策略不是唯一选项:

neo4j:// 协议下的读写路由: 写会话 → 主库 读会话 → 从库(默认负载均衡) 想读主库?neo4j:// 协议 + access mode 配置,或直接 bolt:// 指向主库

什么时候故意读主库?两类场景:写后立刻读且懒得传书签的简化路径;从库复制明显滞后但业务要求"最新数据"的查询。代价是把读压力重新压回主库——所以它应当是例外而非默认。

六、监控集群健康的三个信号

集群值班比单机多看三样东西:

信号 健康表现 异常动作
复制延迟 秒级以内 查网络与从库磁盘 IO
选举频率 长期为零 频繁选举说明核成员不稳,查心跳配置
路由表一致性 驱动无"会话过期"告警 查路由协议与集群地址配置

复制延迟直接决定裸读从库的数据新鲜度,它是 5.2 开头那张因果图的"时间刻度"。延迟飙高的第一嫌疑人是批量导入——大批写数据时,从库追日志会明显吃力,这属于预期行为,导入窗口内避免强一致读即可。

七、FAQ

问:从库能写吗?
不能。写请求会被路由协议送回主库。别试图在从库上跑写入——它只读,这是设计而非缺陷。

问:核成员数量怎么定?
奇数(3 或 5)。Raft 多数派要求下,3 核容忍 1 台故障,5 核容忍 2 台。核成员越多写确认越慢——多数核成员是"可用性保险",不是"写扩展手段"。

八、单机到集群:迁移实操要点

从单机迁到集群,应用代码几乎不用改(这就是驱动抽象的红利),但要检查四件事:

1. 连接串换成 neo4j:// 协议 + 全部核成员地址 (驱动自动发现路由,别只给一个地址) 2. 写事务全部走托管事务(execute_write)—— 故障转移的重试吸收依赖它 3. 写后读的路径补书签——4.1 的代码直接复用 4. 长事务排查:SHOW TRANSACTIONS 找出超长会话, 集群上长事务的代价被多数派确认放大

第 2 条是迁移质量的分水岭:单机上"从不重试也没事"的侥幸写法,上集群后第一次主库切换就会现形。迁移前先把单机环境的重试纪律补齐,切换那天才会平静。

问:从库挂了会怎样?
读流量被驱动重新均衡到其余实例,写路径完全不受影响——从库是"可随时替换的读扩展",这也是"多从读"设计的工程意义所在。

本节要点回顾

  • 因果集群 = 单主写(Raft 多数派)+ 多从读(异步复制)
  • 书签机制:读请求只路由到复制进度越过书签的实例,因果一致;
  • 故障转移秒级完成,靠应用层托管事务的重试吸收抖动;
  • 集群不提升写吞吐——写瓶颈拆业务域,不加从库;
  • 四道检验过了再上集群,别为虚荣心买单。

内核与部署讲完了。图攒多了之后干什么?下一节请出图算法。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U