news 2026/5/22 4:36:17

从 Hash 到 HyperLogLog:Redis 海量 UV 统计的 3 种高阶玩法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从 Hash 到 HyperLogLog:Redis 海量 UV 统计的 3 种高阶玩法

真实业务场景

假设我们正在开发一个电商大促活动页,产品经理提了一个“简单”的需求:我们需要实时显示“当前正在浏览商品的用户数”。这个数字每秒可能变化数万次。在 10 万级并发下,传统关系型数据库会面临什么问题?

经典错误场景:

// Java 初学者的常见做法 public synchronized void addCount() { int count = getFromMySQL(); updateMySQL(count + 1); }

上述代码在高并发下会导致:

  1. 数据库连接池过载(超时错误)

  2. 行锁竞争(死锁风险)

  3. CPU 飙升至 100%(性能崩溃)

这正是我们需要设计 Redis 统计方案的核心原因——在这种场景下,关系型数据库的 ACID 特性反而成了负担。

Redis 方案的演进

阶段 1:Hash 方案——精确统计的起点

原理:使用哈希表记录每个独立访客,适用于对精度要求高、中小型规模的场景。

// 将用户访问记录添加到 Hash Jedis jedis = new Jedis("localhost", 6379); String pageKey = "page_visit_count:examplePage"; // 页面访问计数 Key String userId = "user_123"; // 已登录用户 String visitorId = "visitor_abc123"; // 未登录用户 // 使用 HSET 命令添加数据,值简单设为 "1" jedis.hset(pageKey, userId, "1"); jedis.hset(pageKey, visitorId, "1"); // 统计访问量,直接使用 HLEN 命令获取字段数量 long visitCount = jedis.hlen(pageKey); System.out.println("The page visit count is: " + visitCount);

这种方法的优点是简单直接——实现容易,查询方便,且精度极高。但缺点也显而易见。

随着访问页面的增加,Key 像滚雪球一样膨胀,链表变长,内存占用迅速飙升,性能逐渐下降。

因此,这种方法更适合流量相对较低的页面,作为初期的尝试。

阶段 2:Bitmap 方案——空间与性能的平衡

当用户基数变大时,使用 Hash 在空间上就显得有些浪费了。

这正是 Bitmap 大显身手的时候,它是空间效率的大师。它巧妙地利用了 32 位 int 类型——不再存储一个完整的用户 ID,而是拆解 32 位,每一位代表一个用户,直接节省了 32 倍的空间。

对于已登录用户,其 ID 直接映射到 Bitmap 中的特定位。对于未登录用户,通过哈希算法将随机字符串标识符转换为哈希值,再映射到特定位。例如,用户 ID 为 5,对应 Bitmap 第 5 位;随机字符串哈希值为 10,对应第 10 位。

// 使用 Bitmap 统计页面访问量 Jedis jedis = new Jedis("localhost", 6379); String pageKey = "bitmap_visit_count:examplePage"; // Bitmap 访问计数 Key String loginUserId = "5"; // 已登录用户 ID String nonLoginUserKey = "random_str_123"; // 未登录用户的随机 Key // 对于已登录用户,直接设置对应位 jedis.setbit(pageKey, Long.parseLong(loginUserId), true); // 对于未登录用户,先对 Key 进行哈希,再设置位 String hashValue = DigestUtils.md5DigestAsHex(nonLoginUserKey.getBytes()); long hashBitIndex = Long.parseLong(hashValue.substring(0, 16), 16) % Long.MAX_VALUE; jedis.setbit(pageKey, hashBitIndex, true); // 使用 BITCOUNT 命令统计访问量 long visitCount = jedis.bitcount(pageKey); System.out.println("The page visit count is: " + visitCount);

这种方法的优势在于极小的内存占用和便捷的查询,甚至可以检查特定用户是否访问过页面。

