learntoall

单元化

单机房有供电和机柜上限,同城三机房也有城市级能源评估天花板。火山引擎 2024 年公开的单元化实践写明:抖音、直播、电商、支付、本地生活已按 Region 做「同城容灾 + 异地多活」,生产接入数千核心微服务、超过 100 万实例。水平扩展的单位不再是再加一台机器,而是再加一个可独立承接流量的单元。

客户端按 UserID 选路

单元 · 北京

Feed / 画像 / 计数
本单元用户数据

单元 · 上海

Feed / 画像 / 计数
本单元用户数据

单元之间异步复制,同一用户不要两边同时写

架构图 · 按 UserID 进入不同 Region 单元,单元间异步复制

单元怎么切

  • 单元维度 = Region。物理机房集合,而不是业务自己划逻辑单元,避免中台被不同上游调度打乱。
  • 分区维度 = UserID(多数 ToC)。同一时刻同一用户的写入只落一个单元。搜索等少数业务按 Region 分区。
  • 映射 = 表达式 + 表。常态用 Hash(UserID) % 100000 按比例切到 Set;高价值用户或灰度用 UserID→Set 映射表钉死。
  • 目标:单元内闭环。一次 Feed 的画像、召回、计数尽量不跨城。北京—上海 RTT P99 约 40ms,链路上打几跳就会把推荐预算打穿。

容灾

同城多 AZ 先抗机房故障;异地单元扛城市级故障,且异地不是冷备——常态就有真实流量。公开分享对比:同城三机房每机房预留 50% buffer;两地多机房后故障流量可摊到其余机房。存储按用户拆分后,每个单元只持有一部分数据。流量调度侧(TrafficRoute GTM 一类)按 GEO/ISP 就近;公开口径约 1 分钟感知,3–5 分钟收敛 90%+ 流量。

四层纠偏

请求带着 UserID
1 客户端选路
2 网关纠偏
3 Mesh 或框架再算一次
4 存储拦截脏写
落到正确单元
流程图 · 四层纠偏:客户端、网关、计算框架、存储依次把请求掰回正确单元

单元化失败模式不是机器不够,而是请求落到错误单元后读到旧数据,或双向同步下双写冲突。

技术落点做什么
客户端选路调度 SDK · 分单元域名第一跳按 UserID 落到归属单元。客户端升级慢,不能当作唯一正确来源。
接入层纠偏LB / API 网关插件计算分区到单元映射,把走错的请求转到正确 Region。
计算层纠偏Kitex / Hertz 切面 · MeshMQ Consumer、定时任务不经过网关,必须在框架里再算一次路由。
存储层管控存储中间件 · Mesh 拦截社交会跨用户读写。纠偏成本高,落地时常先审计拦截脏写。

跨单元业务

归属单元 1 的用户 A 评论了归属单元 2 的用户 B。通知在单元 1 发出,B 打开 App 被调度到单元 2。若评论还在同步延迟窗口里,B 看不到这条评论。社交、点赞、关注都是一个用户写另一个用户的数据,无法理想闭环。

用户A 单元1
网关
单元1 服务
复制通道
单元2 服务
用户B 单元2

评论 B 的视频

写入评论并通知

异步同步评论

打开通知

读评论

复制已到:看到 / 还在窗口:暂时看不到

时序图 · A 评论 B 的视频,B 可能因为复制延迟暂时看不到

做法是接受最终一致,对读做短时回源或会话粘滞,对写用分区主单元加异步复制,并在存储访问层拦住双单元同时写同一 Key。