单元化
单机房有供电和机柜上限,同城三机房也有城市级能源评估天花板。火山引擎 2024 年公开的单元化实践写明:抖音、直播、电商、支付、本地生活已按 Region 做「同城容灾 + 异地多活」,生产接入数千核心微服务、超过 100 万实例。水平扩展的单位不再是再加一台机器,而是再加一个可独立承接流量的单元。
客户端按 UserID 选路
单元 · 北京
Feed / 画像 / 计数
本单元用户数据
单元 · 上海
Feed / 画像 / 计数
本单元用户数据
单元之间异步复制,同一用户不要两边同时写
单元怎么切
- 单元维度 = 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 切面 · Mesh | MQ Consumer、定时任务不经过网关,必须在框架里再算一次路由。 |
| 存储层管控 | 存储中间件 · Mesh 拦截 | 社交会跨用户读写。纠偏成本高,落地时常先审计拦截脏写。 |
跨单元业务
归属单元 1 的用户 A 评论了归属单元 2 的用户 B。通知在单元 1 发出,B 打开 App 被调度到单元 2。若评论还在同步延迟窗口里,B 看不到这条评论。社交、点赞、关注都是一个用户写另一个用户的数据,无法理想闭环。
用户A 单元1
网关
单元1 服务
复制通道
单元2 服务
用户B 单元2
评论 B 的视频
▶
写入评论并通知
▶
异步同步评论
▶
打开通知
◀
读评论
▶
复制已到:看到 / 还在窗口:暂时看不到
▶
做法是接受最终一致,对读做短时回源或会话粘滞,对写用分区主单元加异步复制,并在存储访问层拦住双单元同时写同一 Key。