redis 统计在线人数的疑问 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
sakudie
V2EX    Redis

redis 统计在线人数的疑问

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

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

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

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

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

    那么我直接在 redis 中维护一个 cur_online_user_numkey, 每当 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     Solana     4078 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 159ms UTC 04:16 PVG 12:16 LAX 21:16 JFK 00:16
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86