有赞一面:亿级用户DAU日活统计,有几种方案?

article/2025/9/18 8:45:36

说在前面

在40岁老架构师 尼恩的读者社区(50+)中,最近有小伙伴拿到了一线互联网企业如极兔、有赞、希音、百度、网易、滴滴的面试资格,遇到一几个很重要的面试题:

(1) 亿级用户场景,如何高性能统计日活?

(2) 如何实现亿级数据统计?

(3) 亿级用户日活统计,有几种方案?

等等等等…

高并发Redis的使用,是面试的重点和高频点。

尼恩作为技术中台、数据中台的架构师,致力于为大家研究出一个 3高架构知识宇宙, 所以,这里,带大家完成一个 亿级用户场景,如何高性能统计日活的架构分析和实操。

当然,作为一篇文章,仅仅是抛砖引玉,后面有机会,带大家做一下这个高质量的实操,并且指导大家写入简历。

让面试官爱到 “不能自已、口水直流”

也一并把这个题目以及参考答案,收入咱们的 《尼恩Java面试宝典》V65版本,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。

注:本文以 PDF 持续更新,最新尼恩 架构笔记、面试题 的PDF文件,请从文末公号 【技术自由圈】取

文章目录

    • 说在前面
    • 业务场景分析
    • 亿级用户日活统计的存储架构
      • 方式1:通过 Redis 的 Set 集合来实现
      • 方式2:利用 Hash 类型实现
      • 方式3:利用 bitmap 实现
      • 方式4:利用 HyperLogLog 实现
    • 存储方案的问题分析
      • bigkey问题
      • 准确性问题
      • 方案选择
    • 回顾:什么是 Big Key?
      • Big Key的危害?
        • 1、阻塞请求
        • 2、内存增大
        • 3、阻塞网络
        • 4、影响主从同步、主从切换
    • HyperLogLog 原理和实操
      • 什么是 HyperLogLog?
      • HyperLogLog 与 bitmap 对比
        • 1、bitmap
        • 2、HyperLogLog
      • HyperLogLog 的使用场景
        • 大数据去重:
        • 用户活跃度统计:
        • 网站UV统计:
        • 社交网络推荐:
    • HyperLogLog 的相关命令
    • SpringBoot 实操:利用 HyperLogLog 实现网站UV统计
    • 超高并发异步架构
      • 队列缓存+批量写入的架构
    • 本文的版本计划和基础学习资料
    • 技术自由的实现路径 PDF:
        • 实现你的 架构自由:
        • 实现你的 响应式 自由:
        • 实现你的 spring cloud 自由:
        • 实现你的 linux 自由:
        • 实现你的 网络 自由:
        • 实现你的 分布式锁 自由:
        • 实现你的 王者组件 自由:
        • 实现你的 面试题 自由:

业务场景分析

什么是日活?

日活跃用户数量(Daily Active User,DAU)是用于反映网站、互联网应用或网络游戏的运营情况的统计指标。

日活跃用户数量通常统计一日(统计日)之内,登录或使用了某个产品的用户数(去除重复登录的用户)。

受统计方式限制,互联网行业使用的日均活跃用户数指在统计周期(周/月)内,该App的每日活跃用户数的平均值。

亿级用户日活统计的存储架构

一个用户一天内多次访问一个网站只能算作一次,

怎么做存储架构呢?

大概有四种方案,可供技术选型:

  • 方式1:通过 Redis 的 Set 集合来实现。
  • 方式2:利用 Hash 类型实现
  • 方式3:利用 bitmap 实现
  • 方式4:利用 HyperLogLog 实现

方式1:通过 Redis 的 Set 集合来实现

将用户id 放到 Set 中,Set 的去重功能能保证不会重复记录同一个用户 ID。

一个ZSET类型的Key,它的成员数量为10000个

一般来说,这个ZSET就是bigkey

方式2:利用 Hash 类型实现

将用户 ID 作为 Hash 集合的 key,访问页面则执行 HSET 命令将 value 设置成 1。

即使用户重复访问,重复执行命令,也只会把这个 userId 的值设置成 “1"。

利用 HLEN 命令,统计 Hash 集合中的元素个数就是 UV。

