3.6 后端风云

从单库单进程承载全部请求走到缓存、路由、分片、副本、负载均衡和故障转移分层,沿状态边界诊断扩容与恢复。

学习目标

  • 能沿请求入口、缓存/路由、分片、读写副本和故障转移追踪一个键的后端路径
  • 能比较取模、 一致性 Hash、Hash Slot、负载均衡与读写分离各自解决的容量或可用性问题
  • 能在正常、边界和故障场景中回答:扩容、缓存穿透、陈旧副本或节点失效时,最早应在哪个状态边界诊断

3.6 后端风云

本页依据刘欣《码农翻身》(2018 年第 1 版)及出版社公开书目信息,独立重构 3.6 后端风云。正文、代码、图示、实验和练习都是本课程重新设计的教学材料,不复制原书正文、插图、练习答案或代码。

先想象一座城市的配送系统:门口分流车辆,附近仓库存放常用货物,地图把订单分到不同仓区,仓库有备用副本,主路堵住时还要换入口。把所有车、货和路线塞进一个仓库,起步简单,但一次扩容或故障就会让全城停摆。

本章解决的是“后端怎样在流量、数据量和节点故障同时增加时保持可用”。拆开组件不等于自动可靠:缓存会过期,路由会迁移,副本会滞后,负载均衡会把请求送到坏节点,故障转移也可能丢失最新写入。每个层次都必须写出容量、状态和恢复合同。

后端扩展链:键、角色与拓扑版本必须可追踪入口可用不等于数据正确,缓存、路由、副本和切换各有证据1请求入口探活 + 路由入口证据2缓存/路由TTL + 拓扑入口证据3选择分片键 → 槽容量边界4读写副本主 + 延迟恢复证据5故障转移角色 + 恢复恢复证据先保存拓扑、键归属、复制位点和角色,再宣布请求恢复
专属图示:把后端扩展的容量路径、状态路径和故障恢复放到同一条链。

三个会让后端扩展失真的陷阱

十三个目录节点到后端证据

3.6 后端风云

总合同是:请求入口负责路由与探活,缓存负责可回收的加速,分片/槽负责键空间归属,副本负责读取与恢复,故障转移负责角色切换。任何路径都要记录键、版本、节点、角色、复制位点和最终业务结果。

数据库老头儿

代表系统的持久事实。扩展前先区分读压力、写压力、存储容量和事务热点;数据库变慢不能只靠加缓存掩盖,否则更新和一致性问题会更晚爆发。

危机

是架构决策的触发器。诊断时把延迟、错误率、命中率、连接数、复制延迟和热点键分开看,先确定瓶颈属于计算、网络、存储还是路由。

党委扩大会议

不是增加组件清单,而是做边界审查:谁保存事实,谁可以丢失,谁负责路由,谁负责恢复,谁能宣布切换完成。每个答案都要对应监控和故障演练。

分家

让容量和故障域可以分别控制,但也引入网络、版本和一致性成本。拆分后必须给每条跨组件边定义超时、重试、幂等和降级,而不是只移动类名。

Redis

可以很快,但速度不等于持久事实或自动高可用。设计时明确数据是否可丢、持久化方式、内存淘汰、集群路由、复制延迟和故障切换证据。

余数算法

适合节点固定、实现简单的分配,但扩容代价高。实验中固定一组键,分别用 3 和 4 个节点计算归属,统计迁移比例并把缓存失效与路由变化关联起来。

一致性Hash算法

减少迁移量,但不自动提供均匀负载、复制一致性或故障恢复。需要虚拟节点、热点监控、迁移限速和失效回源策略共同配合。

Hash槽 (Hash Slot)

把“某个键去哪”变成“某个槽由谁负责”。迁移时先确认槽状态、双写/阻塞规则和客户端路由更新,不能只把节点地址替换掉。

后端扩展链:键、角色与拓扑版本必须可追踪入口可用不等于数据正确,缓存、路由、副本和切换各有证据1请求入口探活 + 路由入口证据2缓存/路由TTL + 拓扑入口证据3选择分片键 → 槽容量边界4读写副本主 + 延迟恢复证据5故障转移角色 + 恢复恢复证据先保存拓扑、键归属、复制位点和角色,再宣布请求恢复
专属图示:把后端扩展的容量路径、状态路径和故障恢复放到同一条链。

故障转移

必须包含检测、判定、切换、连接恢复和数据验证。探活误报会造成双主,切换过慢会造成不可用;复制位点和业务写入确认决定了恢复后的数据边界。

高可用的Nginx

解决的是入口可达与流量分配,不是数据库一致性。要明确健康检查是进程级还是业务级,失败重试是否会重复提交,以及代理切换时如何保留请求 ID。

高可用的Tomcat

需要和会话、连接池、线程池、发布版本一起设计。实例活着不代表依赖健康;滚动发布与故障切换要验证旧请求、重试和幂等行为。

数据库的读写分离

要让业务知道何时需要读己之写、强一致读或允许陈旧读。副本延迟超过预算时应降级到主库或返回可解释状态,不能静默展示旧事实。

最小路由与副本合同

route(key, topology) -> shard_or_slot
read(key, consistency) -> replica_with_lag_budget
write(key, version) -> primary_ack
failover(role, replication_position) -> new_primary

合同把键归属、读取一致性、写入确认和角色切换分开。真实系统还要保存拓扑版本、槽迁移状态、缓存版本、复制位点、请求 ID 和幂等键;单一故障样本不能只看最终 HTTP 状态。

