基于Redis实现-UV统计

基于Redis实现-UV统计

本文将使用HyperLogLog来实现UV统计。

首先我们搞懂两个概念:

  • UV :全称U nique Visitor,也叫独立访客量,是指通过互联网访问、浏览这个网页的自然人。1天内同一个用户多次访问该网站,只记录一次。
  • PV :全称P age View,也叫页面访问量或点击量,用户每访问网站的一个页面,记录一次PV,用户多次打开页面,则记录多次PV,往往用来衡量网站的流量。

UV统计在服务端做会比较麻烦,因为要判断该用户是否已经统计过了,需要将统计的用户信息保存,但是如果每个访问的用户都保存到Redis中,数据量会非常恐怖。

1.HyperLogLog(HLL)

HyperLogLog(HLL)是从Loglog算法派生的概率算法用于确定非常大的集合的基数 ,而不需要存储其所有值。相关算法原理大家可以参考:算法介绍

Redis中的HLL是基于string结构实现 的,单个HLL的内存永远小于16kb ,内存占用极低!作为代价,其测量结果是概率性 的,有小于0.81%的误差 。不过对于UV统计来说,这完全可以忽略

shell 复制代码
#1. PFADD --- 添加元素到 HyperLogLog
#作用:向指定的 HLL 中添加一个或多个元素。
#返回值:1:如果至少有一个新元素被添加  0:如果所有元素已经存在(不会重复计数)
# 向 "daily_uv" 添加 3 个用户访问记录
PFADD daily_uv user1 user2 user3
(integer) 1  # 表示有新增数据

# 再次添加(user1 已存在,但 user4 是新用户)
PFADD daily_uv user1 user4
(integer) 1  # user4 是新元素,返回 1
--------------------------------------------------------------------------------------------
#2. PFCOUNT --- 计算基数(不重复元素数量)
#作用:返回 HLL 中近似的不重复元素数量(允许少量误差)。
#返回值:估算的基数(如 UV 数)。
# 查询 "daily_uv" 的独立访客数
PFCOUNT daily_uv
(integer) 4  # 返回近似值(实际可能是 4 或 3.96≈4)

# 计算多个 HLL 的并集(如统计一周的 UV)
PFCOUNT monday_uv tuesday_uv wednesday_uv
(integer) 1250  # 返回 3 天的总 UV(去重后)
--------------------------------------------------------------------------------------------
#3. PFMERGE --- 合并多个 HyperLogLog
#作用:将多个 HLL 合并成一个新的 HLL(计算并集)。
#返回值:OK(成功时返回)。
# 合并 "monday_uv" 和 "tuesday_uv" 到 "weekly_uv"
PFMERGE weekly_uv monday_uv tuesday_uv
OK

# 查询合并后的 UV
PFCOUNT weekly_uv
(integer) 850  # 返回两天的总 UV(去重后)

2.使用UV统计

这里先查看此时Redis内存使用情况:

  • used_memory:1485704(字节)
  • used_memory_human:1.42M

我们向Redis插入100万条数据:

java 复制代码
@Resource
private StringRedisTemplate stringRedisTemplate;
@Test
void testHyperLogLog() {
    // 准备数组,装用户数据
    String[] users = new String[1000];
    // 数组角标
    int index = 0;
    for (int i = 1; i <= 1000000; i++) {
        // 赋值
        users[index++] = "user_" + i;
        // 每1000条发送一次
        if (i % 1000 == 0) {
            index = 0;
            stringRedisTemplate.opsForHyperLogLog().add("Num", users);
        }
    }
    // 统计数量
    Long size = stringRedisTemplate.opsForHyperLogLog().size("Num");
    System.out.println("size = " + size);
}

注意:在Java中size对应PFCOUNT 命令,add对应PFADD 命令,union对应PFMERGE 命令。

插入结果:

此时我们查看Redis的内存使用情况:

  • used_memory:1500088(字节)
  • used_memory_human:1.43M

    (1500088-1485704)/1024=14.04kb,可以看到内存使用极少!!
    因此当我们需要统计大数据量时不妨考虑考虑UV统计。
相关推荐
倔强的石头_18 小时前
表空间自动目录创建与存储管理实践:参数化配置与性能优化
数据库
white-persist18 小时前
【vulhub spring CVE-2018-1270】CVE-2018-1270 Spring Messaging 远程命令执行漏洞 完整复现详细分析解释
java·服务器·网络·数据库·后端·python·spring
鬼先生_sir18 小时前
MySQL进阶-事务与锁机制
数据库·mysql·mvcc
treacle田18 小时前
达梦数据库-达梦数据库中link链接访问远程Sql Sever-记录总结
数据库·达梦-sqlserver
ClouGence18 小时前
不用搭复杂系统,也能做跨地域数据迁移?
大数据·数据库·saas
xcjbqd018 小时前
SQL中视图能否嵌套存储过程_实现复杂自动化报表逻辑
jvm·数据库·python
身如柳絮随风扬18 小时前
Redis中的哈希槽怎么理解
redis·哈希算法
听*雨声19 小时前
软件设计师上午题5:数据库
数据库
hong781719 小时前
阿里coding plan qwen3.6-plus 不支持图片上下文长度只有200K,问题出在哪?
linux·运维·数据库
未秃头的程序猿19 小时前
🚀 从“单机崩盘”到“集群稳如狗”:Redis 高可用避坑指南(保姆级实战)
redis·后端·面试