一个Hash类型的Key,它的成员数量虽然只有1000个但这些成员的Value值总大小为100MB,

一般来说,这个 Hash 就是bigkey

方式3:利用 bitmap 实现

使用bitmap,记录用户id的访问,则把指定key的用户id对应的bit位标记为1,

统计 日活,就是就是指定key中1的个数。

显然这里是操作位,相比2中,一个字节为8位,估算一下占用空间:96M/8=12M,

1千万用户只要 1M多的空间,但是 1亿的用户需要12M的大小即可记录。

一个String类型的Key,它的值为5MB, 就是bigkey

bitmap 底层结构,和String类型是类似的。

方式4:利用 HyperLogLog 实现

在输入用户数量非常大时,计算基数所需要的空间总是固定的,并且是很小的,

每个hyperloglog键需要12kb内存可以计算2^64个不同元素的基数,

这和元素基数元素越多,耗费内存越多的集合形成鲜明对比,

但是hyperloglog只会根据元素来计算基数,不会存储元素本身,所以不能像其它类型一样返回各个元素

hyperloglog是概率算法,是牺牲准确率换区空间的,

对于对精度要求不高的情况下可以使用,因为概率算法本身不直接存储数据本身,能保证误差在一定范围内,又不占用空间,误差在0.81%左右

存储方案的问题分析

bigkey问题

方案1、方案2、方案3

准确性问题

方案4

方案选择

如果允许 存在 准确性问题,就使用 hyperloglog 存储架构

如果允许 存在 bigkey 问题,或者解决 bigkey 问题,就使用 方案3 存储架构

这里优先使用 hyperloglog 存储架构

回顾:什么是 Big Key?

通俗易懂的讲,Big Key就是某个key对应的value很大,占用的redis空间很大,本质上是大value问题。

key往往是程序可以自行设置的,value往往不受程序控制,因此可能导致value很大。

redis中这些Big Key对应的value值很大,在序列化/反序列化过程中花费的时间很大,因此当我们操作Big Key时,通常比较耗时,这就可能导致redis发生阻塞,从而降低redis性能。

BigKey指以Key的大小和Key中成员的数量来综合判定,用几个实际的例子对大Key的特征进行描述:

  • Key本身的数据量过大:一个String类型的Key,它的值为5MB
  • Key中的成员数过多:一个ZSET类型的Key,它的成员数量为10000个
  • Key中成员的数据量过大:一个Hash类型的Key,它的成员数量虽然只有1000个但这些成员的Value值总大小为100MB

Big Key的危害?

1、阻塞请求

Big Key对应的value较大,我们对其进行读写的时候,需要耗费较长的时间,这样就可能阻塞后续的请求处理。Redis的核心线程是单线程,单线程中请求任务的处理是串行的,前面的任务完不成,后面的任务就处理不了。

2、内存增大

读取Big Key耗费的内存比正常Key会有所增大,如果不断变大,可能会引发 OOM(内存溢出),或达到redis的最大内存maxmemory设置值引发写阻塞或重要Key被逐出。

3、阻塞网络

读取单value较大时会占用服务器网卡较多带宽,自身变慢的同时可能会影响该服务器上的其他Redis实例或者应用。

4、影响主从同步、主从切换

删除一个大Key造成主库较长时间的阻塞并引发同步中断或主从切换。

HyperLogLog 原理和实操

HyperLogLog 是大数据基数统计中的常见方法,无论是 Redis,Spark 还是 Flink 都提供了这个功能,其目的就是在一定的误差范围内,用最小的空间复杂度来估算一个数据流的基数。

这个最小的空间,小到什么程度呢?在 Redis 中实现的 HyperLogLog,只需要12K内存就能统计2^64个数据。不过有得必有失,HyperLogLog计数存在一定的误差,误差率整体较低。标准误差为 0.81% ,不到1%。当然,误差可以被设置辅助计算因子进行降低。

什么是 HyperLogLog?

HyperLogLog 是一种概率性数据结构,它是 LogLog 算法的升级版,作用是能够提供不精确的去重计数。HyperLogLog 下面简称为HLL,

