基于Redis的统计UV方法

项目中经常遇到需要统计系统每天使用情况的需求,基于此总结出的几种Redis统计UV的方式.
如果统计 PV 那非常好办,给每个网页一个独立的 Redis 计数器就可以了,这样来一个请求,incrby 一次,最终就可以统计出所有的 PV 数据。但UV不同,UV统计的是用户的使用情况,同一天同一个用户多次访问网站或者接口只能计数一次.因此需要考虑去重.

  1. Set集合:说到去重,很容易就会想到set集合,方案是每一个页面(接口)设置一个独立的 set 集合来存储所有当天访问过此页面的用户 ID。当一个请求过来时,我们使用 sadd 将用户 ID 塞进去就可以了。然后通过 scard 可以取出这个集合的大小,这个数字就是这个页面的 UV 数据。
    该方案简单易懂,但是访问数据量较大时需要维护一个较大的set,占用空间较大.
  2. Bitmap位图:bitmap是一串连续的2进制数字,每一位所在的位置为偏移,方案是建立了一个bitmap,每一位标识一个用户ID。当某个用户访问我们的网页时,我们使用setbit将用户Id所在的偏移量设置为1,然后使用bitcount统计一个key中1的个数,结果即为UV数据.该方案使用存储空间较小,1亿的用户数据量存储空间大约为11.9M(100000000/810241024=11.9M).但是如果用户Id为UUID,就无法对其进行统计.
    基于Redis的统计UV方法
  3. BloomFilter(布隆过滤器):布隆过滤器是一种多哈希函数映射的快速查找算法。通常应用在一些需要快速判断某个元素是否属于集合,但是存在一定的误差,布隆过滤器不会将集合中存在的数据判定为不存在,但是会将集合中不存在的数据判定为存在,基于此可以作为去重工具使用.假设有两个hash函数,用户Id分别进行hash,映射到位图中,最开始各个位置均为0,说明userId=13的用户不存在,加入.随着用户越来越多,hash函数存在哈希碰撞,那么将不存在的用户判定为存在了.使用布隆过滤器只是去重,如果统计UV还需要一个计数器配合使用,布隆过滤器的误判率与哈希函数的个数与布隆过滤器的长度有关.说明下,redis中没有天然的bloomfilter的命令,需要使用布隆过滤器的插件.
    基于Redis的统计UV方法
  4. HyperLogLog:HyperLogLog是redis的高级数据结构,提供去重功能,但是与布隆过滤器一样存在误判率,但是误差很小,对于统计UV还是可以容忍的,命令也很简单,使用pfadd即可将用户Id假如集合中(不是set集合那样放入集合,而与位图的情况相似),使用pfcount即可统计集合里元素的个数,HyperLogLog的最大优势就是存储空间较小且固定为12K,如果上亿的用户量,与前面三种所使用的空间相比优势巨大.HyperLogLog使用简单,但是实现原理比较复杂,需要很好的概率论知识,如果有兴趣的可以自信研究一下.

注:以上命令均为Redis命令