访问场景上面题目是访问微博的主要应用场景,用户在一般情况下,主要用户查看自己收到的最新的微博,以及访问某个特定用户 profile 的所有微博。
访问特征
题目不需要考虑的点
此题主要是存储层的设计,因此不需要考虑缓存层设计。
由于微博是异步写入的,在某种程度可以起到错峰作用,所以作业暂时不需要考虑写入的峰值。 不需要考虑 id 如何产生,假定系统已经有发号服务。 不需要考虑用户收到的微博怎么聚合,那个由服务层来完成。
设计需要考虑的点Scale-out 扩展性
Cost 成本
High availability 高可用,以及 Reliability 可靠性 – 复制
Sharding 策略Shard 常用策略有
Re-Sharding 拆分设计
容量规划
预规划: 容纳未来一段时间的数据
2 的指数倍: shard 数量变更简单
Tradeoff
案例精选案例一:使用 user id range 作为分片 ( by 张轲)
案例二:使用 user id hash 作为分片 案例三 :by 张亮
历史数据 每半年根据日期分库,如:2015.01 - 2015.06 为一个库。每天增加 1 亿数据,半年 180 亿,约为 0.72T 数据,可以保留在 1T 的磁盘中。 根据 uid 取模分库(表),便于查询和分散数据。
当前 n 日数据 暂定 n 为 10,存储 10 亿数据。 根据 uid + 权重的 hash 算法分库。权重可以根据每个 uid 的微博 id 数量,粉丝数等指标离线计算。 为了应对突然发生的事件导致访问量激增,需要考虑2级甚至3级分片,而不宜直接做re-sharding导致数据迁移。多级分片可考虑读取一个标记,放在zk中。根据标记确定分片的hash算法加入小时等维度。
其中 hash 算法需保证: 同一 uid 需落在一个库。 权重接近的用户尽量均匀的落在不同库。
查询索引 增加发帖索引字段,记录每个用户的每个帖子的索引。 增加发帖总数统计表,以用户为维度,每个用户发一次贴则发帖总数++ 增加二级索引表,记录每个用户,每次分片库的发帖索引。如:uid 1的用户,在 2015 年第一帖是该用户发帖的总数的第 10 贴,2015 年最后一贴是该用户发帖总数的第 50 贴。 分页查询使用二级索引表,先查到该查哪个真实库(可能是多个),再到真实库中获取数据。
总结 通过灵活的运用时间维度分片,免去因uid分片数量不足导致的大规模迁移,使用外部 flag 灵活的控制分片策略。而且用时间维度分片更易做到冷热分离。 分片逻辑可以灵活到,zk中记录时间段,某个时间段内,按月分,某个时间段,按年分,之类。 通过离线计算权重的方式均匀分散数据访问。权重周期性调整,对于调整权重的用户,需要重点考虑当前n日数据的数据迁移方案。但由于调整权重的用户属于少量,所以迁移应该数据变动较小。历史数据不需权重概念,无需数据迁移。 查询使用二级索引。使用修改 btree 结构去掉二级索引能有效减少数据量,但实现难度较大,可以在之后的局部优化中实现,对总体数据库结构影响不大。 将前 n 日数据和当天数据整合在一起,之前对微博的场景理解不深,以为有首屏显示这样的概念。
|