点赞功能是目前APP开发的基本功能。今天我们就来说说点赞、评论、收藏等场景的db数据库设计问题。1、先看场景需求:显示点赞数,判断用户是否点赞,用于去重。必须判断显示个人点赞列表。一般在用户中心展示文章点赞列表。我们来看今日头条和微博的例子,两者都是顶级流量,然后端必然有复杂的架构,今天只讲流行的方案。2.1mysql解决方案mysql解决方案,随着nosql的普及,大数据持续火热,但是mysql仍然不可替代,对于大多数中小型项目,数据量在千万级以下,完全可以使用mysql分表+缓存胜任,稳定性是其他解决方案无法比拟的:createtablepost{post_idint(11)NOTNULLAUTO_INCREMENT,...star_numint(11)COMMENT'点赞数'}--usertablecreatetableuser{user_idint(11)NOTNULLAUTO_INCREMENT,......star_numint(11)COMMENT'点赞数'}--liketablecreatetablestar{idint(11)NOTNULLAUTO_INCREMENT,post_id,user_id,......}常用查询:查询用户点赞数Selectpost_idfromstar其中user_id=?查询喜欢文章的用户selectuser_idfromstarwherepost_id=?点赞数可以通过定时和异步统计的方式更新到post表和user表中。当数据量不大时,这种设计基本可以满足需求。缺点:数据量大时,一张表查询压力大,需要分表,不管是用post_id还是user_id来hash表。如果有冲突的需求,唯一的办法就是让两张表冗余。这会增加存储空间、维护工作量,并且可能存在一致性问题。2.2Redis解决方案当数据量达到亿级时,就需要经过缓存。因为点赞这个动作非常随机,很多人看到拇指就想点击,所以数据量迅速增加。数据规模增大后,mysql的读写压力很大。这时候就要考虑memcache和redis来做存储或者缓存。为什么一般都选择redis?redis作为流行的nosql,数据类型丰富,可以适应多种场景的需求。使用redis有两个目的,一个是存储,一个是纯缓存,需要+mysql一起。纯缓存是先从mysql往redis中写入数据,用户先读取缓存,miss之后再拉取mysql,同时同步缓存。在大多数场景下,两者是同时使用的,并不冲突。下面说一下redis作为存储的解决方案:场景a:在点赞的地方显示点赞数,只显示点赞数,可以区分用户是否点赞过。一般来说,用户并不关心这个列表。在这种情况下,只需要一个数字。可以的,量比较大的时候一般显示为“7k”和“10W”。以文章id为key//以文章id=888为例127.0.0.1:6379[2]>setstar:tid:888898//设置点赞数OK127.0.0.1:6379[2]>incrstar:tid:888//实现自增个数(整数)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)3127.0.0.1:6379[2]>sismemberstar:list:tid:888456//判断是否点赞(integer)1个点赞的地方,如果已经被点赞,则显示为红色,否则为黑白显示,今日头条不是地方可以看到点赞列表,点开微博,详情页可以看到点赞列表,但是不会分页显示最近的几十个。如下图,我选了一个热点,粉丝多的“猪猪”,可能有人会觉得没人关心点赞列表,存储会浪费很多资源,还不如不存!但是,此数据是强制性的。两点:去重。点赞数可以不准确,但去重一定要准确。另一个社交产品需要记录用户行为的点点滴滴,这对于后续的用户行为分析和数据挖掘是有意义的。上面用string存储的用户点赞数,除了用string存储,也可以用hash存储。文章id分块,每100个存储一个hash,分别存储在hash表中。每篇文章的id是hash的key。该值存储喜欢它的用户id。如果喜欢的用户比较多,为了避免id过多带来的性能问题,可以单独列出来,存储在sortedset结构中。毕竟,只有几个热点。该方案的优缺点与hash相比:使用较少的全局键,节省内存空间;但同时也带来了如何根据文章id路由到对应hash的问题?在散列或集合中查找用户ID?存在不确定性。虽然使用散列可以节省空间,但会增加复杂性。如何选择取决于个人需求。除此之外,你还有别的方法吗?3、数据一致性当使用redis作为存储时,一定要做好数据持久化,必须开启rdb和aof,会导致业务只用到一半的机器内存,所以需要监控容量和扩容及时的能力。另外,只要有数据副本,就会有一致性问题,这是另一个很重要的话题。以后有时间再详细说吧!写在最后:把问题写清楚真的不是一件容易的事!前几天写的一篇文章,得到了很多同行的热烈回复。很荣幸能与众多同行交流!对于工程问题,没有标准的解决方案,一千个人有一千种解决方案,只有你自己知道哪一个最适合你!期待你更好的想法和方法。
