一个聚合接口,如何才能优化时延 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
请不要在回答技术问题时复制粘贴 AI 生成的内容
luxinfl

一个聚合接口,如何才能优化时延

  •  
  •   luxinfl Oct 26, 2021 5414 views
    This topic created in 1644 days ago, the information mentioned may be changed or developed.
    接口逻辑中会调用 6,7 次外部接口查询数据,然后再把结果汇总。现在用的是 parallelStream 来分别调用这几个外部接口,但是效果貌似不太好。还有什么其他方法可以并行调用的?
    Supplement 1    Oct 28, 2021
    之前用的 list.parallel.xxx 没有用自定义 ForkJoinPool ,改成自定义线程池后,貌似变好了些
    30 replies    2021-10-29 10:31:04 +08:00
    pushyzheng
        1
    pushyzheng  
       Oct 26, 2021
    Reactor 挺适合这种场景的
    Jooooooooo
        2
    Jooooooooo  
       Oct 26, 2021
    并行调用耗时就是最慢的那个接口, 这个角度没啥可优化的点了.
    luxinfl
        3
    luxinfl  
    OP
       Oct 26, 2021
    @pushyzheng 有点太复杂了,不太适合吧。我应用场景就是并发调用接口

    @Jooooooooo 实现不太一样吧,有时候还会碰到从连接池获取连接超时。。
    luxinfl
        4
    luxinfl  
    OP
       Oct 26, 2021
    主要是测试压测有个时延要求,p95 要到 50ms ,但是这个服务需要调用多个外部接口。没什么优化经验。。用了 parallelStream ,增大的连接池的 defaultMaxPerRoute 。效果不是太好,就在想是不是 parallelStream 有什么缺陷
    JadeLove
        5
    JadeLove  
       Oct 26, 2021
    建议不要用 parallelStream ,ForkJoinPool 是全局共用的。。
    luxinfl
        6
    luxinfl  
    OP
       Oct 26, 2021
    @urzz 如果定义那个 ForkJoinPool 有啥问题么
    JadeLove
        7
    JadeLove  
       Oct 27, 2021
    你如果可以保证没有别人用 parallelStream ,那可以。要不然这种在 parallel 中进行 io 调用的,是可能会导致阻塞的

    这种情况下,可以尝试自己定义线程池,然后用 CompletableFuture.supplyAsync ,配合 CompletableFuture.allOf(...).join() 等待线程结束获取结果。建议改完后压一波试试
    FarAhead
        8
    FarAhead  
       Oct 27, 2021
    Fibers + Channel
    VHacker1989
        9
    VHacker1989  
       Oct 27, 2021 via Android
    分布式
    aeiou520
        10
    aeiou520  
       Oct 27, 2021
    CompletableFuture?
    siweipancc
        11
    siweipancc  
       Oct 27, 2021 via iPhone
    多线程加阻塞同步器,怕并发太大可以塞信号量
    nl101531
        12
    nl101531  
       Oct 27, 2021 via iPhone
    @luxinfl 这个用的是 forkjoin 公共线程池,你系统用的多,就可能排队阻塞
    Aliberter
        13
    Aliberter  
       Oct 27, 2021
    自定义线程池+CountDownLatch ,说到底总耗时还是取决于最慢的那个接口的响应时间。
    wolfie
        14
    wolfie  
       Oct 27, 2021
    可以自定义 ForkJoinPool

    forkJoinPool.execute(e -> {
    someList.parallelStream()
    })
    hingbong
        15
    hingbong  
       Oct 27, 2021
    用 parallelStream 都会自定义 ForkJoinPool 吧,问题不大
    Vegetable
        16
    Vegetable  
       Oct 27, 2021
    先做好日志确认一下,确认是否「总用时~=耗时最长的外部服务」,如果是的话,就没什么优化的空间了,如果不是再排查吧,按理说这么做没问题。
    Chinsung
        17
    Chinsung  
       Oct 27, 2021
    查数据就是并发+缓存,没啥别的办法。
    8355
        18
    8355  
       Oct 27, 2021
    除非提前调用直接查 不然并行调用还是会以最慢的接口时间
    如果因为网络或者机器位置的关系找运维给你加代理网关会好很多
    xiang0818
        19
    xiang0818  
       Oct 27, 2021
    这个没办法解决的,外部接口的调用时间在于别人服务器对你的响应时间。
    night98
        20
    night98  
       Oct 27, 2021
    提前聚合
    WispZhan
        21
    WispZhan  
       Oct 27, 2021
    最直接的解 CompletableFuture ,这玩意写起来贼恶心。
    比较优雅的解 Kotlin 协程
    makdon
        22
    makdon  
       Oct 27, 2021
    无解,就算你的六七个接口都没有互相依赖,全并行一起请求外部,
    访问外部来回 rtt 也是要耗时的,外部接口再稍微慢一点你的 p95 就到不了 50ms 了
    除非把机房搬外部接口提供方机房旁边,不然跨一下地域轻轻松松就过 50ms 了,不过你这个 case 还有 6 ,7 次外部接口,也不知道是不是同一个提供商,不是的话机房都搬不动了

    随便搜了一下时延的经验值
    腾讯云:

    北京到上海:38ms
    上海到广州:40ms
    北京到广州:53ms
    az402
        23
    az402  
       Oct 28, 2021
    <groupId>com.jd.platform</groupId>
    <artifactId>asyncTool</artifactId>
    <version>1.4.1-SNAPSHOT</version>

    可以看一下这个,前段无意中发现的。
    还没仔细看,貌似不错。
    jorneyr
        24
    jorneyr  
       Oct 28, 2021
    CompletionService 或者 CompletableFuture 挺好用的,还可以自己传入 ThreadPoolExecutor
    snappyone
        25
    snappyone  
       Oct 28, 2021
    p95 要到 50ms , 你先确定下你依赖的那几个接口能到这个速度吗
    luxinfl
        26
    luxinfl  
    OP
       Oct 28, 2021
    @hingbong 项目里面真的好多 paralleStream 都没有自定义线程池。每个 parallel 都自定义一个是不是不太好
    @Vegetable 奇怪的是,每个并发流时间都不高,但是最终却很高,怀疑是用了共享线程池的缘故
    @WispZhan @aeiou520 @urzz 我用的 CompletableFuture 然后自定义线程池,但是用了 get()方法,感觉就和 Future 差不多的样子
    JadeLove
        27
    JadeLove  
       Oct 28, 2021
    @luxinfl #26 原理是差不多的,都是异步同时请求接口,而不是串行。只不过这种方式可以将任务丢进线程池,而不是每次 new 线程跑。
    不过这种方式是否能满足你需求也是母鸡的。。毕竟这种聚合接口的耗时要看你依赖接口的
    billly
        28
    billly  
       Oct 29, 2021
    之前看过 linkedin/parseq ,看起来还行,没用过
    luxinfl
        29
    luxinfl  
    OP
       Oct 29, 2021 via Android
    @billly 现在改用 CompletableFuture 试试会不会好,实际用起来,感觉并发流不太好。
    KuroNekoFan
        30
    KuroNekoFan  
       Oct 29, 2021
    试试 nodejs(
    About     Help     Advertise     Blog     API     FAQ     Solana     5557 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 103ms UTC 03:46 PVG 11:46 LAX 20:46 JFK 23:46
    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