Redis实现唯一计数的3种方法分享
转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/121.html?1455855118
唯一计数是网站系统中十分常见的一个功能特性,例如网站需要统计每天访问的人数uniquevisitor(也就是UV)。计数问题很常见,但解决起来可能十分复杂:一是需要计数的量可能很大,比如大型的站点每天有数百万的人访问,数据量相当大;二是通常还希望扩展计数的维度,比如除了需要每天的UV,还想知道每周或每月的UV,这样导致计算十分复杂。
在关系数据库存储的系统里,实现唯一计数的方法就是selectcount(distinct<item_id>),它十分简单,但是如果数据量很大,这个语句执行是很慢的。用关系数据库另外一个问题是插入数据性能也不高。
Redis解决这类计数问题得心应手,相比关系数据库速度更快,消耗资源更少,甚至提供了3种不同的方法。
1.基于set
Redis的set用于保存唯一的数据集合,通过它可以快速判断某一个元素是否存在于集合中,也可以快速计算某一个集合的元素个数,另外和可以合并集合到一个新的集合中。涉及的命令如下:
代码如下:
SISMEMBERkeymember#判断member是否存在
SADDkeymember#往集合中加入member
SCARDkey#获取集合元素个数
基于set的方法简单有效,计数精确,适用面广,易于理解,它的缺点是消耗资源比较大(当然比起关系数据库是少很多的),如果元素个数很大(比如上亿的计数),消耗内存很恐怖。
2.基于bit
Redis的bit可以用于实现比set内存高度压缩的计数,它通过一个bit1或0来存储某个元素是否存在信息。例如网站唯一访客计数,可以把user_id作为bit的偏移量offset,设置为1表示有访问,使用1MB的空间就可以存放800多万用户的一天访问计数情况。涉及的命令如下:#p#分页标题#e#
代码如下:
SETBITkeyoffsetvalue#设置位信息
GETBITkeyoffset#获取位信息
BITCOUNTkey[startend]#计数
BITOPoperationdestkeykey[key...]#位图合并
基于bit的方法比起set空间消耗小得多,但是它要求元素能否简单映射为位偏移,适用面窄了不少,另外它消耗的空间取决于最大偏移量,和计数值无关,如果最大偏移量很大,消耗内存也相当可观。
3.基于HyperLogLog
实现超大数据量精确的唯一计数都是比较困难的,但是如果只是近似的话,计算科学里有很多高效的算法,其中HyperLogLogCounting就是其中非常著名的算法,它可以仅仅使用12k左右的内存,实现上亿的唯一计数,而且误差控制在百分之一左右。涉及的命令如下:
代码如下:
PFADDkeyelement[element...]#加入元素
PFCOUNTkey[key...]#计数
这种计数方法真的很神奇,我也没有彻底弄明白,有兴趣可以深入研究相关文章。
redis提供的这三种唯一计数方式各有优劣,可以充分满足不同情况下的计数