使用Redis HyperLogLog统计UV浏览用户数

在开发中,经常遇到要统计某个页面的访问用户数UV。我们很容易想到使用Redis Set来统计,当用户数不多的时候确实可以,本人开发的项目中要统计一个月面一个月用户的访问数量,月活跃用户数量在千万级别以上,如果用Set即使使用Hash打散存储key也需要700-800MB的redis内存,这明显很浪费.这种场景中使用HyperLogLog进行去重统计是非常合适的.

HyperLogLog算法是一种非常巧妙的近似统计海量去重元素数量的算法。它内部维护了 16384 个桶(bucket)来记录各自桶的元素数量。当一个元素到来时,它会散列到其中一个桶,以一定的概率影响这个桶的计数值。因为是概率算法,所以单个桶的计数值并不准确,但是将所有的桶计数值进行调合均值累加起来,结果就会非常接近真实的计数值。

HyperLogLog只有三种种命令格式
pfadd 添加指定元素到 HyperLogLog 中。
pfcount 返回给定 HyperLogLog 的基数估算值。
pfmerge 将多个 HyperLogLog 合并为一个 HyperLogLog
注意并不能判断元素是否存在。

pfcount的是基于概率统计论的,有一定的误差,在0.81%左右。但是在UV统计中已经足够了。

下面往HyperLogLog 增加数据,增加数据,统计到数据不一致时停止

import redis

HOST = '127.0.0.1'
PORT = '6379'
PASSWORD = ''

pool = redis.ConnectionPool(host=HOST, port=PORT, password=PASSWORD, max_connections=1024)
conn = redis.Redis(connection_pool=pool)
for i in range(1000):
    conn.pfadd("codeHole","1000%d" %i)
    total = conn.pfcount("codeHole")
    if total != i+1:
        print("total:%d real:%d" % (total,i+1))
        break
conn.delete("codeHole")
conn.close()

输出: total:104 real:105

将测试数据增加到10000看看统计结果

import redis

HOST = '127.0.0.1'
PORT = '6379'
PASSWORD = ''

pool = redis.ConnectionPool(host=HOST, port=PORT, password=PASSWORD, max_connections=1024)
conn = redis.Redis(connection_pool=pool)
for i in range(10000):
    conn.pfadd("codeHole","1000%d" %i)
total = conn.pfcount("codeHole")
print(total)
conn.delete("codeHole")
conn.close()

输出9921

参考资料:《Redis深度历险:核心原理与应用实践》
Redis HyperLogLog 内部数据结构分析

你可能感兴趣的:(Redis,python)