Java 如何设计频繁 HTTP 请求(至少 13w 次)的统计程序? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
EdwardLee
V2EX    问与答

Java 如何设计频繁 HTTP 请求(至少 13w 次)的统计程序?

  •  
  •   EdwardLee 2019-04-19 10:51:47 +08:00 5021 次点击
    这是一个创建于 2374 天前的主题,其中的信息可能已经有所发展或是发生改变。

    1.场景描述
    现有基础数据 13w 条,需循环通过第三方 HTTP 接口获取历史数据进行分析统计,意味着要发生 13w 次 HTTP 请求。接口请求速度还比较慢,平均每次请求需要 1s,如果在单线程的情况下至少需要 36 个小时,目前我设计的是使用多线程每 3w 条作为一个任务进行请求,目前的消耗时间大概能减少到 16 小时左右,但效率还是太低了,有没有大佬有更好的解决方案的?求 Help!!

    2.部署环境
    系统:CentOS7

    配置:单 CPU 双核

    49 条回复    2019-04-22 11:21:43 +08:00
    gaius
        1
    gaius  
       2019-04-19 11:04:25 +08:00
    1s 是网络问题还是对方处理的比较慢?
    EdwardLee
        2
    EdwardLee  
    OP
       2019-04-19 11:10:09 +08:00
    @gaius 对方处理慢
    EdwardLee
        3
    EdwardLee  
    OP
       2019-04-19 11:14:53 +08:00
    @gaius 请问您觉得在不减少 HTTP 请求次数的情况下,我这边还有什么更好的处理方式吗?
    2kCS5c0b0ITXE5k2
        4
    2kCS5c0b0ITXE5k2  
       2019-04-19 11:16:59 +08:00 via iPhone
    @EdwardLee 感觉没啥办法。。1s 太慢了
    peyppicp
        5
    peyppicp  
       2019-04-19 11:18:47 +08:00
    ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(100, 200,
    10, TimeUnit.MINUTES, new ArrayBlockingQueue<>(100),
    new NamedThreadFactory("trade-thread-", true), new ThreadPoolExecutor.CallerRunsPolicy());
    然后你主线程 for 循环提交 runnable 或者 callable 任务就完事了。200 条线程应该可以了
    EdwardLee
        6
    EdwardLee  
    OP
       2019-04-19 11:22:46 +08:00
    @emeab 是啊,太慢了,扎心
    orangeade
        7
    orangeade  
       2019-04-19 11:23:58 +08:00 via Android   1
    换 golang 然后无脑开 goroutine ?
    EdwardLee
        8
    EdwardLee  
    OP
       2019-04-19 11:28:13 +08:00
    @peyppicp 200 个线程会不会出问题啊?我试试。多线程不太会用,我是参照网上说的 IO 密集型任务应设置线程数为核心数的两倍,HTTP 请求应该属于网络 IO 吧。
    EdwardLee
        9
    EdwardLee  
    OP
       2019-04-19 11:29:36 +08:00
    @orangeade 这...
    xuwenping
        10
    xuwenping  
       2019-04-19 11:33:05 +08:00 via Android
    对方能不能也使用多线程?
    HuHui
        11
    HuHui  
       2019-04-19 11:33:25 +08:00 via Android
    让对方提供批量查询接口
    peyppicp
        12
    peyppicp  
       2019-04-19 11:42:04 +08:00   1
    @EdwardLee IO 密集型,线程数可以开到很高。CPU 密集型,线程数开到核心数。

    如果对方接口允许,我觉得开 500 线程都行
    honeycomb
        13
    honeycomb  
       2019-04-19 11:45:53 +08:00 via Android
    @EdwardLee spring webflux ?
    honeycomb
        14
    honeycomb  
       2019-04-19 11:47:23 +08:00 via Android
    @EdwardLee 楼主遇到的情况是每个线程大部分时间在等回复,这个意义上再多开一些(三五百个)也成。
    gz911122
        15
    gz911122  
       2019-04-19 11:52:58 +08:00
    用 netty 异步回调
    这种性能主要是卡在网络 io 的情况下用异步再合适不过了
    gz911122
        16
    gz911122  
       2019-04-19 11:53:36 +08:00
    @gz911122 或者就是楼上说的那样,往死里开线程
    feiyuanqiu
        17
    feiyuanqiu  
       2019-04-19 11:56:36 +08:00 via Android
    对方一个请求都能处理一秒,开几百个线程的不一下把人家服务器打死?
    问问看能不能提供批量查询接口吧,估计没戏
    az422
        18
    az422  
       2019-04-19 12:13:45 +08:00 via Android
    异步 httpclient,如 Apache 那个 httpasync 或者 vertx.client (多个实例),并设置 keepalive (双方)
    当然还是批量接口靠谱
    EdwardLee
        19
    EdwardLee  
    OP
       2019-04-19 12:25:19 +08:00
    @xuwenping
    @HuHui
    @feiyuanqiu 就是坑在这,第三方暂时不可控,增加批量接口行不通
    EdwardLee
        20
    EdwardLee  
    OP
       2019-04-19 12:27:46 +08:00
    @peyppicp 好的,谢谢,我先试试,有结果了我再来反馈
    rrfeng
        21
    rrfeng  
       2019-04-19 12:30:11 +08:00 via Android
    你算一下对方最多能提供每秒几个
    然后就写自己的并发量

    取决于对方而不是自己
    EdwardLee
        22
    EdwardLee  
    OP
       2019-04-19 12:30:45 +08:00
    @honeycomb 是的,瓶颈就卡在请求等待这里,我先试试多开线程看下结果
    EdwardLee
        23
    EdwardLee  
    OP
       2019-04-19 12:32:12 +08:00
    @gz911122
    @az422 异步的方式是不是也类似于多线程。需要取决于第三方接口的承受能力?
    lhx2008
        24
    lhx2008  
       2019-04-19 12:51:03 +08:00 via Android
    异步可以一下打 13 万条请求出去,对方回数据,操作系统会自动保存,然后程序可以慢慢拿返回结果。但是对方的服务器是妥妥的挂了。。

    所以先压测一下,看看同时打多少条出去
    MoHen9
        25
    MoHen9  
       2019-04-19 13:00:05 +08:00 via Android
    数据量有多大,返回怎么那么慢?还有为什么不能自定义获取条数?
    JadeV
        26
    JadeV  
       2019-04-19 13:12:37 +08:00 via iPhone
    对接的蛋疼事儿,并发量只能看对方接口了。。之前也碰到过,并发请求多了被对方拉黑了。。。
    az422
        27
    az422  
       2019-04-19 13:18:33 +08:00
    @EdwardLee 是取决于对方承受能力,但跟多线程本质不同,多线程本质会阻塞的,异步不会,在对方承受能力下能增大你这边的吞吐量。
    `我设计的是使用多线程每 3w 条作为一个任务进行请求,目前的消耗时间大概能减少到 16 小时左右` 像你这样设计,在对方 1s 内没有返回内你的线程是被阻塞不能干其他事的,完全浪费了性能。130000/(16*3600)约 2.25 ,相当于你 1s 才 3 个请求?要是对方能力真这样当我没说。。。 假设对方最大 qps=10000, 你可以开 10000 线程, (但是你单 CPU 双核 = =), 这种情况下还是用异步 IO 能压榨对方性能
    misaka19000
        28
    misaka19000  
       2019-04-19 13:22:45 +08:00 via Android
    异步操作
    33and66
        29
    33and66  
       2019-04-19 13:58:08 +08:00
    这种数据 建议生成 txt 文件 然后通过文件内容建议直接做
    方法很土 但是很实用
    我们现在和银行每天上千万的数据对账就是这么干
    liujan
        30
    liujan  
       2019-04-19 15:37:55 +08:00
    如果是对方数据加工处理比较慢的话,是不是可以先让他每天 定时离线处理好了数据,然后你再过去拉处理后的数据?
    whp1473
        31
    whp1473  
       2019-04-19 15:51:58 +08:00
    每天根据你的数据定时获取对方数据,将获取的数据保存起来,用户查询时查自己库,然后缓存起来。
    mritd
        32
    mritd  
       2019-04-19 15:57:14 +08:00 via iPhone
    可能这个回答不对路,但是如果这种需要大并发处理的我真的会上 golang 写,因为这样基本不需要带脑子....
    xdlucky
        33
    xdlucky  
       2019-04-19 15:57:40 +08:00
    联系对方直接买数据
    xzg
        34
    xzg  
       2019-04-19 17:44:51 +08:00
    看你响应结果是否需要,不需要就搞异步多线程。如果需要响应结果那就只能等待 1s,尝试开启多线程,实在不行部署多个服务并行发
    Yourshell
        35
    Yourshell  
       2019-04-19 20:39:07 +08:00
    寄 U 盘吧
    EdwardLee
        36
    EdwardLee  
    OP
       2019-04-22 09:49:17 +08:00
    @rrfeng
    @lhx2008 好的,感谢建议
    EdwardLee
        37
    EdwardLee  
    OP
       2019-04-22 09:52:26 +08:00
    @MoHen9 数据量不算大,从一条到两三千条 JSON 字符串不等,应该是数据需要处理比较慢吧
    EdwardLee
        38
    EdwardLee  
    OP
       2019-04-22 09:52:52 +08:00
    @CoSpLi 拉黑,这么过分的吗,Hahh
    EdwardLee
        39
    EdwardLee  
    OP
       2019-04-22 09:55:59 +08:00
    @az422 目前使用 30 个线程,处理时间已经减少到 3.5 小时,偶尔会有 HTTP 请求超时的情况出现。我再观察一下,感谢您的建议
    EdwardLee
        40
    EdwardLee  
    OP
       2019-04-22 09:56:52 +08:00
    @misaka19000 很多都是建议异步操作的,没怎么了解过,我试试看。感谢建议
    EdwardLee
        41
    EdwardLee  
    OP
       2019-04-22 10:00:46 +08:00
    @33and66 如果有现成的数据文件是可行,但是在第三方不改动的情况下,暂时也没有其他方式可以获取数据来源,还是得调接口请求
    EdwardLee
        42
    EdwardLee  
    OP
       2019-04-22 10:02:11 +08:00
    @liujan 第三方那边不可控,还是得我这边想办法优化一下。感谢建议
    EdwardLee
        43
    EdwardLee  
    OP
       2019-04-22 10:07:06 +08:00
    @whp1473 您建议的这种方式可能不太适合我这个场景,应该适合那种一次性响应数据量比较大的情况。目前接口并非因为响应数据量大而缓慢,所以即使定时获取也无法迈过多次 HTTP 请求这道坎,还是得想办法提高 IO 利用率
    EdwardLee
        44
    EdwardLee  
    OP
       2019-04-22 10:08:43 +08:00
    @mritd 好多大佬说 golang 的,不带脑子都行,那么强大的吗,hah
    mritd
        45
    mritd  
       2019-04-22 10:52:44 +08:00
    @EdwardLee #44 怎么说呢,就是相对于 java 开并发 心智负担小得多,基本上不用带脑子
    EdwardLee
        46
    EdwardLee  
    OP
       2019-04-22 10:58:14 +08:00
    @Yourshell 每天寄 U 盘也挺累的,手动狗头
    EdwardLee
        47
    EdwardLee  
    OP
       2019-04-22 11:00:11 +08:00
    @xzg 业务场景是不需要实时响应的,异步应该是可行的。暂时不太了解异步,尝试了下多线程,效果还是很明显的,已经能够满足需求了。
    EdwardLee
        48
    EdwardLee  
    OP
       2019-04-22 11:17:22 +08:00
    目前情况:
    1. 单线程:耗时约 36 小时,请求稳定(效率极低)
    2. 分批 3w 数据 /线程,共 5 个线程:耗时约 16 小时,请求较稳定 (效率略低)
    3. 固定 30 个线程:耗时约 3.5 小时,偶有 HTTP 请求超时(效率已经能够满足,需解决部分超时异常)
    4. 固定 100 个线程:测试过程因请求超时案例过多,暂不予考虑,所以未计耗时

    总结:
    我的业务场景属于网络 IO 密集型任务,时间基本都消耗在等待 HTTP 请求的响应,所以多线程请求还是效果很明显的,至于固定多少线程效率最高我无法确定,纯手工尝试,有科学测量方式的小伙伴麻烦指教一下。30 线程数已经能够满足业务需求,暂以项目交付为先,关于各位 V 友的建议比如异步请求之类的有空的时候再尝试。

    在此感谢各位 V 友的不吝赐教
    JadeV
        49
    JadeV  
       2019-04-22 11:21:43 +08:00 via iPhone
    @EdwardLee 被当做恶意爬虫了。那会儿写还真没考虑过这么多
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2812 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 06:31 PVG 14:31 LAX 23:31 JFK 02:31
    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