Facebook点赞模块的设计与实现

这是一个来自Tim Yang博客中的问题:http://timyang.net/management/design-review/

需求

题目需求如下:

可以对一个对象(一条feed、文章、或者url)进行like操作
需要看到一个对象的like总数
可以看到一个对象的like用户列表,优先显示我的好友列表(social list)。
数据量:每天新增的like对象数为1千万,每秒like计数器查询量及social user list均为30万次/秒。

假设现有系统的存储结构(MySQL)为:

friends表, from_uid + to_uid 为联合主键
(from_uid bigint,
to_uid bigint,
ctime timestamp)

feed表, feed_id + like_uid 为联合主键
(feed_id bigint,
like_uid bigint,
ctime timestamp);

假设以上存储是单表结构,请问如何设计like技术方案?如何评判你的like方案的优劣?

我的实现

这个问题麻雀虽小,五脏俱全,互联网行业类似Facebook、Twitter的点赞功能的设计与实现,涉及到互联网行业对功能和质量要求的方方面面,通过对这个简单功能的架构,阐述了如何进行架构设计才能实现高性能,高可用,可伸缩,可扩展的线上功能模块。

本打算围绕Like项目写一篇架构设计文章,由于离开微博后工作比较忙,一直没有时间写,就先把当时我当时这个实现附上来,我实现的项目里面代码中有注释,并且有doc文件夹里面有些设计文档和测试文档,供大家参考。

下载此项目:MyLike

评审意见

这个项目做完之后,在组里进行了架构评审,评审的过程中,大家提出了如下的问题:

1. 找到性能瓶颈在哪?为什么别人2w memcache,而我这这么小,才9700?系统的性能瓶颈在哪呢?memcahce线程和log4j锁的问题。
2. 显示用户列表是一页一页显示吗?缓存一部分数据吗?很大的列表有多少?怎么存呢?如何还要显示登录用户的好友在前面呢?
3. 为什么要用MQ, 直接线程不是更好吗,各个方案优略?写数据量少,直接线程池推送,如果大呢,就用mq。
4. 为什么不把更新和查询放在一台机器上,这样我的更新机器就不用主备了,因为更新只有100/s,不影响查询,为啥要单独一台呢?
5. 往缓存里增加数据或者删除数据user list or count应该咋办?用inc或者cas增加,如果不在呢,则查询数据库然后缓存,如果没有则缓存0。
6. 私信一天也就有3000w条新加记录,查询10万级别,没有like练习多,微博查询是100w/s级别的。
7. 如何分库分表,数据库压力到底有多大,先按照时间,然后按照hash,动态分片?
8. 如果缓存近一个月的数据, 1亿条,有多少feed是有实效性的,有的微博时间长了也是热点,那就要有监控中心统计热点微博,在cache里面存些热点数据。
9. 如果从cache里取出来当前值,然后incr,不在cache里咋办?或者本微博没有人关注怎么办?查数据库,缓存0。
10. 内存计算要考虑到长list,平均list多大,长列表有多少,最大多大?memcache只能存4M。
11. 每个环节cpu, io,memory等等的利用率。
12. 更新count用inc或者cas更新cache?java memcache client没有cas,spy memcache有。
13. list太大如何分片缓存,分片缓存后如何更新或者删除?分片后如何优先显示当前登录的好友列表。
14. LIKE列表太大,如何分页,如何优先显示好友列表。
15. memcache down掉, 压力压倒数据库?有办法吗?需要多少机器,上万台机器?
16. down掉可以返回脏数据,也可以缓存在cookie里的数值作为当前显示?
17. memcache down掉怎么办?一定压跨数据库? 不能优化数据库的查询吗?用SSD优化?算算能不能优化mysql支持住吗?
18. 可以用megament对memcache进行HA吗?

可见群众的智慧是无穷的,尽管我在设计的过程中已经竭尽全力考虑功能和非功能质量,但是,还是忽略掉了很多重要是的点,本想把所有的这些点解决后再发布出来,由于时间有限,还是直接贴出来供大家思考。

发表评论