问题的产生:
在编写微服务点赞模块时,为防止用户重复点赞,是将用户的id组合自定义的点赞字符串组合拼接存入redis中,由redis的过期时间来保证用户在一段时间内不允许重复点赞。
对于一般的业务而言也满足了需求,尤其是用户量不是很大,但帖子更新速度尚可的网站。用户在点赞某一篇文章后,第二天会较难再刷到同一篇文章,即使刷到也不一定会再点开看。总而言之,是对点赞数不敏感的网站都可以采用这种方式。
但对于微博、QQ空间等社交依托的服务,点赞数就必须精准且严格,还要保证快速。
就无法直接使用redis这种方式来防止用户以你设置的redis过期时间为单位来刷赞。
那么如何解决问题呢?
先说解决这个问题我的思考过程:
首先考虑这个问题的性能瓶颈,网络访问是不可避免由用户发起且无法主动提升的。
那么服务器方面的瓶颈就是在IO操作上。
为了提高IO操作的效率,缓存是我们必须考虑的技术。
Cache、redis能减少部分的IO操作,因为数据可以不经过数据库,直接从缓存中取到。
但是缓存也存在容量的上限,因为缓存就占用着程序的内存空间,而我们实际的情况又是复杂的。
很多用户估计帖子就不会有评论和回复。
而热点大V用户一个人的帖子可能就会到几百万的点赞。
点赞多的评论也会多。
所以需要设计算法,对于进入缓存的数据进行一定的优化。
可以参考JVM的垃圾回收机制,设置巨型代、新生代、老生代、永久代。
把大v的数据存放到巨型代中,并且达到过100w数据的大v一旦进入过巨型代,那么设置在较长的一段时间内,都不会进入到新生代。
这里先说明,巨型代、新生代、老生代、永久代,这4个分类,前3者都是在内存中,但是在内存中的生命周期不同。永久代就存储到了磁盘中。
巨型代的生命周期会更长,虽然会随着热度在巨型代、老生代中自我转化,同时设定更高的难度防止其快速进入新生代。毕竟流量一直都在大v身上。
生命周期一到就会存入数据库中,这里我想类比Logstash来同步数据。
大量的无评论无点赞微博会进入新生代,然后在相对较短的时间完成转化,进入永久代,直接存入磁盘,不占用内存空间。
并且甚至希望能设计专门的数据库。
因为MongoDB中对于增加操作的操作方式,和普通的mysql不同,mysql需要查询,然后修改,再保存,这涉及了2次IO操作,而MongoDB提供了原生的++方式,是一次IO操作。
所以类比一下,可以设计出1次IO操作的数据库。只提供++和--,从减少IO次数的层面上来提高效率。
最后是永久代数据再被访问的问题,这时候就需要从硬盘中找到该数据(考古帖子),数据量一定会非常巨大,普通的分库估计解决不了这个问题。。。可能有更散列的hash算法能快速找到?或者通过其他的因素进行数据库分区,随着学习更多的知识,应该能有解决这部分问题的新思路。
在网上找到了一篇博客,讲到了微博点赞计数器的设计思路:
作者是:Cydu
http://blog.cydu.net/weidesign/2012/08/30/weibo-counter-service-design-1/
http://blog.cydu.net/weidesign/2012/09/09/weibo-counter-service-design-2/
感兴趣的大家可以去了解一下。