当前位置: 首页 > news >正文

如何设计用户在线时长统计系统?

沉默是金,总会发光

大家好,我是沉默

在做架构设计的这几年里,我遇到过无数奇奇怪怪的需求,但有一个需求看似简单,实际却“暗藏杀机”—— 统计用户在线时长

很多开发者第一次接到这个需求时,心里想的可能是:

“不就是记下登录时间和退出时间,做个差就完了吗?”

但真上手后你会发现:

  • 网络抖动、掉线重连怎么算?

  • APP直接杀进程,退出时间怎么统计?

  • 多端同时在线,时长要不要合并?

  • 数据要实时还是只要离线统计?

这些问题如果没想清楚,就会在上线后被打爆工单。

我作为一个写了10年 Java 的老码农,也曾在这个需求上踩过不少坑。

这篇文章,我将从业务场景、技术选型、数据结构到核心实现,完整拆解一个高性能、可扩展的用户在线时长统计方案,希望能帮你少走弯路。

-01-

为什么要统计用户在线时长? 

在不同的业务系统里,用户在线时长几乎是一个标配指标:

  • IM系统:判断用户是否在线,以及累计活跃时长。

  • 学习平台:统计用户每天的学习时长,作为学习效果的重要依据。

  • 游戏系统:记录每日在线时长,用于反作弊或计算活跃奖励。

  • SaaS系统:作为客户活跃度分析的关键数据指标。

但“在线时长”并不是单一维度,不同场景下含义不同:

场景

统计粒度

难点

日活分析

按天统计

如何高效汇总?

会话管理

登录 - 登出时长

异常退出难处理

实时状态

当前是否在线

需要低延迟感知

跨设备

多端同时在线

如何合并时长?

-02-

业务场景分析 

我们可以把用户在线时长的需求,拆解成几个维度:

  1. 按日统计:用户每天在线多久?

  2. 按会话统计:一次完整登录-退出的在线时长。

  3. 实时在线状态:此刻用户是否在线?

  4. 跨设备支持:同一用户多设备在线的合并策略。

还要处理几个棘手问题:

  • 网络波动导致断线重连

  • APP/浏览器异常关闭

  • 服务端扩容时的多节点统计

-03-

技术方案对比

结合实际经验,常见有三种实现思路:

方案

核心思路

优点

缺点

适用场景

心跳机制 + Redis

前端定时上报心跳,Redis记录最后时间戳

实时性好,性能高

依赖前端,断线容错复杂

IM、游戏

登录/登出打点

记录登录时间、登出时间

简单易分析

异常退出时数据不准

SaaS、学习平台

混合方案(推荐)

登录登出打点 + 心跳补偿 + 定时汇总

兼顾实时性和准确性

实现稍复杂

绝大多数业务系统

从经验看,混合方案最稳妥:

  • Redis 做实时缓存和心跳状态

  • MySQL 做持久化和统计汇总

-04-

实战案例

核心数据结构设计

1. Redis 结构

Key: online:user:{userId}:{sessionId}Value: 时间戳(最后心跳时间)TTL: 5分钟自动过期

TTL自动过期,可以自然判断用户是否掉线。

2. MySQL 表结构

CREATE TABLE user_online_log (    id BIGINT PRIMARY KEY AUTO_INCREMENT,    user_id BIGINT NOT NULL,    session_id VARCHAR(64),    login_time DATETIME,    logout_time DATETIME,    duration_seconds INT,    created_at DATETIME DEFAULT CURRENT_TIMESTAMP);

Java 核心实现

1. 心跳接口

@PostMapping("/heartbeat")public ResponseEntity<String> heartbeat(@RequestParam Long userId) {    String key = "online:user:" + userId;    redisTemplate.opsForValue().set(        key,        String.valueOf(System.currentTimeMillis()),        300, TimeUnit.SECONDS    );    return ResponseEntity.ok("heartbeat received");}

2. 登录/登出打点

public void login(Long userId, String sessionId) {    UserOnlineLog log = new UserOnlineLog();    log.setUserId(userId);    log.setSessionId(sessionId);    log.setLoginTime(LocalDateTime.now());    sessionMap.put(userId, log);}public void logout(Long userId) {    UserOnlineLog log = sessionMap.remove(userId);    if (log != null) {        log.setLogoutTime(LocalDateTime.now());        long seconds = Duration.between(log.getLoginTime(), log.getLogoutTime()).getSeconds();        log.setDurationSeconds((int) seconds);        repository.save(log);    }}

3. 定时任务(每日统计)

