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

项目中使用 redis,再高并发下竟然遇到了这种问题,一年开发经验解决不了,来个大神看看。。

  •  
  •   Jekins · 2021-06-06 00:31:41 +08:00 · 5689 次点击
    这是一个创建于 1293 天前的主题,其中的信息可能已经有所发展或是发生改变。

    提交订单功能,判断当前用户有没有提交订单(订单创建成功会保存到 redis )。以下是伪代码,逻辑和提交订单是一样的,遇到的问题也是一样的,请求老牛解决!

    ConcurrencyTester tester = ThreadUtil.concurrencyTest(1000, () -> { Set<String> keys = redisTemplate.keys("key");//查询 redis 有没有这个 key,有就返回 key if (keys.size() > 0) { return; } System.out.println("我来插入到 redis"); //此处被执行多次 redisTemplate.opsForValue().set("key", "value"); });

    23 条回复    2021-06-28 18:52:31 +08:00
    Jooooooooo
        1
    Jooooooooo  
       2021-06-06 00:39:00 +08:00
    搜一下 setnx

    当然用 redis 做锁当发生故障时极小概率保障不了唯一性, 看你的需求了
    swulling
        2
    swulling  
       2021-06-06 00:52:41 +08:00
    一年开发经验,特别是做高并发,首先需要了解一个概念叫做并发冲突。

    查询 Key 是否存在 + 设定 Key 的 Value,这两步在你的实现里不是原子的。解决办法就是使用原子操作替代两步操作。
    ccde8259
        3
    ccde8259  
       2021-06-06 01:01:13 +08:00 via iPhone   ❤️ 2
    为什么不用 SETNX
    为什么不用 MULTI WATCH
    为什么不用 LUA SCRIPT
    Hurriance
        4
    Hurriance  
       2021-06-06 01:11:12 +08:00
    不嫌麻烦的话可以用 lua + 2 楼的方法
    jones2000
        5
    jones2000  
       2021-06-06 03:12:44 +08:00
    直接插入不覆盖的模式, 如果插入成功就说明是新订单, 插入失败就说明订单已存在。
    Addup
        6
    Addup  
       2021-06-06 03:16:36 +08:00
    用 lua 注意定时清理下脚本缓存, 这里有两个坑: 不然不断累积导致内存爆满, 建有 dts 的话从机也需要执行命令清脚本缓存, 脚本缓存过多时, 清除命令耗时过长可能导致 dts 连接异常.
    fewok
        7
    fewok  
       2021-06-06 04:17:45 +08:00
    咱们先说人话,你们交易业务,下单最高峰,秒杀最高峰的 TPS 是多少???
    jorneyr
        8
    jorneyr  
       2021-06-06 08:27:00 +08:00
    redisTemplate.keys("key");
    Java 代码在这里并发了,多个线程执行到这里时 key 不存在,则进行了多条插入。

    Redis 的单线程保证的是自己内部,Java 端的并发 Redis 处理不了。
    limuyan44
        9
    limuyan44  
       2021-06-06 09:21:31 +08:00
    对于并发而言,这种问题过于常识了,建议先找点相关的文章看看,这还是涉及钱的下单功能,这么搞迟早把自己坑死。
    szzadkk
        10
    szzadkk  
       2021-06-06 10:00:17 +08:00
    这个操作不是原子性的,肯定有问题,用 setnx 或者 lua 脚本
    ttyn
        11
    ttyn  
       2021-06-06 11:00:49 +08:00
    猜测你本意是用 Redis 做并发锁,防止订单重复提交。
    要理解你失败的原因,需要先了解 Redis 的原子操作,作为一年的开发经验,有点为难你。
    Redis 有个现成的东西,叫 Redlock,参考: https://blog.csdn.net/hanchao5272/article/details/99695360
    Jekins
        12
    Jekins  
    OP
       2021-06-06 11:05:58 +08:00
    @ccde8259 感谢分享经验
    Jekins
        13
    Jekins  
    OP
       2021-06-06 11:06:36 +08:00
    @ttyn 谢谢老哥,我只干了一年都还不到,之前确实没有碰到过这种情况。。
    Jekins
        14
    Jekins  
    OP
       2021-06-06 11:07:02 +08:00
    感谢楼上各位老哥!
    Jekins
        15
    Jekins  
    OP
       2021-06-06 11:14:14 +08:00
    @fewok 当前这个项目新开发的,没有什么并发,但是遇到了这个并发下单问题,也是以后要面对的。。
    pydiff
        16
    pydiff  
       2021-06-07 10:52:38 +08:00
    有点好奇,究竟是什么样的公司,敢让一个新手来做这种关键业务,如果 boom 了算谁的呢
    shimianxiang
        17
    shimianxiang  
       2021-06-07 13:44:21 +08:00
    建议直接 lua,还好扩展
    vgbhfive
        18
    vgbhfive  
       2021-06-07 14:44:45 +08:00 via Android
    lua 脚本或者 setnx 保证原子性
    wunsch0106
        19
    wunsch0106  
       2021-06-08 11:45:16 +08:00
    @pydiff 敢叫他上就敢写呗,boom 了肯定领导负责啊
    neptuno
        20
    neptuno  
       2021-06-11 14:54:52 +08:00
    原子操作,lua+redis 分布式锁,网上随便找个例子模仿写
    OV0
        21
    OV0  
       2021-06-16 18:06:59 +08:00
    分布式锁的套路:本地锁+分布式锁 + 数据库业务。
    DreamSpace
        22
    DreamSpace  
       2021-06-26 00:15:28 +08:00 via Android
    楼上说得很明白了,这里在补充一点,如果用 redis.keys(key)做模糊匹配,效率极低,而且会阻塞其他请求!!
    siweipancc
        23
    siweipancc  
       2021-06-28 18:52:31 +08:00 via iPhone
    keys? 真让人头大
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5388 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 07:45 · PVG 15:45 · LAX 23:45 · JFK 02:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.