让API并行调用的方法是什么

72次阅读
没有评论

共计 3134 个字符,预计需要花费 8 分钟才能阅读完成。

本篇内容介绍了“让 API 并行调用的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让丸趣 TV 小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

当数据量较大的时候,都会通过分库分表来拆分,分担读写的压力。分库分表后比较麻烦的就是查询的问题,如果不是直接根据分片键去查询的话,需要对多个表进行查询。

在一些复杂的业务场景下,比如订单搜索,除了订单号,用户,商家 这些常用的搜索条件,可能还有时间,商品等等。

目前常见的做法将数据同步到 ES 这类搜索框架中进行查询,然后通过搜出来的结果,一般是主键 ID,   再去具体的数据表中查询完整的数据,组装返回给调用方。

比如下面这段代码,首先查询出文章信息,然后根据文章中的用户 ID 去查询用户的昵称。

List ArticleBO  articleBos = articleDoPage.getRecords().stream().map(r -  { String nickname = userManager.getNickname(r.getUserId()); return articleBoConvert.convertPlus(r, nickname); }).collect(Collectors.toList());

如果文章有 10 条数据,那么就需要调用 10 次用户服务提供的接口,而且是同步调用操作。

当然我们也可以用并行流来实现并发调用,代码如下:

List ArticleBO  articleBos = articleDoPage.getRecords().parallelStream().map(r -  { String nickname = userManager.getNickname(r.getUserId()); return articleBoConvert.convertPlus(r, nickname); }).collect(Collectors.toList());

并行流的优点很明显,代码不用做特别大的改动。需要注意如果用并行流,最好单独定义一个 ForkJoinPool。

除了用并行流,还可以使用批量查询的方式来提高性能,降低 RPC 的调用次数,代码如下:

List Long  userIds = articleDoPage.getRecords().stream().map(article -  article.getUserId()).collect(Collectors.toList()); Map Long, String  nickNameMap = userManager.queryByIds(userIds).stream().collect(Collectors.toMap(UserResponse::getId, UserResponse::getNickname)); List ArticleBO  articleBos = articleDoPage.getRecords().stream().map(r -  { String nickname = nickNameMap.containsKey(r.getUserId()) ? nickNameMap.get(r.getUserId()) : CommonConstant.DEFAULT_EMPTY_STR; return articleBoConvert.convertPlus(r, nickname); }).collect(Collectors.toList());

但批量查询还是同步模式,下面介绍如果使用 CompletableFuture 来实现异步并发调用,直接用原生的 CompletableFuture   也可以,但是编排能力没有那么强,这里我们选择一款基于 CompletableFuture   封装的并行编排框来实现。

稍微做了下封装,提供了更方便使用的工具类来实现并发调用多个接口的逻辑。

第一种方式,适用于比如从 ES 查出了一批 ID, 然后根据 ID 去数据库中或者调用 RPC 查询真实数据,最后得到一个 Map,可以根据 Key   获取对应的数据。

内部是多线程并发调用,会等到结果全部返回。

public Object aggregationApi() { long s = System.currentTimeMillis(); List String  ids = new ArrayList (); ids.add( 1  ids.add( 2  ids.add( 3  Map String, UserResponse  callResult = AsyncTemplate.call(ids, id -  { return userService.getUser(id); }, u -  u.getId(), COMMON_POOL); long e = System.currentTimeMillis(); System.out.println( 耗时: + (e-s) +  ms  return   }

另一个场景就是 API 聚合的场景,需要并行调用多个接口,将结果进行组装。

List AsyncCall  params = new ArrayList (); AsyncCall Integer, Integer  goodsQuery = new AsyncCall( goodsQuery , 1); params.add(goodsQuery); AsyncCall String, OrderResponse  orderQuery = new AsyncCall(orderQuery ,  100  params.add(orderQuery); UserQuery q = new UserQuery(); q.setAge(18); q.setName(yinjihuan  AsyncCall UserQuery, UserResponse  userQuery = new AsyncCall( userQuery , q); params.add(userQuery); AsyncTemplate.call(params, p -  { if (p.getTaskId().equals(goodsQuery)) { AsyncCall Integer, Integer  query = p; return goodsService.getGoodsName(query.getParam()); } if (p.getTaskId().equals(orderQuery)) { AsyncCall String, OrderResponse  query = p; return orderService.getOrder(query.getParam()); } if (p.getTaskId().equals(userQuery)) { AsyncCall UserQuery, UserResponse  query = p; return userService.getUser(query.getParam()); } return null; });

AsyncCall 中定义参数和响应的类型,响应结果会在执行完后会自动设置到 AsyncCall 中。在 call 方法中需要根据 taskId   去做对应的处理逻辑,不同的 taskId 调用的接口不一样。

“让 API 并行调用的方法是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注丸趣 TV 网站,丸趣 TV 小编将为大家输出更多高质量的实用文章!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-27发表,共计3134字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)