V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
chenfang
V2EX  ›  程序员

redis 控制用户频次问题

  •  
  •   chenfang · 19 天前 · 1978 次点击

    redis 如何限制用户频次?

    目前的是 tomcat 集群,然后会有多个任务 id,同时需要限制用户 id 频次,比如 每人每天展示 5 次

    现在的 redis 结构限制频次会丢一些 (第一个图)

    现在要改成精准控制频次,目前我想到的方案是 (第二个图)

    这个方案倒是可以满足需求,有两个不足的点

    1. 因为涉及到多个任务 id,就会使用多个 hash,然后导致任务 id 和用户 id(key)过多,这样是不是会占用一倍的 redis 内存空间? 多个相同的用户 id 如何才能让它存一份数据,其他的用指针?

    2. 之前没用过 lua 脚本,这个性能如何?

    图 1 图 2

    22 条回复    2024-11-12 19:28:49 +08:00
    gongguowei02
        1
    gongguowei02  
       19 天前   ❤️ 1
    为什么不考虑使用 Redis 的 INCR+ EXPIRE 来实现限流功能呢?
    admol
        2
    admol  
       19 天前
    参考如何设计一个分布式限流器: https://jingling.im/posts/design-a-rate-limiter
    ddonano
        3
    ddonano  
       19 天前
    Redisson
    chenfang
        4
    chenfang  
    OP
       19 天前
    @gongguowei02 是个好方法, 多个用户 id 和任务 id 增加内存占用 这个貌似还是解决不了
    chenfang
        5
    chenfang  
    OP
       19 天前
    @ddonano 我们就是用的 redisson...
    chenfang
        6
    chenfang  
    OP
       19 天前
    @admol 我去看看这个文章
    airqj
        7
    airqj  
       18 天前
    @chenfang #4 想知道用户量有多大
    gongguowei02
        8
    gongguowei02  
       18 天前
    @admol 大佬 merge 我的 pr 了,满意
    nice2cu
        9
    nice2cu  
       18 天前
    你目的是想 获取 map 、map 值变更 这两步做成原子操作吗
    lua 脚本应该可以的吧
    chenfang
        10
    chenfang  
    OP
       18 天前
    @nice2cu 可以变结构

    ,map 中的 map 如果用 lua 涉及到第二个 map 序列话问题,再有就是 lua 脚本会锁整个 redis 实例

    这两点来说 两个 map 嵌套不是一个好的方案,如果要精准限制频次的话
    Goooooos
        11
    Goooooos  
       18 天前
    key: 用户 id_任务 id_日期

    incr key ,incr 如果结果=1 ,就执行 expire 。

    lua 脚本都没啥必要
    admol
        12
    admol  
       18 天前
    @gongguowei02 谢谢,不是大佬,只是老,有问题可以随时提
    edward1987
        13
    edward1987  
       18 天前
    hash_{任务 id}_{日期}
    key 用户 id
    你这个需求不用保存历史记录的吧,每天删一删之前的,根本不用考虑内存问题了
    edward1987
        14
    edward1987  
       18 天前
    或者 hash_{用户 id}_{日期}
    key 任务 id
    这种更推荐,因为大表按理来说更占内存,也满足你 [多个相同的用户 id 如何才能让它存一份数据] 这个需求
    chenfang
        15
    chenfang  
    OP
       18 天前
    @edward1987 #14 大表按理来说更占内存 能解释一下这个么? 另外什么是大表?
    chenfang
        16
    chenfang  
    OP
       18 天前
    @Goooooos 目前确实在在考虑如何不用 lua 毕竟我感觉对整体性能有不小的影响
    edward1987
        17
    edward1987  
       18 天前
    @chenfang 指的 hash 表,大表就是 key 很多的表,也就是按 任务 id 做表名的表,因为扩容的时候是乘以 2 这样去扩容的,所以会占用更多内存。
    archxm
        18
    archxm  
       18 天前
    分桶如何?根据 id 取模,然后分配到特定服务器来处理。非陪到的服务器,从 redis 取数据。判断频次。单台机器,就好做数据冲突处理了吧
    archxm
        19
    archxm  
       18 天前
    @archxm 单台机器,同样对 id 做取模分桶,用线程池解决。单个线程处理单次请求。
    chenfang
        20
    chenfang  
    OP
       18 天前
    @archxm #18 忘记说了 现在 redis 是集群的 使用 hash 是需要分桶 如果不是 hash 那就会分到不同的实例了
    archxm
        21
    archxm  
       18 天前
    @chenfang #20 不管 redis 是啥,你后台服务器几台呢?如果多台,就先按用户 id 分桶,用户肯定每次固定分配到一台服务器。
    然后用户分到一台服务器后,你的服务器是多线程或多进程吗?然后你可以在服务器上设置线程池或进程池,来定死用户到固定线程(或进程)上来处理,这样不会发生冲突。不用管具体存到 redis 哪个分片
    ychost
        22
    ychost  
       18 天前
    疲劳度控制问题是吧,设置好数据过期时间应该费不了多少内存
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2632 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 04:00 · PVG 12:00 · LAX 20:00 · JFK 23:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.