V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
luxinfl
V2EX  ›  程序员

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

  •  
  •   luxinfl · 2021 年 10 月 26 日 · 5268 次点击
    这是一个创建于 1553 天前的主题,其中的信息可能已经有所发展或是发生改变。
    接口逻辑中会调用 6,7 次外部接口查询数据,然后再把结果汇总。现在用的是 parallelStream 来分别调用这几个外部接口,但是效果貌似不太好。还有什么其他方法可以并行调用的?
    第 1 条附言  ·  2021 年 10 月 28 日
    之前用的 list.parallel.xxx 没有用自定义 ForkJoinPool ,改成自定义线程池后,貌似变好了些
    30 条回复    2021-10-29 10:31:04 +08:00
    pushyzheng
        1
    pushyzheng  
       2021 年 10 月 26 日
    Reactor 挺适合这种场景的
    Jooooooooo
        2
    Jooooooooo  
       2021 年 10 月 26 日
    并行调用耗时就是最慢的那个接口, 这个角度没啥可优化的点了.
    luxinfl
        3
    luxinfl  
    OP
       2021 年 10 月 26 日
    @pushyzheng 有点太复杂了,不太适合吧。我应用场景就是并发调用接口

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

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

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

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

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

    可以看一下这个,前段无意中发现的。
    还没仔细看,貌似不错。
    jorneyr
        24
    jorneyr  
       2021 年 10 月 28 日
    CompletionService 或者 CompletableFuture 挺好用的,还可以自己传入 ThreadPoolExecutor
    snappyone
        25
    snappyone  
       2021 年 10 月 28 日
    p95 要到 50ms , 你先确定下你依赖的那几个接口能到这个速度吗
    luxinfl
        26
    luxinfl  
    OP
       2021 年 10 月 28 日
    @hingbong 项目里面真的好多 paralleStream 都没有自定义线程池。每个 parallel 都自定义一个是不是不太好
    @Vegetable 奇怪的是,每个并发流时间都不高,但是最终却很高,怀疑是用了共享线程池的缘故
    @WispZhan @aeiou520 @urzz 我用的 CompletableFuture 然后自定义线程池,但是用了 get()方法,感觉就和 Future 差不多的样子
    JadeLove
        27
    JadeLove  
       2021 年 10 月 28 日
    @luxinfl #26 原理是差不多的,都是异步同时请求接口,而不是串行。只不过这种方式可以将任务丢进线程池,而不是每次 new 线程跑。
    不过这种方式是否能满足你需求也是母鸡的。。毕竟这种聚合接口的耗时要看你依赖接口的
    billly
        28
    billly  
       2021 年 10 月 29 日
    之前看过 linkedin/parseq ,看起来还行,没用过
    luxinfl
        29
    luxinfl  
    OP
       2021 年 10 月 29 日 via Android
    @billly 现在改用 CompletableFuture 试试会不会好,实际用起来,感觉并发流不太好。
    KuroNekoFan
        30
    KuroNekoFan  
       2021 年 10 月 29 日
    试试 nodejs(
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   Solana   ·   3475 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 10:55 · PVG 18:55 · LAX 02:55 · JFK 05:55
    ♥ Do have faith in what you're doing.