Redis中的HLL是基于string结构实现的,单个HLL的内存永远小于16kb内存占用低的令人发指!作为代价,其测量结果是概率性的,有小于0.81%的误差

HLL是一种用于基数统计的算法,可以用来估计一个集合中不同元素的数量,而不需要存储这些元素本身。它可以高效地处理大规模的数据集,且占用的空间非常小,通常只需要几千个字节的存储空间就可以处理数十亿个元素。HLL算法的实现非常简单,可以使用位图和随机哈希函数来实现。

HLL算法的基本思想是利用随机哈希函数将元素映射到一个二进制字符串中,并根据哈希函数的结果将字符串分为若干个桶。在每个桶中,记录哈希值的最大前导零的数量。

对于一个大的数据集,可以对每个元素进行哈希并记录其对应桶的最大前导零的数量,然后计算所有桶的平均值,得到一个近似的基数估计值。

HLL算法的误差率可以控制在0.81/sqrt(m)以内,其中m是桶的数量。

因此,随着桶的数量增加,误差率将变得越来越小。

HLL算法的优点在于它具有极低的内存消耗和高效的计算速度,并且可以处理极大的数据集。

HyperLogLog 与 bitmap 对比

1、bitmap

优势是:非常均衡的特性,精准统计,可以得到每个统计对象的状态,秒出。

缺点是:当你的统计对象数量十分十分巨大时,可能会占用到一点存储空间,但也可在接受范围内。也可以通过分片,或者压缩的额外手段去解决。

注意:bitmap是精确的

2、HyperLogLog

优势是:

可以统计夸张到无法想象的数量,并且占用小的夸张的内存。

缺点是:

建立在牺牲准确率的基础上,而且无法得到每个统计对象的状态。

注意:HyperLogLog 不是精确的,误差在 1%左右

HyperLogLog 的使用场景

HyperLogLog算法主要用于基数统计场景,即需要快速统计一个数据集中不同元素的数量的场合。在实际应用中,HyperLogLog算法通常应用于以下场景:

大数据去重:

在大数据场景下,需要去重的数据量非常大,如果使用传统的去重算法,需要对每个元素进行存储和比对,时间和空间消耗非常高。HyperLogLog算法可以在占用极小的空间的情况下,高效地对大规模数据进行去重,提高去重效率。

用户活跃度统计:

在Web应用和移动应用中,需要对用户的活跃度进行统计。如果每个用户的活跃度都进行存储,需要消耗大量的存储空间。HyperLogLog算法可以在占用极小的空间的情况下,高效地统计活跃用户数量,提高统计效率。

网站UV统计:

在Web应用中,需要统计网站每日独立访客数量(即UV),但是由于数据量非常大,不能简单地直接计数,因为会导致内存不足。HyperLogLog算法可以在占用极小的空间的情况下,高效地对大规模的访问日志进行去重和统计,提高统计效率。

社交网络推荐:

在社交网络中,需要对用户的兴趣爱好进行统计,以便向用户推荐相关内容。HyperLogLog算法可以在占用极小的空间的情况下,高效地对用户行为进行去重和统计,提高推荐效率。

总之,HyperLogLog算法可以在需要高效处理大规模数据集的场景下发挥作用,适用于各种基数统计场合,可以提高数据处理效率,减少存储空间的消耗。

HyperLogLog 的相关命令

Redis提供了多个HyperLogLog相关的指令,包括以下几个:

  • PFADD:将一个或多个元素添加到指定的HyperLogLog数据结构中。
    语法:PFADD key element [element ...]
PFADD hll_key a b c
  • PFCOUNT:统计指定的HyperLogLog数据结构中不同元素的数量。
    语法:PFCOUNT key [key ...]
PFCOUNT hll_key
  • PFMERGE:将多个HyperLogLog数据结构合并为一个。
    语法:PFMERGE destkey sourcekey [sourcekey ...]
PFMERGE hll_key1 hll_key2 hll_key3

这些指令可以方便地对HyperLogLog数据结构进行添加、统计和合并操作,以满足各种基数统计场景的需求。

需要注意的是,HyperLogLog数据结构虽然占用空间非常小,但是在添加元素时需要进行哈希计算,因此添加元素的效率可能会受到影响。

