点赞功能是目前app开发基本的功能,明天我们就来说说点赞、评论、收藏等这种场景的db数据库设计问题。
1、我们先来瞧瞧场景的需求:
我们先看一下头条和微博的事例
这两个都是具有顶尖流量的,前端肯定有复杂的构架,我们明天只谈大众化的方案。
2.1mysql方案
mysql方案,随着nosql的流行,大数据的持续热点,并且mysql依然不可取代,对于大多数的中小项目,高于千万级的数据量,采用mysql分表+cache,是完全可以胜任的,但是稳定性是其他方案无可比拟的:
--文章表
createtablepost{
post_idint(11)NOTNULLAUTO_INCREMENT,
......
star_numint(11)COMMENT'点赞数目'
--用户表
createtableuser{
user_idint(11)NOTNULLAUTO_INCREMENT,
......
star_numint(11)COMMENT'点赞数目'
--点赞表
createtablestar{
idint(11)NOTNULLAUTO_INCREMENT,
post_id,
user_id,
......
常用的查询:
查询用户点赞过的文章selectpost_idfromstarwhereuser_id=?
查询文章的点赞用户selectuser_idfromstarwherepost_id=?
点赞数目可以通过定时异步统计更新到post和user表中。
数据量不大的时侯,这些设计基本可以满足需求了,
缺点:
数据量大时,一张表在查询时压力巨大,须要分表快手双击点赞是什么功能,而不论用post_id还是user_id来hash分表都与我们的需求有冲突,惟一的办法就是做两个表冗余。这降低了储存空间和维护工作量,还可能有一致性问题。
2.2redis方案
当数据量达到上亿的量,上cache是必经的阶段,QQ帐号出售平台因为点赞这些动作很随便,好多人见到大手指就想点,所以数据量下降很快,数据规模上来后,对mysql读写都有很大的压力,这时就要考虑memcache、redis进行储存或cache。
为何通常都选择redis,redis作为流行的nosql,有着丰富的数据类型,可以适应多个场景的需求。
采用redis有两种用途,一种是storage,一种是纯cache,须要+mysql一起。纯cache就是把数据从mysql先写入redis,用户先读cache,miss后再拉取MySQL,同时cache做同步。
多数场景两者是同时使用的,并不冲突。
下边说下redis作为storage的方案:
场景a:显示点赞数目
在点赞的地方,只是显示一个点赞数目,能分辨用户是否点赞过,通常用户不关心这个列表,这个场景只要一个数字就可以了,当数目比较大时,通常显示为"7k","10W"这样。
以文章id为key
//以文章id=888为例
127.0.0.1:6379[2]>setstar:tid:888898//设置点赞数目
OK
127.0.0.1:6379[2]>incrstar:tid:888//实现数目自增(integer)
899
场景b:点赞去重,防止重复点赞
要实现这个需求,必须有文章点赞的uid列表快手双击点赞是什么功能,以uid为key场景c:通常在用户中心,可以看见用户自己的点赞列表
这个需求可以使用场景b的数据来实现。
场景d:文章的点赞列表,类似场景b,以文章id为key
//以文章id=888为例
127.0.0.1:6379[2]>saddstar:list:tid:888123456789//点赞uid列表(integer)
127.0.0.1:6379[2]>sismemberstar:list:tid:888456//判定是否点赞(integer)
点赞的地方,假若点赞过显示绿色,没有则显示黑褐色,
明日头条是没有地方可以见到点赞列表的,而微博点进去,详情页可以看见点赞列表,并且只会显示近来的几十条,没有分页显示。
如右图,我选了一条热点,拥有诸多粉丝的“猪猪”
可能有人认为,点赞列表没人关心,储存又会浪费大量资源,不如不存!并且,这个数据是必需要有的。两点:
里面使用string储存的用户点赞数目,不仅string,还可以用hash来储存,对文章id分块,每100个存到一个hash,分别存入hashtable,每位文章id为hash的一个key,value储存点赞的用户id,假若点赞用户好多,防止id过多形成性能问题,可以单列下来,用sortedset结构保存,热点的其实是少数。
方案异同点比对
hash:使用了更少的全局key,节约了显存空间;并且也带来了问题
怎么按照文章id路由到对应的hash?
查找一个用户id是在hash还是set?存在不确定性
使用hash其实节约了空间,但降低了复杂度,怎么选择就看个人需求了。
除此之外,你还有其他的方式吗?
3、数据一致性
redis作为storage使用时,一定要做好数据的持久化,必须开启rdb和aof,这会造成业务只能使用一半的机器显存,所以要做好容量的监控,及时扩容。
另外只要有数据copy,都会有一致性问题,这就是另外一个很重要的话题了。之后有时间再细聊吧!
-End-