让API并行调用变得如丝般顺滑的绝招
当数据量较大的时候,都会通过分库分表来拆分,分担读写的压力。分库分表后比较麻烦的就是查询的问题,如果不是直接根据分片键去查询的话,需要对多个表进行查询。
在一些复杂的业务场景下,比如订单搜索,除了订单号,用户,商家 这些常用的搜索条件,可能还有时间,商品等等。
目前常见的做法将数据同步到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封装的并行编排框来实现,详细介绍查看我之前的这篇文章:https://mp.weixin.qq.com/s/3EE8ccydK16gC1oY4AWnoA
稍微做了下封装,提供了更方便使用的工具类来实现并发调用多个接口的逻辑。
第一种方式,适用于比如从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调用的接口不一样。
源码参考:https://github.com/yinjihuan/kitty
关于作者:尹吉欢,简单的技术爱好者,《Spring Cloud微服务-全栈技术与案例解析》, 《Spring Cloud微服务 入门 实战与进阶》作者, 公众号猿天地发起人。
让API并行调用变得如丝般顺滑的绝招的更多相关文章
- 如何把 Caffeine Cache 用得如丝般顺滑?
一.关于 Caffeine Cache 在推荐服务中,虽然允许少量请求因计算超时等原因返回默认列表.但从运营指标来说,越高的"完算率"意味着越完整的算法效果呈现,也意味着越高的商业 ...
- 如丝般顺滑地从Windows迁移SQLServer数据库到Linux
老鸟看过菜鸟的上一篇<MSSQL On Linux备份与还原>文章后,很满意,但是还是忍不住发问:"这篇文章讲的是MSSQL在Linux系统上的备份与还原,如果我之前是Windo ...
- 大促密集,CDN如何保障电商体验如丝般顺滑?
简介: 前不久,阿里云技术天团空降CSDN在线峰会,对核心技术竞争力进行解读.其中,阿里云高级技术专家曾福华分享了<双11: CDN如何保障电商大促如丝般顺滑>的议题.俗话说:养兵千日,用 ...
- 如丝般顺滑:DDD再实践之类目树管理
在上次反思DDD实践之后,在类目树管理项目中再次实践DDD.从需求分析到建模和具体的落地,结合个人体会,都是干货.
- 想让安卓 APP 如丝般顺滑?
随着安卓手机市场占有率的节节攀升,随便在大街上找几个人估计 80% 用的都是安卓手机吧!用安卓手机的人这么多,不知道大家是否曾经感觉到过 APP 卡顿.死机?是否遇到应用程序无响应.闪退?本文就为大家 ...
- 微软 Build 大会发布大量开发工具与服务!编码、协作、发布,如丝般顺滑
Microsoft Build 2020开发者大会已经圆满落幕,在连续两天48小时的不间断直播中,来自全世界的开发者共赴盛宴,场面相当壮观.在这一年一度的大聚会里,微软也是诚意满满,带来了一连串的产品 ...
- ios滑动流畅(丝般顺滑)滚动
在ios html->body->list(少一个样式都不行!) html->body->list <!DOCTYPE html> <html lang=&q ...
- 【AMAD】django-silk -- 为Django提供如丝般顺滑的性能测量
动机 简介 个人评分 动机 Django作为一个web框架,进行性能测量是很复杂的,不可以使用传统的程序profile工具. 因为,web app的性能是多维度的,不仅仅是代码执行效率,还包括网络延时 ...
- BumbleBee: 如丝般顺滑构建、交付和运行 eBPF 程序
本文地址:https://www.ebpf.top/post/bumblebee 1. 前言 不久前,Solo.io 公司在官网博客宣布了开源了一个名称为 BumbleBee 的新项目.该项目专注于简 ...
随机推荐
- partial conv
Image Inpainting for Irregular Holes Using Partial Convolutions pytorch代码 论文贡献: 提出了部分卷积(partial conv ...
- Spring Boot 2.4发布了,但Spring Cloud用户不推荐着急升级
前段时间Spring Boot发布了本年度最后一个重要更新版本:Spring Boot 2.4.0. 最近在社群里也开始有讨论关于Spring Boot 2.4的一些使用问题.我发现有很多Spring ...
- BYTE WORD DWORD
在Visual C++ 6.0中,BYTE与WORD,DWORD本质上都是一种无符号整型,它们在WINDEF.H中被定义,定义如下:typedef unsigned char BYTE;t ...
- 【GDOI2014模拟】JZOJ2020年8月14日T2 网格
[GDOI2014模拟]JZOJ2020年8月14日T2 网格 题目 Time and Memory Limits Description 某城市的街道呈网格状,左下角坐标为A(0, 0),右上角坐标 ...
- 从代码角度理解NNLM(A Neural Probabilistic Language Model)
其框架结构如下所示: 可分为四 个部分: 词嵌入部分 输入 隐含层 输出层 我们要明确任务是通过一个文本序列(分词后的序列)去预测下一个字出现的概率,tensorflow代码如下: 参考:https: ...
- 树莓派搭建seafile服务器备忘
用户:pi 密码:raspberry 启用root用户https://blog.csdn.net/chenxd1101/article/details/53437925(防止特殊原因pi用户不能登录时 ...
- linux搭建harbor与使用
条件:安装docker&docker-compose 如未安装,请看:linux离线安装docker + docker-compose harbor 1.下载 下载地址:https://git ...
- java的jdk8新特性optional怎么样使用
从 Java 8 引入的一个很有趣的特性是 Optional 类.Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException) -- 每个 Java 程序员都 ...
- CSS常用语法缩写
使用缩写可以帮助减少你CSS文件的大小,更加容易阅读.CSS常用语法缩写的主要规则如下: 颜色 16进制的色彩值,如果每两位的值相同,可以缩写一半,例如:#000000可以缩写为#000;#33669 ...
- linux 复制文件前n行到另外一个文件
head -n 100 train.txt > 123.txt head -100 train.txt > 123.txt