五步复核一条后端请求

分步1 / 5

1. 进入代理并固定拓扑

记录请求 ID、目标服务、探活结果、拓扑版本和重试预算。基线走健康实例;边界场景让一个实例进入排空,验证新请求不会再分配给它。

后端扩展链:键、角色与拓扑版本必须可追踪入口可用不等于数据正确,缓存、路由、副本和切换各有证据1请求入口探活 + 路由入口证据2缓存/路由TTL + 拓扑入口证据3选择分片键 → 槽容量边界4读写副本主 + 延迟恢复证据5故障转移角色 + 恢复恢复证据先保存拓扑、键归属、复制位点和角色,再宣布请求恢复
专属图示:把后端扩展的容量路径、状态路径和故障恢复放到同一条链。

Lab

后端拓扑与故障转移实验

只改变拓扑或角色状态,观察键迁移、回源、复制延迟和恢复判定如何变化。

缓存命中,键落在当前槽,副本已追平

request → cache hit → slot=417 → replica lag=0 → response v12

判定

accept:路径短,版本和角色均可解释

当前样本:稳定拓扑;保存请求 ID、拓扑版本、键归属、缓存状态、复制位点和业务版本。

正常、边界与故障证据矩阵

后端证据矩阵:容量变化与数据事实分开验收正常样本看路径,边界样本看预算,故障样本看恢复观察项正常边界故障入口探活通过排空/重试误报缓存命中过期/热点击穿路由槽稳定迁移拓扑旧数据副本追平陈旧预算主失效先记录最早偏离,再判断是回源、迁移、陈旧还是角色切换
专属图示:把入口、缓存、键路由与副本恢复逐层对齐。
样本只改变的变量预期判定必存证据
正常拓扑稳定、缓存有效、副本追平路由正确,读写结果满足一致性预算拓扑版本、命中率、复制位点
边界新增节点、热点过期或副本滞后迁移/回源/读策略可解释,不雪崩迁移比例、TTL、延迟、回源数
故障代理、应用或主库节点失效有限切换后业务恢复,角色唯一首个探活失败、切换时间、业务读写

故障诊断:先找键、角色和版本

  1. 入口侧:查请求 ID、代理探活、连接排空、重试预算和实例版本;入口 200 不代表后端写入成功。
  2. 缓存侧:查键、TTL、版本、命中率、回源并发和淘汰;命中旧版本要回到失效与更新顺序。
  3. 路由侧:查取模/一致性 Hash/槽拓扑、迁移状态和客户端缓存;节点变化造成的重映射要可量化。
  4. 数据侧:查主副本角色、复制位点、读一致性预算和故障转移;恢复后必须验证业务事实而非只看进程健康。

如果扩容后大量缓存未命中,先比较拓扑映射;如果读取旧数据,查副本延迟与读己之写策略;如果切换后重复写入,查代理重试与幂等键;如果集群抖动,查探活误报、迁移并发和连接刷新。每次只改变一个状态边界并重放基线。

术语表

名词解释

本章出现的专业名词,用大白话再讲一遍。

数据库老头儿

保存持久业务事实、供其他层回源与核对的权威存储。

危机

单一后端承受容量、并发与故障压力并需要拆分职责的临界状态。

党委扩大会议

把容量、缓存、路由、副本与恢复边界放在一起审查的设计讨论。

分家

按状态与故障职责拆成可独立扩展和恢复的组件边界。

Redis

用于缓存、键值访问和分布式数据结构的技术参照服务。

余数算法

按 Hash 值除以节点数取余路由,节点变化会导致大量键迁移。

一致性Hash算法

把键和节点放入共同有序空间,减少节点变化时迁移范围的算法。

Hash槽 (Hash Slot)

把固定键空间切成槽位并分配给节点的可迁移路由单元。

故障转移

检测节点/角色失效后提升备用角色、更新路由并验证服务的过程。

高可用的Nginx

负责入口探活、流量分配、排空与切换的高可用代理边界。

高可用的Tomcat

通过多实例、会话和优雅下线提升 Java Web 服务可用性的运行边界。

数据库的读写分离

写主库、读副本以换取容量和可用性,同时承担复制延迟与一致性复杂度的方式。

练习

练习

问题 1: 节点从 3 个扩到 4 个后缓存几乎全部失效。为什么取模算法会这样?怎样降低迁移?

问题 2: 写主库成功后马上读到旧副本,应该怎样选择策略?

问题 3: 修改本页“后端拓扑与故障转移实验”,让一个节点失效后显示主库切换、缓存回源和副本延迟,并说明重置后恢复哪些状态。

资料与写作方式声明

本章以码农翻身权威目录界定学习范围,并结合正文列出的技术资料独立重写;不宣称复现原书正文,也不沿用原作表述。

原作版权归作者与出版社所有;本站原创教学结构与表述仅供学习交流。

本页小结

  • 缓存、路由、分片、副本、入口和故障转移解决不同问题。
  • 取模简单但扩容迁移大,一致性 Hash/Hash Slot 仍需迁移与热点策略。
  • 读写分离必须显式处理副本延迟和读己之写。
  • 故障切换要验证角色、连接、复制位点和业务结果。

读完后的自测问题是:扩容后大量缓存失效或主库切换后读到旧数据时,你能否用键映射、拓扑版本、复制位点和一致性预算定位最早偏离?

讨论

评论区加载中…