INCR key语法,可以将 key 中储存的数字值增一。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。最重要的是INCR是一个原子性的自增操作。非常适合用来实现计数器。
引入了Redis之后,遇到高并发和大数据量的问题解决起来就简单了——堆机器。
当然,这个方案虽然在很大程度上解决了大数据量和高并发的问题。但是,如果真的是业务量特别巨大,总不能无限制的增加通过增加机器来解决问题吧,机器就是成本啊。
关于这种问题,微博就遇到了,因为微博的点赞功能和我们的投票功能其实是类似的。明星的一条微博的点赞数可能有几十万,甚至百万以上。有人(微博计数器的设计)算过一笔帐:
假设 key 为8字节,value为 4字节,通过incr存储的话:
一个 value 通过 createStringObjectFromLongLong 创建一个robj,由于value在LONGMIN 和LONGMAX 之间,所以可以将value用 ptr指针来存储,需要占用 sizeof(robj) = 16 字节;
一个key(即微博id) 最长64位数字(Eg: 56515491),但通过 sdsdup 以字符串的形式存储,至少需要 8(struct sdshdr)+19+1 = 28字节;
为了存到Redis 的dict里面,需要一个dictEntry对象,继续 3*8 = 24字节;
放到db->dict->ht[0]->table中存储dictEntry的指针,再要 8个字节; 存储一个64位key,32位value的计数,Redis也至少需要耗费: 16 + 28 + 24 + 8 = 76 字节。
1000亿个key全内存的话,就至少需要 100G * 76 = 7.6TB 的内存了(折算76G内存机器也需要100台!)。
我们的有效数据其实是1000亿个32位 = 400GB,但是却需要了7.6T来存储,内存的有效利用率约为:400GB/7600GB = 5.3%
总的来说,Redis做为优秀的内存数据结构,接口方便,使用简单,对于小型数据量的中高访问量的计数类服务来说,是一个很不错的选择,但是对于微博计数器这种极端的应用场景,成本还是无法接受!
所以,微博的点赞功能,其实是在Redis的基础上进行了二次开发。如在数据机构优化、转发和评论数 Value的优化、key的优化、数据的持久化、一致性保证等方面做了很多事情。这里不详细介绍了,感兴趣的同学可以参考微博计数器的设计
其他
避免刷票
在创造101的投票规则中,明确规定了:请公平参与点赞,如采用违法或违反赛事规则的点赞行为,将会被收回相关点赞数并追究责任。
那么,如果我们是这个投票系统的开发,如何有效的避免刷票行为呢?
首先,我们要通过设计一个很好的计数器,能够有效的避免高并发请求带来的计数错误。因为投票时可能有很多人使用脚本等构造多条请求,试图来突破限制来多投票。
其次,还可以通过一些其他限制手段来防止恶意刷票,如限制同一IP的投票次数、限制同一帐号的投票频率等。
避免数据溢出
据说,在前段时间的MSI比赛前期,MSI的助威活动中,人气选手uzi的票数达到了网站开发人员设置的int的最大值。
以上只是个传说,我并没有去辩证他的真伪,但是这至少给我们一个提醒,在设计投票系统的时候,要充分的考虑到粉丝们的热情和实力!
持久化数据的备份
无论最终选用那种方式进行计数,数据的持久化问题都至关重要,一定要做好数据存储的容灾工作。避免由于系统问题导致数据丢失。
PS:作者并没有在工作中开发过实际的投票系统,以上总结均是基于日常工作中的积累及一些参考资料(参考链接请到原文中查看)总结得出。欢迎大家指正与讨论。
好啦,看完这篇文章之后,如果你有收获,请给我菊姐投票!!!
- MORE | 更多精彩文章 -
如果你看到了这里,说明你喜欢本文。
来源:【九爱网址导航www.fuzhukm.com】 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!