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

面试碰到一个问题,搞不定

  •  
  •   luxinfl · 2020-12-16 22:00:43 +08:00 · 6452 次点击
    这是一个创建于 1198 天前的主题,其中的信息可能已经有所发展或是发生改变。
    比如说要调用 abcde 这五个微服务,调用 b 的前提是先调用 a,cde 没有这种顺序要求。最终数据要求整合。怎么才能让时延变小??
    44 条回复    2020-12-23 14:08:26 +08:00
    Yoock
        1
    Yoock  
       2020-12-16 22:10:13 +08:00
    waitgroup
    luxinfl
        2
    luxinfl  
    OP
       2020-12-16 22:15:02 +08:00
    @Yoock 有 java 的实现么
    fanyiaa
        3
    fanyiaa  
       2020-12-16 22:19:59 +08:00 via Android
    c#里用 task 很容易。java 不知道有什么简便方法
    Cbdy
        4
    Cbdy  
       2020-12-16 22:21:39 +08:00   ❤️ 4
    let resultA
    const [resultB, resultC, resultD, resultE] = await Promise.all([a().then(ra => { resultA = ra; return b() }), c(), d(), e()])
    Yoock
        5
    Yoock  
       2020-12-16 22:23:33 +08:00
    搜到一个 [CountDownLatch]( https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html)
    不太了解 Java,你看一下
    luxinfl
        6
    luxinfl  
    OP
       2020-12-16 22:27:55 +08:00
    我想说的不是 AQS 方面的东西。是侧重于 java 微服务相关的
    pkwenda
        7
    pkwenda  
       2020-12-16 22:45:45 +08:00
    比如 zuul 网关应该可以写 groovy 从注册中心获取微服务,先调用啊,并发调用 cde,代码整合
    kong 这种可以写 lua 插件
    是这个意思吧,不进行并发处理延时是一样的
    网关做 merge
    mango88
        8
    mango88  
       2020-12-16 23:49:08 +08:00
    可以用几个 future,然后用 CompletableFuture.allOf() ,等所有 future 完成再去组装数据
    xizismile
        9
    xizismile  
       2020-12-16 23:51:10 +08:00 via Android
    去看看 CompletableFuture 类
    hangszhang
        10
    hangszhang  
       2020-12-16 23:59:11 +08:00
    Java 的话, CompleteFuture 或者 RxJava 或者 Future
    DoctorCat
        11
    DoctorCat  
       2020-12-17 01:57:50 +08:00
    看起来是架构方案题,不是编程细节吧。b 调用 a,并降低时延,意味着 b 与 a 的调用链路最短+系统状态保持最优啊。如果分别部署在不同实例,那最好 b 与 a 同一个机架同一个子网,物理距离和网络逻辑位置最短的原则。
    数据聚合最好设计一个数据聚合层比如引入 MQ 而且最好是 pubsub 机制……保持 tcp 长连接替代 HTTP 等等,还有 kernel 网络相关的调优、系统进程 CPU 亲和性的调优等等。
    beidounanxizi
        12
    beidounanxizi  
       2020-12-17 02:33:21 +08:00
    @luxinfl go 的 waitgroup Java 的 countdownlatch 都可以实现 ,
    carlclone
        13
    carlclone  
       2020-12-17 06:52:39 +08:00 via Android
    这题难道不是考察分布式事务吗,楼上的都在讲什么乱七八糟的
    noogler67
        14
    noogler67  
       2020-12-17 08:44:47 +08:00 via iPhone
    时延的话,就是同时发起 acde,等完成后再发起 b
    anthow
        15
    anthow  
       2020-12-17 08:55:52 +08:00
    整几个 CompletableFuture
    Peachl
        16
    Peachl  
       2020-12-17 09:00:55 +08:00   ❤️ 1
    @carlclone 分布式事务是保证事务的 明显这个位置问的是如何做到顺序性的 completableFuture 就是正解
    blessyou
        17
    blessyou  
       2020-12-17 09:18:49 +08:00
    js 的话大概是 Promise.all()
    TonyYOYO
        18
    TonyYOYO  
       2020-12-17 09:33:15 +08:00 via iPhone
    @fanyiaa 你可笑死我了
    liuhuan475
        19
    liuhuan475  
       2020-12-17 09:41:56 +08:00
    Future
    sonice
        20
    sonice  
       2020-12-17 09:55:47 +08:00   ❤️ 4
    ```
    CompletableFuture<String> futureAb = CompletableFuture.runAsync(() -> {
    // no operation
    }).thenApply(b-> "ab");

    CompletableFuture<String> futureC = CompletableFuture.supplyAsync(() -> "c");
    CompletableFuture<String> futureD = CompletableFuture.supplyAsync(() -> "d");
    CompletableFuture<String> futureE = CompletableFuture.supplyAsync(() -> "e");

    String collect = Stream.of(futureAb, futureC, futureD, futureE)
    .map(CompletableFuture::join)
    .collect(Collectors.joining(" "));

    //output: ab c d e
    System.out.println(collect);
    ```
    Cbdy
        21
    Cbdy  
       2020-12-17 10:35:42 +08:00
    我是 4L,我把原先的 JS 版改成 Java 版
    var resultList = Stream.of(CompletableFuture.supplyAsync(() -> a()).thenApply(ra -> Stream.of(ra, b())),
    CompletableFuture.supplyAsync(() -> c()),
    CompletableFuture.supplyAsync(() -> d()),
    CompletableFuture.supplyAsync(() -> e()))
    .map(CompletableFuture::join)
    .flatMap(it -> it instanceof Stream ? ((Stream<?>) it) : Stream.of(it))
    .collect(Collectors.toList());
    gmywq0392
        22
    gmywq0392  
       2020-12-17 10:37:30 +08:00
    回调
    dddz97
        23
    dddz97  
       2020-12-17 10:40:13 +08:00
    感觉想问的点是 MQ 之类的
    shyrock
        24
    shyrock  
       2020-12-17 10:54:30 +08:00
    插眼等有效回答。
    qiaobeier
        25
    qiaobeier  
       2020-12-17 10:58:19 +08:00
    无非轮询事件回调。
    fantastM
        26
    fantastM  
       2020-12-17 11:39:18 +08:00
    先同步调用 a,再用线程池异步并行地调用 bcde 。

    因为整合数据时,需要保证 bcde 请求调用完成,所以就用一下 CountDownLatch 来实现这个等待机制。
    XDJI
        27
    XDJI  
       2020-12-17 14:36:03 +08:00
    就是 20 21 解法 全链路异步
    kkkkkrua
        28
    kkkkkrua  
       2020-12-17 14:40:27 +08:00
    这不就是考察 CompletableFuture ?
    surfire91
        29
    surfire91  
       2020-12-17 17:17:04 +08:00
    @fantastM 为什么不先调用 acde,然后等 a 返回了再调 b
    wangritian
        30
    wangritian  
       2020-12-17 17:31:01 +08:00
    a+b 一个 goroutine,cde 各一个 goroutine,主线程 waitgroup
    zy445566
        31
    zy445566  
       2020-12-17 17:41:49 +08:00
    如果是 js 的话,这样就行
    ```js
    const data = await a();
    const dataList = await Promise.all([c(),d(),d()]);
    // 整合数据
    ```
    Jooooooooo
        32
    Jooooooooo  
       2020-12-17 18:46:30 +08:00
    20l 答案差不多了
    liian2019
        33
    liian2019  
       2020-12-17 19:01:54 +08:00
    public static void test() throws Exception{
    Map<String,String> resultMap = new HashMap<>();
    CompletableFuture.allOf(CompletableFuture.supplyAsync(() -> {
    // 调用 A
    String aResult = "Hello";
    resultMap.put("A",aResult);
    return aResult;
    }, executor).thenAcceptAsync(aResult -> {
    // 调用 B
    String bResult = aResult + " World";
    resultMap.put("B",bResult);
    }), CompletableFuture.runAsync(() -> {
    // 调用 C
    String cResult = "CValue";
    resultMap.put("C",cResult);
    },executor), CompletableFuture.runAsync(() -> {
    // 调用 D
    String dResult = "DValue";
    resultMap.put("D",dResult);
    },executor),
    CompletableFuture.runAsync(() -> {
    // 调用 E
    String eResult = "EValue";
    resultMap.put("E",eResult);
    },executor)).join();
    System.out.println(JSON.toJSONString(resultMap));
    }
    luvroot
        34
    luvroot  
       2020-12-17 19:14:30 +08:00   ❤️ 1
    ab 打包成一个微服务,ecd 做成 3 个微服务,即可
    gengzi
        35
    gengzi  
       2020-12-17 19:24:22 +08:00
    多线程异步( Callable ),异步调用 a,调用 cde,等待 a 返回结果,再调用 b 。 最终的时延 acde 服务最长的一个耗时+b 服务耗时。
    crclz
        36
    crclz  
       2020-12-17 19:30:22 +08:00
    System.ReactiveX rxjs rxjava
    mxT52CRuqR6o5
        37
    mxT52CRuqR6o5  
       2020-12-17 19:30:37 +08:00
    就是在满足调用条件时就马上去调用,把这个逻辑写出来就行
    Achieve7
        38
    Achieve7  
       2020-12-17 19:30:50 +08:00
    CompletableFuture 或者 ForkJoinPool 都可以 如果是微服务 就异步呗
    IssacTomatoTan
        39
    IssacTomatoTan  
       2020-12-17 19:42:57 +08:00 via Android
    Js:
    const f = new Promise(async (r)=>{
    await a();
    await b();
    r();
    })
    promise.all([c,d,e,f]).then
    laminux29
        40
    laminux29  
       2020-12-18 00:57:43 +08:00   ❤️ 1
    微服务这功能,从本质上来说,首先是软件工程与管理上的问题,目的是为多人协同的大中型软件项目服务,是用增加组件间延时的代价来换取更快的平均运行性能与开发协作效率,所以时延高是必须,是代价,没办法从原理上降低。否则,如果低时延是刚需,那就不应该用微服务,而是单机 + 进程内部调用,这样子延时才会最小化。

    其他细节上的问题,楼上的老哥们已经说了。
    js8510
        41
    js8510  
       2020-12-18 08:45:14 +08:00
    x->b and x->a pre call
    got b response, retrieve a response with the real ->a call
    这样 是 max(x->b, x->a pre call) + x-a round trip 的时间

    如果 a processing time 短于 b 还可以。
    x->b and x->a precall
    b processing and then retrieve ->a response
    response x

    这样的时间 和 x->a round trip + a prossing time 是一样的
    mitsuizzz
        42
    mitsuizzz  
       2020-12-18 11:57:15 +08:00
    20L 是我常用的方法,之前做过清理各个服务的数据,整合各个服务备份的脚本
    519718366
        43
    519718366  
       2020-12-18 12:01:06 +08:00 via Android
    其实面试回答,cde 异步请求就完事了…
    在追问你怎么异步实现,当然优先微服务框架特性,再语言特性实现
    Suddoo
        44
    Suddoo  
       2020-12-23 14:08:26 +08:00
    @luvroot 感觉你这个最简洁明了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5356 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 40ms · UTC 05:49 · PVG 13:49 · LAX 22:49 · JFK 01:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.