美文网首页
6.【Redis系列】Redis的高级应用-HyperLogLo

6.【Redis系列】Redis的高级应用-HyperLogLo

作者: 773eeb0e0c48 | 来源:发表于2019-03-09 08:53 被阅读0次

    老规矩还是先假设一个场景:比如京东的商品详情页,如果需要你来统计每天的UV数据,你会如何实现?

    如果是PV就好办了,直接给每个网页增加一个计时器,每个网页增加一个日期,这样一进来incrby一次,最终可以计算出每天的统计所有的PV数据。

    但是UV就不一样了,每一个用户进来多次每天也只能算一个UV。无论是登录用户还是未登录用户,都需要给一个唯一的ID来标识。

    有可能你已经想到了通过set集合去重的功能,为每一个页面创建一个set集合,每进来一次,都add一下,最后通过scard取出集合的大小就可以了,这是一个非常简单的方案,如果爆品页每天的UV几千万的话,这样是非常浪费空间资源的。如果这样的页面很多,存储空间是惊人的。为了去重浪费这么大空间是不值得的。

    Redis提供了一种解决方案,使用Hyper log log数据结构来解决这种统计的问题,Hyper log log提供的是不精确的去重计数方案,虽然不精确但也不是完全不精确,标准误差在0.81%左右。Hyper logLog是Redis的高级数据结构,非常有用,但是使用的人很少。

    使用方法

    127.0.0.1:6379> pfadd codehole user1
    (integer) 1
    127.0.0.1:6379> pfcount codehole
    (integer) 1
    127.0.0.1:6379> pfadd codehole user2
    (integer) 1
    127.0.0.1:6379> pfcount codehole
    (integer) 2
    127.0.0.1:6379> pfadd codehole user3
    (integer) 1
    127.0.0.1:6379> pfcount codehole
    (integer) 3
    127.0.0.1:6379> pfadd codehole user4
    (integer) 1
    127.0.0.1:6379> pfcount codehole
    (integer) 4
    127.0.0.1:6379> pfadd codehole user5
    (integer) 1
    127.0.0.1:6379> pfcount codehole
    (integer) 5
    127.0.0.1:6379> pfadd codehole user6
    (integer) 1
    127.0.0.1:6379> pfcount codehole
    (integer) 6
    127.0.0.1:6379> pfadd codehole user7 user8 user9 user10
    (integer) 1
    127.0.0.1:6379> pfcount codehole
    (integer) 10
    

    上面说HyperLogLog不精确的统计方案,下面我们用java来测试一下:

    public class JedisTest {
      public static void main(String[] args) {
        Jedis jedis = new Jedis();
        for (int i = 0; i < 100000; i++) {
          jedis.pfadd("codehole", "user" + i);
        }
        long total = jedis.pfcount("codehole");
        System.out.printf("%d %d\n", 100000, total);
        jedis.close();
      }
    }
    

    跑了约半分钟,我们看输出:

    > python pftest.py
    100000 99723
    

    差了 277 个,按百分比是 0.277%,对于上面的 UV 统计需求来说,误差率也不算高。然后我们把上面的脚本再跑一边,也就相当于将数据重复加入一边,查看输出,可以发现,pfcount 的结果没有任何改变,还是 99723,说明它确实具备去重功能。

    pfmerge 适合什么场合用?

    HyperLogLog 除了上面的 pfadd 和 pfcount 之外,还提供了第三个指令 pfmerge,用于将多个 pf 计数值累加在一起形成一个新的 pf 值。

    比如在网站中我们有两个内容差不多的页面,运营说需要这两个页面的数据进行合并。其中页面的 UV 访问量也需要合并,那这个时候 pfmerge 就可以派上用场了。

    注意事项

    HyperLogLog 这个数据结构不是免费的,不是说使用这个数据结构要花钱,它需要占据一定 12k 的存储空间,所以它不适合统计单个用户相关的数据。如果你的用户上亿,可以算算,这个空间成本是非常惊人的。但是相比 set 存储方案,HyperLogLog 所使用的空间那真是可以使用千斤对比四两来形容了。

    不过你也不必过于担心,因为 Redis 对 HyperLogLog 的存储进行了优化,在计数比较小时,它的存储空间采用稀疏矩阵存储,空间占用很小,仅仅在计数慢慢变大,稀疏矩阵占用空间渐渐超过了阈值时才会一次性转变成稠密矩阵,才会占用 12k 的空间。

    相关文章

      网友评论

          本文标题:6.【Redis系列】Redis的高级应用-HyperLogLo

          本文链接:https://www.haomeiwen.com/subject/bryjpqtx.html