Joezeo
V2EX  ›  问与答

求大神解答一下一个小白程序员的疑惑

  •  
  •   Joezeo · Aug 27, 2020 · 2300 views
    This topic created in 2261 days ago, the information mentioned may be changed or developed.

    今天跟我一位朋友讨论一个防止表单二次提交的问题,他是考虑用 redis,我的解决方案是在本地使用锁来保证请求在处理完成之前同一用户的其他请求会被忽略,代码如下:

    private static final Set<String> LOCK_SET = new CopyOnWriteArraySet<>();
    
    public String execute(){
    ...
        synchronized (this) {
            if (LOCK_SET.contains(uuid)) {
                return "failed";
            }
            LOCK_SET.add(uuid);
        }
    ...
    }
    

    然后就跟他杠上了,他的看法是当其他用户的请求来时会被锁住等待,用 redis 更快。
    而我的看法是这个问题用 redis 有点太大材小用了,我认为在这个情况下等待锁的时间是远远小于连接 redis 的开销的。
    有大神能帮忙解答一下吗,感激不尽。

    17 replies  •  2020-08-27 19:19:29 +08:00
    IGJacklove
    IGJacklove
    Aug 27, 2020
    1
    感觉 redis 不算大材吧...
    Joezeo
    Joezeo
    OP
    Aug 27, 2020
    2
    @IGJacklove 主要我是感觉这个没有必要用 redis..
    kop1989
    kop1989
    Aug 27, 2020
    3
    我没太读懂。
    redis 不是一个缓存技术么,只是作用于存储。

    对于接口黑名单而言(二次提交也是黑名单,只不过是持续时间很短),不管用什么技术存储黑名单,锁是一定要存在的吧,所以不管用不用 redis,读取黑名单这步骤依然是要队列执行的。
    kop1989
    kop1989
    Aug 27, 2020
    4
    所以你们的争论其实就是 new 对象和用 redis 来存储黑名单的区别?
    Immortal
    Immortal
    Aug 27, 2020
    5
    早起还没有前后端分离的时候 后端会在 form 里渲染一个 key 存在这个 key 并且和服务端一致才让提交
    现在前后端分离了 前端可以同样按这个思路 客户端自己维护这个 key
    这类解决方案 google 下很多的 用 redis 啥的有点夸张了
    Joezeo
    Joezeo
    OP
    Aug 27, 2020
    6
    @kop1989 emmm 差不多就是这个意思,我们争论的点就是在这个情况下有没有必要使用 redis 来进行存储
    Joezeo
    Joezeo
    OP
    Aug 27, 2020
    7
    @Immortal 好的,感谢(我也是觉得这个用 redis 有点夸张了)
    kop1989
    kop1989
    Aug 27, 2020
    8
    @Joezeo #6 如果我理解的没错的话,那优缺点就很明显了。
    直接 new 一个对象集合来存储是不可靠的,有可能被 web 容器的垃圾清理释放掉。
    redis 相对安全,但 redis 的效率比直接 add 进集合再 remove 肯定是要慢很多。

    但还是要强调下,这个话题和锁不锁无关,这种场景肯定是要有锁的,只不过 redis 是单线程,你不需要去操作锁而已。所以你同事说的啥“当其他用户的请求来时会被锁住等待”这个对 redis 也一样适用。
    IGJacklove
    IGJacklove
    Aug 27, 2020 via Android
    9
    @Joezeo 我感觉你锁接口比用 Redis 重的多,你的问题是单用户的重复提交,你的解决方案是锁全部人的提交。感觉你的问题不是更大吗?假如有一百个人的 200 个请求过来,你要做的就是拦住一百个人的后一百次重复提交,你的解决方案是锁了所有人的提交,这不是明显有问题吗?要是一百个人的一百次请求你根本不需要锁啊
    hahasong
    hahasong
    Aug 27, 2020
    10
    CSRF token 不香吗,提交一次就失效,不刷新页面再提交肯定失败
    013231
    013231
    Aug 27, 2020
    11
    如果服務進程不止一個,你的本地鎖要如何解決兩次請求落在兩個不同進程的問題?
    672795574
    672795574
    Aug 27, 2020
    12
    11 楼说的才是要解决的问题,你本地锁得保证这个用户的请求落到同一台机器上
    wysnylc
    wysnylc
    Aug 27, 2020
    13
    sync 在分布式下无用
    looplj
    looplj
    Aug 27, 2020
    14
    首先看是不是单服务器部署,再看用户量级以及请求量。
    单服务器部署,用户量级少,请求量少,可以放内存。
    opengps
    opengps
    Aug 27, 2020
    15
    推荐保留 redis,因为他可以集群内共享,扩展集群时候不用你额外改动代码
    byzf
    byzf
    Aug 27, 2020
    16
    目测你这个 add 再 remove 一下, LOCK_SET 大了受不了.

    redis 就是用来做这个的, 不算大材小用.
    Jooooooooo
    Jooooooooo
    Aug 27, 2020
    17
    这

    分布式的锁和内存里单机的锁没有可比性
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   2737 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 52ms · UTC 13:57 · PVG 21:57 · LAX 05:57 · JFK 08:57
    ♥ Do have faith in what you're doing.