直接用 redis 的 hyperloglog 统计 dau,核心是设备标识去重、按天分桶、避免跨日干扰;它仅估算去重数量,误差约 0.81%,内存恒定约 12kb;推荐设备 id(如 android_id、idfv)优先,次选 ip+user-agent 哈希,禁用纯公网 ip;key 需含日期如 dau:app:20260709,并配合 expire 清理;tp8.0 中通过 pfadd 添加、pfcount 查询,多日统计须用 pfmerge 合并后计数。

直接用 Redis 的 HyperLogLog 统计每日活跃设备(DAU),核心在于:用设备标识去重、按天分桶、避免跨日干扰。它不存具体设备号,只估算去重后数量,误差约 0.81%,但内存恒定仅约 12KB,百万级设备也毫无压力。
设备标识怎么选?
DAU 关注的是“设备”而非“用户”,所以不能用登录态 ID(未登录用户就漏了)。推荐优先级如下:
- 客户端生成的唯一设备 ID(如 Android 的 ANDROID_ID、iOS 的 IDFV/IDFA,Web 可用 localStorage + 指纹组合),最稳定可靠;
- 退而求其次用 IP + User-Agent 哈希值(注意:NAT 环境下多个设备可能共用 IP,会低估;但比纯 IP 更准);
- 避免单独用公网 IP —— 运营商动态分配、家庭宽带共享都会导致严重高估或低估。
Key 设计要带日期维度
HyperLogLog 本身不支持过期,必须靠 Key 命名隔离每天数据。推荐格式:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
这样既能按天查,也能用 Redis 的 EXPIRE 或定时任务自动清理历史 Key(比如保留最近 90 天)。
PHP TP8.0 中调用示例
使用 ThinkPHP 8.0 内置的 Redis 驱动即可,无需额外扩展:
// 获取设备标识(以 App 场景为例)
$deviceId = input('device_id', '', 'htmlspecialchars');
if (!$deviceId) {
$deviceId = md5($_SERVER['HTTP_USER_AGENT'] . $_SERVER['REMOTE_ADDR']);
}
// 构建当天 Key
$date = date('Ymd');
$key = "dau:app:{$date}";
// 添加到 HyperLogLog(自动去重)
$redis = \think\facade\Cache::store('redis')->getRedis();
$redis->pfAdd($key, $deviceId);
// 查询当日 DAU(返回近似值)
$dau = $redis->pfCount($key);
怎么查多日趋势或合并统计?
HyperLogLog 支持合并,适合做周活(WAU)、月活(MAU)或跨渠道汇总:
- 查 7 天 DAU 总和?不行 —— pfCount 只能单 key 或多个 key 合并后计数,不能简单相加(会重复计算跨日活跃设备);
- 正确做法:用
PFMERGE合并多日 Key,再PFCOUNT,例如:$redis->pfMerge('dau:app:week_july03_09', ['dau:app:20260703', ..., 'dau:app:20260709']);$wau = $redis->pfCount('dau:app:week_july03_09'); - 注意:合并后的 Key 也需手动设置过期,否则长期堆积。










