微博类应用的架构设计与思考
2018-11-21 本文已影响16人
小盒子的技术分享
一 需求
APP中包括社交类功能,如点赞、关注、评论等,以点赞为例有如下问题&需求:
- 数据规模显著高于内容类数据:发帖子来自用户深思熟虑的行为,而点赞、关注是无意识行为,容易产生大规模数据
- 数据分布极度不均匀:大V 与普通用户的数据量差异极大,前者轻松几百万赞/关注,后者零星可怜几个赞/关注
- 有反向查询的需求:比如我点赞了你的帖子,你的帖子下面需要列出点赞的人的列表,我也需要看到自己点过赞的帖子列表;
- 有基数查询的需求:需要查看点赞者数量,也需要看我点赞过的数量;
二 现状
我们是一个新的APP,用户数从0开始,也就是基数为0,一切的量化都是从0开始的。
三 现在的设计
最开始,我们的想法很简单,以关注功能为例,先设计数据结构和功能,用mysql存储数据,数据结构非常简单和微博一样:
image.png
这样的做法优点是:
1 设计开发、实现 速度快,简单
2 数据完整落库,不会丢
缺点是:
1 数据增速快,单表数据量很快就上去了,会导致查询压力。
2 在预期内单表数据会不断上涨,要一开始就考虑拆分,否则拆分会带来逻辑、部署、运维的各种复杂度
3 查询性能会随着数据量的增加越来越低,用户体验差
4 处理复杂逻辑缓慢,如 查询用户关注列表、查询用户粉丝列表、查询用户双向关注列表、判断两个用户关系。
还有更复杂的需求:“我与他的共同关注列表”、“我关注的人里谁关注了他
如果基于上面的方案,我需要判断mysql单表的性能,理论上单表5000万以上才会性能急剧下降,有些db架构师也是这么说过。但是实际情况却不一定。 所以我的预估最多是500万就要开始做技术储备了。
**不过基于以上的分析,我们一期的设计并没有单纯采用数据库**。我们需要在DB之上加一层高速缓存,利用redis的数据结构和内存速度优势来解决我们的问题。
虽然决定采用Redis做缓存 ,但这里还有一个问题,就是redis的角色到底是什么,是cache角色,还是storage角色?分别说明一下两种角色的情况:
-
storage角色 我个人认为这是一种相对激进的做法,就是说把redis当DB用,所有数据都在内存中,当然也并不是说完全不持久化数据,Redis 作为存储,为了数据可靠性必须开启 rdb 和 aof。
然而,而这会导致业务只能使用一半的机器内存。再者,因为aof启动redis时会试图加载所有数据,不管冷热,这是不明智的,数据总有“冷”、“热”之分,冷数据都放Redis显然浪费资源。 -
cache角色,将需要缓存的数据放在redis中,仅利用redis的数据结构,不用redis持久化数据,持久化用mysql
经过我的考虑最后决定的方案是这样:
redis + mysql 异步双写 +预热缓存 当用户请求来的时候,将该缓存的数据(如计数、关系)缓存 一份进redis,异步刷一份数据到mysql,项目启动时预热部分缓存到redis中,目前的预热规则是7天内登录过的用户,规则算法有待优化。用户的大多数请求会被redis挡住,落不到DB,只有少数落到了DB上,落到DB的请求得到的数据也会加载回redis。
这样的缺点是:1 缓存预热算法有待优化 2缓存淘汰方式有待深思。
这样的优点是:1 基于redis可以方便做扩展 2 理论上在5百万级以下的记录是可以hold住。3 数据全量落库
四 未来规划
从上面的描述不难看出,我还是利用mysql做持久化,这样数据增量仍然会给单表带来压力,这样的话,就需要考虑分表,业务层也要进行相应的修改来支持。
从数据容量的规划上,目前的架构可以支持10w+用户 单表500w记录没有问题,在数据增量上来之前的这段时间,我们可以做技术和相关知识储备+调整设计+优化实现。
未来我不能考虑用户量在亿级规模,那不实现,未来我首先考虑的是一个百万级用户的规模,在这样数据规模的前提下,当前的构架显然不合适,需要做调整,我对业务的设计是:关系服务+数据存储:
1 服务层面
- 与点赞类似的 评论、转发、关注等 开发 “关系服务” 统一解决扩展性问题。
- 引用消息队列,将持久化工作流细粒度化后整合为任务。
- 服务化、接口后化,应用就好做扩展了
2 存储层面,暂时可以先用Mysql做落地方案,但要设计好分表规则,用redis抗的同时,尽量减少与DB的直接IO,复杂逻辑交给应用层处理。
未来可能采用hbase,非关系型数据库来优化存储方案。
redis的集群方案上面,如考虑到可靠性问题,会加入双写的功能。
五 总结
架构考虑的是 性能、成本、可靠性,最终是一个权衡的问题。没有最好的架构设计,只有最适合的架构设计,到什么规模什么体量用怎样的方案,我觉得,这是考验架构师的一个非常重要的点。
以上。