因此,在java代码中,可以使用 队列缓存+ 批量写入的架构,进行批量添加, 尽量减少io时间。

在使用HyperLogLog数据结构时,需要根据实际情况评估其效率和误差率,以确定是否适合使用HyperLogLog算法。

SpringBoot 实操:利用 HyperLogLog 实现网站UV统计

利用HyperLogLog实现网站UV统计 ,代码如下:

测试如下:

误差计算:

1百万,减去 99 6723 ,大概在 4000左右,不到1%

超高并发异步架构

通过阻塞队列,使用队列缓存+批量写入的架构

队列缓存+批量写入的架构

这里用了阻塞队列,这个非常常用

具体的架构图如下:

所以阻塞队列的结构,以及底层原理,大家好好掌握

BlockingDeque<String> dauList = new LinkedBlockingDeque<>();

访问记录,直接进入到 阻塞队列,参考代码如下

异步写入的参考代码如下:

本文的版本计划和基础学习资料

尼恩作为技术中台、数据中台的架构师, 高并发是尼恩架构的重点, 所以,后面会大家从 架构到实操, 多个维度、多种场景的高并发实操。

而且尼恩指导简历的过程中,也指导过小伙伴写过 10Wqps 超高并发 网关、超高并发秒杀、超高并发物联网等等简历,里边涉及到大量的设计模式,

经过尼恩的指导之后,很多 小伙伴的简历,里边立马金光闪闪,并且顺利走上了架构师之路。

后面有机会,带大家做一下这个高质量的实操,并且指导大家写入简历。

所以,这个材料后面也会进行持续迭代,大家可以在文末找尼恩获取最新版本和技术交流。

尼恩编著的400页PDF电子书 《SpringCloud Alibaba 技术圣经》

尼恩编著的500页 PDF电子书 《Java高并发核心编程 卷2 加强版》,清华大学出版社出版

技术自由的实现路径 PDF:

实现你的 架构自由:

《吃透8图1模板,人人可以做架构》

《10Wqps评论中台,如何架构?B站是这么做的!!!》

《阿里二面:千万级、亿级数据,如何性能优化? 教科书级 答案来了》

《峰值21WQps、亿级DAU,小游戏《羊了个羊》是怎么架构的?》

《100亿级订单怎么调度,来一个大厂的极品方案》

《2个大厂 100亿级 超大流量 红包 架构方案》

… 更多架构文章,正在添加中

实现你的 响应式 自由:

《响应式圣经:10W字,实现Spring响应式编程自由》

这是老版本 《Flux、Mono、Reactor 实战(史上最全)》

实现你的 spring cloud 自由:

《Spring cloud Alibaba 学习圣经》

《分库分表 Sharding-JDBC 底层原理、核心实战(史上最全)》

《一文搞定:SpringBoot、SLF4j、Log4j、Logback、Netty之间混乱关系(史上最全)》

实现你的 linux 自由:

《Linux命令大全:2W多字,一次实现Linux自由》

实现你的 网络 自由:

《TCP协议详解 (史上最全)》

《网络三张表:ARP表, MAC表, 路由表,实现你的网络自由!!》

实现你的 分布式锁 自由:

《Redis分布式锁(图解 - 秒懂 - 史上最全)》

《Zookeeper 分布式锁 - 图解 - 秒懂》

实现你的 王者组件 自由:

《队列之王: Disruptor 原理、架构、源码 一文穿透》

《缓存之王:Caffeine 源码、架构、原理(史上最全,10W字 超级长文)》

《缓存之王:Caffeine 的使用(史上最全)》

《Java Agent 探针、字节码增强 ByteBuddy(史上最全)》

实现你的 面试题 自由:

4000页《尼恩Java面试宝典 》 40个专题

以上尼恩 架构笔记、面试题 的PDF文件更新,请到《技术自由圈》公号取↓↓↓


http://chatgpt.dhexx.cn/article/xGHkj37Q.shtml

相关文章

数据分析——用户粘性指标 DAU/MAU

