新浪微博「点赞功能」数据库如何设计的?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了新浪微博「点赞功能」数据库如何设计的?相关的知识,希望对你有一定的参考价值。

对于第一个问题,设计一个schema->(messageID,likedCount),记录每条微博的点赞数。messageID是微博的编号,likedCount是该微博的点赞人数。但是这里有两个问题需要解决,第一是并发,第二是数据量。

每条微博都有可能有很多人同时点赞,为了保证点赞人数精确就需要保证likedCount++是原子操作,这个可以由应用程序来实现,也可以用redis的事务来实现(如果redis有事务机制或者自增功能的话),但是我觉得为了性能考虑,也可以不用实现原子操作,具体原因就不展开了。

每天都上亿可能更多的微博内容产生,这样就会有上亿个新的(messageID,likedCount)生成,这样的数据量是比较大的,单机数据库比较难提供高效的服务,所以需要采取sharding的功能(有时候也叫分表分库),可能根据messageID把这些schema分散到十个或者更多的shards上(据说,sina微博有600个节点,如何三个节点组成一个shard,就有200个shards),这样每个shard处理的请求就只有原来的十分之一,从而就能提高服务的性能。

关于点赞人列表的设计,一般来说,可能想到的schema是(messageID,userID),但是这样的设计有一个小问题,就是有些大发的微博可能会得到几十万的点赞,这样就会产生几十万个条数据,这样数据有点多,读取起来可能也慢。所以可以用这样一个schema(messageID,partID,userIDs),让一个messageID对于多个userID,同时比对应太多的userID,所以加入一个新的partID,一个part存1000个userID,这样几十万个点赞,只需要存几百条数据。这样做还有一个好处,用户点击查看点赞人时的,一般都不是完全显示所有点赞人,而是一批一批显示,这样可以一次只读一条数据,就可显示一批点赞用户信息。

参考技术A

每个微博都有一个点赞数,跟微博内容是分开存储的。

数据库用了基于redis二次开发的计数器,里面有很多亮瞎的细节具体就不方便多说了,主要优化了存储效率,内存存储了最近几年的点赞数据,在达到存储极限的时候会将最旧的数据转到磁盘,如果缓存miss会读磁盘,而且只有特别老的数据才会读磁盘,所以影响不大,性能和原生的redis一样,但是同样的内存会存储更多的数据,具体有多少倒是没有算过

这个问题可以分成两部分来分析:

显示『此微博的点赞情况』,只需要显示总赞数和最近几个赞的人,数据量很小,更新频繁,不要求较高的一致性。必须缓存,可以异步反范式化保存,用Redis或别的什么NoSQL,也可用RDBMS。

检查『用户是否赞了这条微博』,这个是防止重复点赞的,要求较高的一致性。需要保存所有的点赞记录,可以用|weibo_id|user_id|的结构保存上亿条,每次只查询一条,要对weibo_id, user_id建联合索引。也可以用NoSQL,就保存weibo_id+user_id格式的key。

数据库可以这样设计,至于怎样设计缓存,就是另外一个问题了。

参考技术B

从微博几年前放出来的 slides上看,有将关注/被关注视为 『长列表』 来针对性的解决关注/被关注的扩展性问题,猜点赞/我的点赞列表该也差不多。

这类 『长列表』 场景有一定共性:

数据规模显著高于内容类数据:发微博来自用户深思熟虑的行为,而点赞、关注是无意识行为,容易产生大规模数据;

数据分布极度不均匀:大V 与小透明的数据量差异极大,前者轻松几百万赞/关注,后者零星可怜几个赞/关注,这时按后者没有性能问题的查询在前者身上容易跪惨,而这类性能问题在早期用户活动较少时不会暴露;

有反向查询的需求:比如我点赞了你的微博,你的微博下面需要列出点赞的人的列表,我也需要看到自己点过赞的微博列表;

有基数查询的需求:需要查看点赞者数量,也需要看我点赞过的数量;

有这几个问题在,早期的单表点赞/被点赞 + 反向索引的做法会很容易遭遇存储瓶颈(数据规模大)和性能瓶颈(计数类操作开销大)乃至稳定性问题(赶上无分页捞全部数据时压力山大)。

不过题主讲的 "一条微博的点赞数就可能有几十万,这个数据量对关系型数据库来说也是大到超乎想象的" 数据规模并不大,一个 shard 上突发的热点数据访问,可以通过缓存 + 读写分离 hold 住大部分问题。

更具体的设计上,结合一点自己的经验:

schema 设计上:

避免反向索引,允许分库分表:

单表多维度查询的存在使数据表难以 shard;

替代以业务层双写,或者统一的关系服务中实现双写逻辑;

业务层的数据访问上:

首先一定要缓存,乃至直接用持久性的 redis 做存储,严格避免一个 query 捞回几十万 id 的行为直接落数据库上:点赞操作发生时,务必要『更新』缓存,而非『失效』缓存;

计数类操作一定要缓存:同样,点赞操作发生时,务必先『增加』缓存中的计数,而非『失效』计数缓存;

服务架构上:

类似的『长列表』场景在社交网站中无处不在,往往也是最显容易暴露瓶颈的场景,根据问题共性,开发类似的『关系服务』统一解决扩展性问题。

以上是关于新浪微博「点赞功能」数据库如何设计的?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过python调用新浪微博的API来爬取数据

关于新浪微博缓存的功能是怎么实现的

如何使用爬虫一键批量采集新浪微博内容

Thinkphp3.2添加QQ互联和新浪微博一键登录功能

android版,请问如何关闭手机新浪微博的推送新闻

使用 swift3.0高仿新浪微博