知识卡片
用时间维度分片实现冷热分离,免去大规模数据迁移
内容
微博Feed存储案例给出了一套超越单一分片策略的组合方案:历史数据和当前近期数据使用完全不同的分片逻辑,而不是所有数据用同一套分片规则一以贯之。历史数据按半年为周期分库(比如2015年1月至6月为一个库),库内再按UID取模分表,这样每个历史库的数据规模是可预估的(每天新增1亿条,半年约180亿条,约0.72T,可以放进1T磁盘),而且历史数据一旦写入基本不再变化,不存在后续因为访问模式变化而需要重新分片迁移的问题。当前n日(近期)数据则采用UID加权重的Hash算法分库,权重根据每个用户的微博数量、粉丝数等指标离线计算得出,用来保证不同活跃度的用户能被更均匀地分散到不同库,避免头部大V用户的数据把某个分片压垮。这套方案最关键的巧思在于应对突发事件导致的访问量激增:不是等真出现热点事件、某个分片扛不住了才临时做re-sharding(这意味着现场做大规模数据迁移,风险和代价都很高),而是提前设计好二到三级分片,通过一个可以动态调整的外部标记(flag,可以存在ZooKeeper里)去控制分片策略要不要引入更细的时间维度(比如按小时再拆分),需要应对突发流量时只需要修改这个标记,不需要真的搬迁数据。这种”预先埋好多级分片开关、按需切换而非事后被动迁移”的思路,是应对流量剧烈波动场景的一个通用架构模式:与其在容量规划时赌一个固定的分片粒度、等出问题了再手忙脚乱地重新分片,不如提前设计好可以动态切换粒度的机制,把”要不要更细粒度分片”变成一个配置开关而不是一次数据迁移工程。
结构图:
flowchart TB
subgraph 历史数据["历史数据(超过n日)"]
H1["按半年周期分库\n(如2015年1-6月一个库)"]
H2["库内按UID取模分表"]
H1 --> H2
H3["数据写入后基本不变\n无需权重、无需迁移"]
H2 --> H3
end
subgraph 近期数据["当前n日数据"]
N1["按UID+权重Hash分库"]
N2["权重=离线计算的\n微博数/粉丝数等活跃度指标"]
N2 --> N1
N3{"是否触发突发流量?"}
N1 --> N3
N3 -->|"否"| N4["维持当前分片粒度"]
N3 -->|"是"| N5["读取ZK中的flag标记\n动态启用小时级等更细分片"]
N5 -.->|"无需数据迁移\n仅切换路由逻辑"| N4
end
近期数据 -->|"超过n日后\n数据下沉"| 历史数据
参考来源
- 位置:《高可用架构(第1卷)》第2章《高可用架构原理与分布式实践》"2.9 微博分布式存储考试题:案例讲解及作业精选"节,"2.9.4 案例精选"(源文件:_epub-src/OEBPS/Text/Chapter2_9_5.xhtml)
- 结论依据:原文说明历史数据"每半年根据日期分库……根据UID取模分库(表)",当前n日数据"根据UID+权重的Hash算法分库……为了应对因突发事件导致的访问量激增,需要考虑2级甚至3级分片,不宜直接做re-sharding 导致数据迁移……根据标记确定分片的Hash算法加入小时等维度",以及总结"通过灵活的运用时间维度分片,免去因UID分片数量不足导致的大规模迁移,使用外部flag灵活地控制分片策略",共同支撑本卡片结论与结构图。
- 原始内容:每半年根据日期分库,如2015年1月—2015年6月为一个库……为了应对因突发事件导致的访问量激增,需要考虑2级甚至3级分片,不宜直接做re-sharding 导致数据迁移……通过灵活的运用时间维度分片,免去因UID分片数量不足导致的大规模迁移,使用外部flag灵活地控制分片策略。