&#xff08; 一 &#xff09;定义 DAU&#xff0c;即&#xff1a;Daily Active User&#xff0c;指日活跃用户数&#xff1b; MAU&#xff0c;即&#xff1a;Monthly Active User&#xff0c;指月活跃用户数。 日活/月活就是体现用户粘性最频繁使用的指标。日活跃用户占月活…

数据分析体系 - 用户粘性(DAU/MAU 和 月人均活跃天数)

对于常见的App&#xff0c;用户粘性的取值范围就是3%~100%&#xff0c; 不同领域的App也会有不同的基准值&#xff0c; 例如移动游戏会以20%为基线&#xff0c; 而工具类App会以40%为基线。 用户粘性的两个计算指标&#xff1a; 1、DAU/MAU 2、月平均活跃人数 这里其实…

数据分析——DAU下降/上升原因分析

本文是对“DAU变动原因”问题进行的思考整理&#xff0c;仅作记录&#xff0c;欢迎讨论。 &#xff08; 一 &#xff09;思维框架 图版&#xff1a; 文版&#xff1a; 内部原因&#xff1a; 1. 数据验证 如果DAU上升或者下降&#xff0c;且非日常波动&#xff0c;需先确…

数据分析 — 用户粘性的两个计算指标(DAU/MAU和月人均活跃天数)

很多运营都了解DAU&#xff08;日活跃用户数&#xff09;和MAU&#xff08;月活跃用户数&#xff09;的重要性&#xff0c;但在某些情况下这两个数值本身并不能反映出太多问题&#xff0c;这个时候就要引用到【DAU/MAU】的概念&#xff0c;即【日活/月活】。 用户粘性的两个计…

峰值21WQps、亿级DAU,小游戏《羊了个羊》是怎么架构的?

小游戏《羊了个羊》 短短的7天内&#xff0c;DAU突破了1亿、吞吐量峰值21WQps。 《羊了个羊》运营后台数据显示&#xff0c;在短短的7天内&#xff0c;这款小游戏的DAU就突破了1亿。 要知道&#xff0c;除了王者荣耀、原神等屈指可数的现象级手游之外&#xff0c;1亿DAU是这个…

dau、mau、pcu、dnu、wau、acu、uv分别是什么意思?

dau、mau、pcu、dnu、wau、acu、uv的意思是什么?怎么分析? DAU(Daily Active User)日活跃用户数量。常用于反映网站、互联网应用或网络游戏的运营情况。 MAU(monthly active users)月活跃用户人数。是在线游戏的一个用户数量统计名词&#xff0c;数量越大意味着玩这款游戏的人…

数据化运营04 DAU、MAU、UV:谁是最有参考价值的活跃指标?

活跃类指标是重要的用户质量指标&#xff0c;代表了产品上真正的用户&#xff0c;代表了具备营销价值的用户群&#xff0c;是几乎所有产品运营的重点。 在这一讲中&#xff0c;我会主要向你介绍 UV、DAU、MAU&#xff0c;以及每日使用时长和每日打开频次等指标。 你是否思考过…

如何理解、分析DNU/DAU?(案例:DNU、DAU面积图)

前言&#xff1a;本文内容以游戏产品为基础进行讲解&#xff0c;内容为以下4部分&#xff1a; 1. 如何理解DNU和DAU 2. 如何使用python绘制DNU和DAU的面积图 3. 如何分析DNU/DAU 4. 如何计算当日DAU有多少由往日N日DAU贡献的&#xff0c;并简单计算用户生命周期&#xff1f; DN…

DAU是啥,数据指标是啥?必知必会的数据分析常识

在刚迈入数据的大门时&#xff0c;我经常对一些数据指标或者数据本身的概念很模糊&#xff0c;尤其是当跟运营、数据分析师扯需求的时候&#xff0c;会被这些密密麻麻的指标给弄糊涂。为了更好的在行业里面摸打滚爬&#xff0c;花了很多时间阅读一些指标相关的文章、书籍&#…

dau、mau、pcu、dnu、wau、acu、uv的意思是什么?怎么分析?

dau、mau、pcu、dnu、wau、acu、uv的意思是什么?怎么分析? DAU(Daily Active User)日活跃用户数量。常用于反映网站、互联网应用或网络游戏的运营情况。 MAU(monthly active users)月活跃用户人数。是在线游戏的一个用户数量统计名词&#xff0c;数量越大意味着玩这款游戏的人…

