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

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

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

    因为整合数据时,需要保证 bcde 请求调用完成,所以就用一下 CountDownLatch 来实现这个等待机制。
    XDJI
        27
    XDJI   228 天前
    就是 20 21 解法 全链路异步
    kkkkkrua
        28
    kkkkkrua   228 天前
    这不就是考察 CompletableFuture ?
    surfire91
        29
    surfire91   228 天前
    @fantastM 为什么不先调用 acde,然后等 a 返回了再调 b
    wangritian
        30
    wangritian   228 天前
    a+b 一个 goroutine,cde 各一个 goroutine,主线程 waitgroup
    zy445566
        31
    zy445566   228 天前
    如果是 js 的话,这样就行
    ```js
    const data = await a();
    const dataList = await Promise.all([c(),d(),d()]);
    // 整合数据
    ```
    Jooooooooo
        32
    Jooooooooo   228 天前
    20l 答案差不多了
    liian2019
        33
    liian2019   228 天前
    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   228 天前   ❤️ 1
    ab 打包成一个微服务,ecd 做成 3 个微服务,即可
    gengzi
        35
    gengzi   228 天前
    多线程异步( Callable ),异步调用 a,调用 cde,等待 a 返回结果,再调用 b 。 最终的时延 acde 服务最长的一个耗时+b 服务耗时。
    crclz
        36
    crclz   228 天前
    System.ReactiveX rxjs rxjava
    mxT52CRuqR6o5
        37
    mxT52CRuqR6o5   228 天前
    就是在满足调用条件时就马上去调用,把这个逻辑写出来就行
    Achieve7
        38
    Achieve7   228 天前
    CompletableFuture 或者 ForkJoinPool 都可以 如果是微服务 就异步呗
    IssacTomatoTan
        39
    IssacTomatoTan   228 天前 via Android
    Js:
    const f = new Promise(async (r)=>{
    await a();
    await b();
    r();
    })
    promise.all([c,d,e,f]).then
    laminux29
        40
    laminux29   228 天前   ❤️ 1
    微服务这功能,从本质上来说,首先是软件工程与管理上的问题,目的是为多人协同的大中型软件项目服务,是用增加组件间延时的代价来换取更快的平均运行性能与开发协作效率,所以时延高是必须,是代价,没办法从原理上降低。否则,如果低时延是刚需,那就不应该用微服务,而是单机 + 进程内部调用,这样子延时才会最小化。

    其他细节上的问题,楼上的老哥们已经说了。
    js8510
        41
    js8510   228 天前
    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   228 天前
    20L 是我常用的方法,之前做过清理各个服务的数据,整合各个服务备份的脚本
    519718366
        43
    519718366   228 天前 via Android
    其实面试回答,cde 异步请求就完事了…
    在追问你怎么异步实现,当然优先微服务框架特性,再语言特性实现
    Suddoo
        44
    Suddoo   222 天前
    @luvroot 感觉你这个最简洁明了
    关于   ·   帮助文档   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2802 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 05:12 · PVG 13:12 · LAX 22:12 · JFK 01:12
    ♥ Do have faith in what you're doing.