V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
typ1805
V2EX  ›  问与答

一天大概会生成七八千量的订单数据,逐一去调用第三方支付接口支付。已有逻辑是使用定时任务同步执行的,每 5 秒执行一次,需要执行几个小时才能完成。怎么改造一下能快速处理完?

  •  
  •   typ1805 · 2021-04-02 13:55:42 +08:00 · 3672 次点击
    这是一个创建于 1365 天前的主题,其中的信息可能已经有所发展或是发生改变。
    42 条回复    2021-04-03 14:16:49 +08:00
    KouShuiYu
        1
    KouShuiYu  
       2021-04-02 14:16:43 +08:00
    改成多个请求接力执行
    KouShuiYu
        2
    KouShuiYu  
       2021-04-02 14:20:27 +08:00
    之前写过一个多文件上传,设置好最大同时上传的数量,每当有一个上传完成自动开启下一个上传任务
    wantooo
        3
    wantooo  
       2021-04-02 14:25:33 +08:00
    对方的支付接口很耗时吗,你 iob 拉起来发给多个线程执行呗
    rylei
        4
    rylei  
       2021-04-02 14:25:56 +08:00
    这种用消息队列生成之后直接调支付不好吗?
    ch2
        5
    ch2  
       2021-04-02 14:29:10 +08:00 via iPhone
    Python 用 grequests,一口气支付 1000 个订单,当然只要你胆子大就可以
    typ1805
        6
    typ1805  
    OP
       2021-04-02 14:31:46 +08:00
    @ch2 用的是 Java
    typ1805
        7
    typ1805  
    OP
       2021-04-02 14:32:19 +08:00
    @rylei 嗯嗯,想着是用消息队列
    Dimomo
        8
    Dimomo  
       2021-04-02 14:32:54 +08:00
    并发请求不行吗?
    typ1805
        9
    typ1805  
    OP
       2021-04-02 14:33:23 +08:00
    @wantooo 调用的三方支付比较多,有的比较耗时
    ch2
        10
    ch2  
       2021-04-02 14:34:44 +08:00 via iPhone
    @typ1805 java 应该也有对应的网络库,批量发送请求的那种,不用一个一个等
    qiayue
        11
    qiayue  
       2021-04-02 14:34:54 +08:00
    先看执行一次请求需要耗时多久,一般 200 毫秒内,那么 1 秒钟就可以请求 5 次。
    实际上你 1 秒钟可以请求超过 5 次,只要对方没有限制。

    最好的办法然是,用队列。
    如果还想用定时任务,那么可以改为 1 秒一次,然后每次取 5 条订单出来,同时发 5 个请求,或者发一个请求,等返回结果后再发下一个请求。

    注意要防止重入,举例第一次你取出来 5 条是 1,2,3,4,5,结果你程序处理到第 4 条时,下一秒又被取出来 5 条是 5,6,7,8,9,那么 5 就有可能被对方处理 2 次。
    keepeye
        12
    keepeye  
       2021-04-02 14:39:40 +08:00
    用 go 就很好解决了。其他也可以用队列+多进程方式处理
    eason1874
        13
    eason1874  
       2021-04-02 14:41:46 +08:00
    看对方 API 频率限制,按 90%最大并发去提交请求,再慢也没办法了。
    whileFalse
        14
    whileFalse  
       2021-04-02 14:44:26 +08:00
    为啥要攒起来逐一调用?请求来了实时调用不行吗?
    Kilerd
        15
    Kilerd  
       2021-04-02 14:48:30 +08:00
    如果对方没有 API 调用限制,异步一梭子,分分钟搞定。
    typ1805
        16
    typ1805  
    OP
       2021-04-02 14:50:12 +08:00
    @whileFalse 业务是批量导入数据,系统自动生产订单入库(状态为未支付),再从数据库读取数据进行支付,更新状态。
    typ1805
        17
    typ1805  
    OP
       2021-04-02 14:50:51 +08:00
    @qiayue 感谢,打算用队列干
    sarices
        18
    sarices  
       2021-04-02 14:53:10 +08:00
    为何不并发去处理呢,数据导到队列,并发几个去处理
    Jooooooooo
        19
    Jooooooooo  
       2021-04-02 14:56:17 +08:00
    并发的搞啊, 不同订单是独立的.
    zw1one
        20
    zw1one  
       2021-04-02 14:57:03 +08:00
    每 5 秒执行一次,一次执行一条数据?
    WangRicky
        21
    WangRicky  
       2021-04-02 14:59:36 +08:00   ❤️ 1
    分通道多个任务去处理,比如按照订单最后一位,那么就会提升 10 倍,或者对订单取模型,分割的方法有很多,这样不用引入新的中间件,而且对数据的进度,成功情况有更好的掌握
    hxndg
        22
    hxndg  
       2021-04-02 15:01:59 +08:00
    典型的批处理任务?
    fiypig
        23
    fiypig  
       2021-04-02 16:02:34 +08:00
    推荐用 Go
    AngryPanda
        24
    AngryPanda  
       2021-04-02 16:03:49 +08:00
    这种支付过程是不需要用户参与的吗?
    daimameiwenti
        25
    daimameiwenti  
       2021-04-02 16:17:10 +08:00
    你用 queue 队列处理订单,一个个处理,OK 的就移除队列,不 OK 的就继续 offer
    zw1one
        26
    zw1one  
       2021-04-02 16:18:55 +08:00
    1 、如果你要改动小的话,就在处理的地方加个线程池,多设置几个线程同时做支付发送就好了,注意 oom 问题。
    2 、如果要改一改架构,上个 mq 提升系统可用性的话,我大概设计了个架构。
    https://www.processon.com/view/link/6066cde95653bb5ceafdc638
    wsbnd9
        27
    wsbnd9  
       2021-04-02 16:40:13 +08:00
    串行 变成 并行调度 跟语言就没啥关系了
    tcsky
        28
    tcsky  
       2021-04-02 16:56:53 +08:00
    你这个不是常规支付接入吧, 是客户下单后用自己账号代付么?多准备几个账号
    WhereverYouGo
        29
    WhereverYouGo  
       2021-04-02 17:34:43 +08:00
    @zw1one #26 牛逼啊 [赞]
    cpstar
        30
    cpstar  
       2021-04-02 17:40:45 +08:00
    为什么不说说为什么已有逻辑设定 5 秒钟搞一次,
    5*8000=40000/3600=11.111 ,那必然半天都在处理订单了。
    我只想知道当初是哪个~哔~设计的这个逻辑。
    cpstar
        31
    cpstar  
       2021-04-02 17:41:41 +08:00
    换句话讲,能保证每一个单子 5 秒钟能处理完?如果没有处理完的,下一个单子怎么办?
    这特么没学过边界测试吧。。。
    corningsun
        32
    corningsun  
       2021-04-02 18:31:39 +08:00
    用阻塞队列就好啦
    一个线程捞任务到队列,如果队列满了就等待
    再搞一个消费线程池,直接从队列取,队列满了就等待。(需要控制消费线程池的大小,保证不把支付接口压垮就好)
    corningsun
        33
    corningsun  
       2021-04-02 18:33:34 +08:00
    修正下:再搞一个消费线程池,直接从队列取,队列空了就等待
    arvinsilm
        34
    arvinsilm  
       2021-04-02 20:08:33 +08:00
    定时任务一般是一次取出全部未执行的数据去执行,没有未执行的数据则等待下次执行。不是每次只取一条数据。。。。。
    pcbl
        35
    pcbl  
       2021-04-02 20:28:37 +08:00 via Android
    平均 10 秒一个新订单,5 秒去执行一次,可以接受,既不会大量积压也不会频繁请求
    pcbl
        36
    pcbl  
       2021-04-02 20:33:32 +08:00 via Android
    不更改原有逻辑不增加中间功能的情况下可以把 5 秒改成一秒,每间隔一秒钟就去获取一个最早生成的未处理的订单,添加一个处理中标记,执行完成后标记为已处理
    dzdh
        37
    dzdh  
       2021-04-02 20:37:33 +08:00
    @typ1805 java 不是有 threadpool 么。
    stardust21
        38
    stardust21  
       2021-04-02 21:05:28 +08:00
    Java 的话直接用固定数量的线程池解决?
    tjq
        39
    tjq  
       2021-04-02 22:38:02 +08:00 via iPhone
    可以试试 PowerJob 这个任务调度框架,支持 MapReduce 分布式计算,很符合你的场景。
    hahasong
        40
    hahasong  
       2021-04-03 00:14:34 +08:00
    开个 threadpool 不就行了 试出 api 的极限 设置一个 80%的大小
    typ1805
        41
    typ1805  
    OP
       2021-04-03 14:16:19 +08:00
    @zw1one 感谢
    typ1805
        42
    typ1805  
    OP
       2021-04-03 14:16:49 +08:00
    @tjq 感谢
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5541 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 36ms · UTC 06:38 · PVG 14:38 · LAX 22:38 · JFK 01:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.