略微加速

略速 - 互联网笔记

Redis 实现 UV 统计

2020-09-14 leiting (2078阅读)

标签 Redis

1 概述

一般我们评估一个网站的访问量,有几个主要的参数:PV(Page View)网页的浏览量、UV(User View)访问的用户量。有很多第三方工具可以统计,如 cnzz,友盟等。如果自己实现的话,PV 比较简单,可以直接通过 Redis 计数器实现。但是 UV 就不一样,UV 涉及到去重的问题。

常规思路:我们首先需要在前端给每一个用户生成一个唯一 id,无论是登录用户还是未登录用户都需要,这个 id 伴随着请求一起到达后端,在后端我们可以通过 Set 数据结构中的 sadd 命令来存储这个 id,最后通过 scard 统计集合大小,进而得出 UV 数据。

按上述思路,如果是千万级别的 UV,需要的存储空间就非常惊人,用 Set 就不是很合适了。一般来说像 UV 统计这种,不需要特别精确,比如 800W 和 803W 的 UV,其实差别不大。因此,我们可以使用 HyperLogLog 来高效的实现。

2 基本使用

Redis 中提供的 HyperLogLog 就是专门用来解决上述问题的,HyperLogLog 提供了一套不怎么精确但是够用的去重方案,会有误差,官方给出的误差数据是 0.81%,这对于 UV 的统计够用了。

HyperLogLog 主要提供了以下命令:

  • pfadd:用来添加记录,类似于 sadd ,添加过程中,重复的记录会自动去重。
  • pfcount:则用来统计数据。
  • pfmerge:合并多个统计结果,在合并的过程中,会自动去重多个集合中重复的元素。

数据量少的时候看不出来误差,我们在 Java 中多添加几个元素:

public class HyperLogLogTest {
    @Test
    public void testHyperLogLog() {
        Redis redis = new Redis();
        redis.execute(jedis -> {
            for (int i = 0; i < 1000; i++) {
                // 重复加入数据,理论值上总数为 1001
                jedis.pfadd("uv", "u" + i, "u" + (i + 1));
            }
            long uv = jedis.pfcount("uv");
            System.out.println(uv);
        });
    }
}

理论值上总数为 1001,实际打印出来 994,有误差,但是在可以接受的范围内。


北京半月雨文化科技有限公司.版权所有 京ICP备12026184号-3