但也存在明显的缺点。多个用户可能会碰撞到同一位上,导致统计略有偏差。此外,如果用户分布稀疏——例如用户 ID 是 1 亿——则需要分配 1 亿个位,可能会造成内存浪费。

因此,这种方法更适合用户分布相对密集的场景。

阶段 3:HyperLogLog 方案——超大数据量的“量子”统计

突破性思维:通常,系统不需要绝对精确的数据,可以用可控的误差换取内存和性能的巨大提升。

它不再追求记录每个用户的确切计数,而是使用概率算法估算近似访问量,误差控制在 0.81% 以内,这在实际应用中通常已经足够。

// 使用 HyperLogLog 统计页面访问量 Jedis jedis = new Jedis("localhost", 6379); String pageKey = "hyperloglog_visit_count:examplePage"; // HyperLogLog 访问计数 Key String userId = "user_456"; // 用户标识,可以是 ID 或其他唯一标识 // 使用 PFADD 命令添加用户访问记录 jedis.pfadd(pageKey, userId); // 使用 PFCOUNT 命令统计访问量 long approxVisitCount = jedis.pfcount(pageKey); System.out.println("The approximate page visit count is: " + approxVisitCount);

总结

这三种方案各有所长。

Hash 就像一本细致的账本,适用于小规模、高精度的统计。Bitmap 是空间压缩的大师,适合用户分布密集的才中等规模场景。HyperLogLog 则是概率统计专家,专为超高并发、高流量的网站设计。

在实际项目中,我们需要根据业务场景灵活选择,从而在并发战场中掌控全局,精准高效地统计用户访问量。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/21 10:38:27

钓鱼即服务:网络犯罪的地下订阅革命

仅供会员阅读的故事 钓鱼即服务:网络犯罪的订阅革命 我们都熟悉“软件即服务”。现在,想象一下在互联网的阴影地带,同样的便利性。欢迎来到“钓鱼即服务”——一个蓬勃发展的地下市场,在这里,专业级的网络钓鱼活动成本…

作者头像 李华
网站建设 2026/5/20 23:22:05

(10-2)模块集成与总装流程:装配流程与工具链

10.2 装配流程与工具链装配流程与工具链直接影响人形机器人整机装配质量与生产效率。本节内容将围绕标准化装配过程,介绍从部件安装到系统集成的关键步骤,并结合专用工具链提升装配一致性与可靠性。10.2.1 关节安装流程关节是人形机器人实现运动功能的…

作者头像 李华
网站建设 2026/5/21 19:35:01

Gstreamer playbin dot文件分析

实验环境:Windows11WSL2 可以查看附件的svg文件,配合原教程食用更佳: 基础教程14:实用元素 --- Basic tutorial 14: Handy elements 一、生成dot文件 WSL命令行,把dot文件输出改为当前输出目录,也可以自…

作者头像 李华
网站建设 2026/5/20 18:05:20

智能科学与技术毕设新颖的课题推荐

1 引言 毕业设计是大家学习生涯的最重要的里程碑,它不仅是对四年所学知识的综合运用,更是展示个人技术能力和创新思维的重要过程。选择一个合适的毕业设计题目至关重要,它应该既能体现你的专业能力,又能满足实际应用需求&#xff…

作者头像 李华
网站建设 2026/5/21 17:43:12

国产化系统中PHP如何实现视频大文件的分块分享?

【一个武汉大四狗的"大文件上传"自救实录:从"PHP?那不是用来写留言板的吗?“到"哥的上传系统能扛住整个光谷的流量!”】 "同学,你简历上写’熟悉PHP开发’,那能说说怎么用PHP实现…

作者头像 李华
网站建设 2026/5/22 13:40:14

Qt学习第一个程序:Hello,World

本文将以Qt 5/6(通用步骤,两者无核心差异)、Qt Creator开发工具为例,完成经典的Hello,World程序,包含纯代码编写和UI拖拽两种方式,步骤详细且适合零基础入门,确保每一步都能落地执行…

作者头像 李华