dau、mau、pcu、dnu、wau、acu、uv的意思是什么?

dau、mau、pcu、dnu、wau、acu、uv的意思是什么?怎么分析? 名词分析 DAU(Daily Active User)日活跃用户数量。常用于反映网站、互联网应用或网络游戏的运营情况。 MAU(monthly active users)月活跃用户人数。是在线游戏的一个用户数量统计名词&#xff0c;数量越大意味着玩…

Spring AOP原理和用法

AOP也就是面向切面编程&#xff0c;首先AOP不等于Spring aop&#xff0c;前者是编程所要实现的目标&#xff0c;后者仅仅是AOP的实现方式之一&#xff0c;作为一种动态注入的实现方式&#xff0c;还有一些别的例如AspectJ&#xff08;静态注入&#xff09;等 一. Spring aop使…

一篇文章详细解读Spring的AOP原理过程(Spring面向切面详解)

目录 概述 使用登录例子说明 AOP AOP&#xff08;底层原理&#xff0c;了解&#xff09; 有两种情况动态代理 第一种 有接口情况&#xff0c;使用 JDK动态代理 第二种 没有接口情况&#xff0c;使用 CGLIB 动态代理 回顾JDK静态代理 ①明星唱歌&#xff0c;经纪人替他签…

IOC/DI、AOP相关原理

文章目录 IOC/DI为什么IOC就降低了耦合性 AOP原理使用AOP的名词们概念性名词JoinPoint/TargetIntroductionProxyWeaving 在代码中有对应注解的名词AspectPointcut&#xff08;在哪儿切&#xff09;Advice&#xff08;什么时候切&#xff09; 示例代码 IOC/DI IOC全称是Inversio…

Spring——AOP原理及流程详解

AOP原理及流程详解 一、AOP结构介绍Pointcut通知原理连接点拦截器 二、Bean介入点EnableAspectJAutoProxyAspectJAutoProxyRegistrarAnnotationAwareAspectJAutoProxyCreatorAbstractAutoProxyCreator实例前执行初始化后执行循环依赖会调用 总结 三、处理切面获取所有切面其下通…

Spring中的AOP原理

目录 0 为什么需要AOP 1 基本概念 2 AOP原理 2.1 JDK动态代理 2.2 CGLIB 动态代理 0 为什么需要AOP 现在有一个情景&#xff1a; 我们要把大象放进冰箱&#xff0c;步骤为&#xff1a;打开冰箱->放入大象->关闭冰箱 如果再把大象拿出来&#xff0c;步骤为&#x…

Spring AOP的实现原理 ?

Spring AOP的实现原理 ? - 知乎 AOP的实现&#xff0c;最关键的有两步&#xff1a; 得到代理对象利用递归责任链执行前后置通知及目标方法 IOC容器初始化时&#xff0c;对于涉及AOP操作的目标类&#xff0c;其实Spring返回的是代理对象&#xff0c;而不是目标类的实例。至于…

AOP理解及底层原理

AOP 基础概念 一、概述 银行系统的简易取款流程如图&#xff1a; 将方框里的流程合为一个&#xff0c;另外系统还会有一个查询余额流程&#xff0c;如图&#xff1a; 这两个业务有一个共同的验证流程&#xff0c;如图&#xff1a; 为什么会有面向切面编程(AOP)&#xff…

Spring AOP原理分析一次看懂

什么是AOP AOP&#xff08;Aspect-OrientedProgramming&#xff0c;面向方面编程&#xff09;&#xff0c;可以说是OOP&#xff08;Object-Oriented Programing&#xff0c;面向对象编程&#xff09;的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构&…

AOP-底层原理

申明&#xff1a;学习笔记整理&#xff0c;内容非原创&#xff0c;仅供参考学习&#xff01;视频详细地址如下&#xff1a; 尚硅谷Spring框架视频教程&#xff08;spring5源码级讲解&#xff09;_哔哩哔哩_bilibili 目录 一、AOP概念 二、AOP底层原理 三、JDK动态代理代码…