sakudie
V2EX  ›  Redis

redis 统计在线人数的疑问

  •  
  •   sakudie · Jun 22, 2018 · 7972 views
    This topic created in 3019 days ago, the information mentioned may be changed or developed.

    系统 session 设置为 2 小时, 并且我的 session 信息是直接存储在 redis 里面的

    现在利用 redis 的 zset 统计人数,每当用户登陆的时候, zadd 添加当前用户 id,score 为登陆时间戳

    这个比较适合统计 一天 或者 一周 的上线人数, 直接 zrange 结果也比较准确

    如果我想同时利用 zset 统计 当前在线人数, 必须得 每当用户访问页面时, 更新用户的 score 为新的时间戳, 是这样吗?

    那么我直接在 redis 中维护一个 cur_online_user_num 的 key, 每当 session 创建的时候, 值++ , 每当 session 失效的时候 值-- , 这样是不是更好点, 避免了 频繁更新 score 的问题?

    12 replies  •  2018-06-23 11:57:34 +08:00
    joaner
        1
    joaner  
       Jun 22, 2018   ❤️ 1
    是的,需要每次访问页面都用 ZADD 更新时间,redis 会按用户 ID 自动去重。
    查询 2 小时内的在线人数时:`ZCOUNT views ($now_timestamp-7200) 9999999999`

    你后面的方案简单点,但 session 失效时的钩子不好设置。
    hiboshi
        2
    hiboshi  
       Jun 22, 2018
    如果用户很长时间不刷新呢?不也在线 比如看一篇比较难懂的文章,建议加个心跳接口。每间隔一段时间 t 去做刷新 last_time.
    zzf2017
        3
    zzf2017  
       Jun 22, 2018
    大佬有文章或者方法吗?我最近也在弄这些东西,但是处理起来不太好
    holyghost
        4
    holyghost  
       Jun 22, 2018   ❤️ 1
    zzf2017
        5
    zzf2017  
       Jun 22, 2018
    @holyghost 你的这种太高端了,还是全英文的,看不懂啊
    a7a2
        6
    a7a2  
       Jun 22, 2018
    避免频繁更新 redis 不是这样设计

    而是“每当用户访问页面时”记录在代码 map 中,开一个专门处理这个 map 数据的任务,每 1 分钟处理一次,把 map 记录的页面访问时间对比 redis 时间才更新。

    就是 redis 前自己缓存一下的意思,网站 pv 量很高的时候也不至于把 redis 搞得太忙
    @sakudie
    sakudie
        7
    sakudie  
    OP
       Jun 22, 2018
    @hiboshi 这个 session 在服务端有定时检测的,过期的会被主动清理掉,session 有效时间设置为 2 小时够长了。
    sakudie
        8
    sakudie  
    OP
       Jun 22, 2018
    @a7a2 如果放到 map 里面,到时候就算定期比较、更新不是要遍历 zset 吗
    owenliang
        9
    owenliang  
       Jun 22, 2018   ❤️ 1
    分享一个我的实现。

    假设 2 分钟以内访问过网站,算作在线。

    那么,当一个访问请求过来的时候,假设此时是 1970 年以来的第 N 分钟,那么你应该执行这样一个 Redis 命令:

    pipeline
    zrem online_${N-1} uid
    zadd online_${N} 0 uid
    expire online_${N} 1800
    exec

    那么你想知道在线用户数量,只需要 zcard online_${N-1} + zcard online_${N},就是 2 分钟内的用户总数量了。

    考虑实际工程问题,用户量大的情况下肯定不能都写一个 redis 集合,可以按 uid 取模到不同的 Redis 实例中,最后统计时做加和。
    a7a2
        10
    a7a2  
       Jun 22, 2018   ❤️ 1
    @sakudie 不需要比较了 直接 map 里面有最后的浏览记录直接写 redis 写完要清空 map 即可免于比较。遍历 map 是必须的,速度也肯定很快,redis 操作这里使用 hmset 效率比单个 set 要高(猜测)
    a7a2
        11
    a7a2  
       Jun 22, 2018
    @sakudie
    记得 遍历+清空 map 前要加锁,写最后浏览数据到 map 建议通过 mq 完成,遍历 map 数据写 redis 也 mq。
    这样保障单服务器每秒 pv 上万的时候不至于在 每当遍历 map 时候卡住一下,因为遍历+清空 map 前有一个锁 这样才能保证每一个数据不丢失
    julyclyde
        12
    julyclyde  
       Jun 23, 2018
    zrange 速度很慢的
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   5419 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 56ms · UTC 02:24 · PVG 10:24 · LAX 19:24 · JFK 22:24
    ♥ Do have faith in what you're doing.