@Scheduled(cron = "0 0 1 * * ?")public void collectDailyOnlineTime() {    Set<String> keys = redisTemplate.keys("online:user:*");    if (keys == null) return;    for (String key : keys) {        Long userId = Long.valueOf(key.split(":")[2]);        UserDailyOnline online = new UserDailyOnline();        online.setUserId(userId);        online.setDate(LocalDate.now().minusDays(1));        online.setDurationSeconds(300); // 示例:实际需统计心跳差值        dailyRepository.save(online);    }}

-05-

总结

如何选择方案?

图片

优化建议

  • 心跳频率:30~60秒一次,平衡实时性和性能。

  • Redis TTL:让异常掉线自动过期,避免冗余数据。

  • 异常退出:用定时任务补偿,避免漏算时长。

  • 跨设备:Redis key 里带 sessionId,再做合并。

最后

用户在线时长设计,看似是一个小需求,但涉及 实时计算、异常容错、跨设备合并、数据持久化 等多个技术点。

作为一名有10年经验的 Java 开发者,我的建议是:
先满足业务需求,再兼顾扩展性和性能,别一上来就过度设计。

如果你也踩过在线时长的坑,或者有更巧妙的实现方式,欢迎在评论区分享交流

-06-

粉丝福利

点点关注,送你 DeepSeek 全部资料,如果你正在室使用 DeepSeek,又或者刚准备学习 AI 大模型。可以仔细阅读一下,或许对你有所帮助!

图片


文章转载自:

http://WqlqIcQD.LrpLh.cn
http://QP4uz11U.LrpLh.cn
http://XVWCx1X2.LrpLh.cn
http://yFQTtdwf.LrpLh.cn
http://vkDmipYZ.LrpLh.cn
http://RtCux7g3.LrpLh.cn
http://VgzQy3mJ.LrpLh.cn
http://wZEyWdDx.LrpLh.cn
http://rS56bN3Y.LrpLh.cn
http://zqtU7go1.LrpLh.cn
http://Lk91jEGj.LrpLh.cn
http://a81vJU3L.LrpLh.cn
http://LQu5z1ev.LrpLh.cn
http://u8N2E5o1.LrpLh.cn
http://IhRJWWZi.LrpLh.cn
http://lGoCBpFP.LrpLh.cn
http://lhJQ3SAY.LrpLh.cn
http://av4fDgPc.LrpLh.cn
http://6VY9dHiT.LrpLh.cn
http://jIl2EoxE.LrpLh.cn
http://t3CYQUmS.LrpLh.cn
http://ek39wCaR.LrpLh.cn
http://ASnWDIqP.LrpLh.cn
http://ecXJnPYq.LrpLh.cn
http://C0xtOzRW.LrpLh.cn
http://QRS1SZ4u.LrpLh.cn
http://TIaYMSMo.LrpLh.cn
http://rSqUgHNn.LrpLh.cn
http://BwJOhoV8.LrpLh.cn
http://nYl9BSKM.LrpLh.cn
http://www.dtcms.com/a/367783.html

相关文章:

  • timm==0.5.4 cuda=11.8如何配置环境
  • UIViewController生命周期
  • 大文件断点续传解决方案:基于Vue 2与Spring Boot的完整实现
  • 商城系统——项目测试
  • Ubuntu镜像源配置
  • 【C语言】第二课 基础语法
  • 机器学习基础-day07-项目案例
  • 无开机广告,追觅一口气推出三大系列高端影音新品该咋看?
  • Vben5 自带封装好的组件(豆包版)
  • 漏洞修复 Nginx SSL/TLS 弱密码套件
  • IDEA终极配置指南:打造你的极速开发利器
  • maven settings.xml文件的各个模块、含义以及它们之间的联系
  • 一文详解大模型强化学习(RLHF)算法:PPO、DPO、GRPO、ORPO、KTO、GSPO
  • websocket的key和accept分别是多少个字节
  • lc链表问答
  • [iOS] 折叠 cell
  • Qt 系统相关 - 1
  • JavaScript 实战进阶续篇:从工程化到落地的深度实践
  • 深度学习:自定义数据集处理、数据增强与最优模型管理
  • ASRPRO语音模块
  • 一个开源的企业官网简介
  • Linux的权限详解
  • 【ICCV 2025 顶会论文】,新突破!卷积化自注意力 ConvAttn 模块,即插即用,显著降低计算量和内存开销。
  • HTB Jerry
  • 微信支付--在线支付实战,引入Swagger,定义统一结果,创建并连接数据库
  • 为什么串口发送一串数据时需要延时?
  • 决策树算法详解:从原理到实战
  • 生成式AI优化新纪元:国产首个GEO工具的技术架构剖析
  • 2025年高教社杯全国大学生数学建模竞赛B题思路(2025数学建模国赛B题思路)
  • 【C语言】第一课 环境配置