背景:前些天在业务不怎么繁忙的时候,我主动用kibana、grafana 创建了一份属于我负责服务的接口性能图,通过性能图就能轻松看出每个接口的响应时间。那么问题来了:我应该如何优化慢查询呢? 我应该通过什么工具来看出我需要优化哪些点呢? 我应该如何实现优化呢?用到的技术点有哪些呢?
grafana 可视化表:
kibana 可视化表:
可以依据自己想看的报表建立相关的可视化,然后通过可视化来排查哪些接口存在性能问题、又有哪些接口存在错误问题等。当找到待优化的接口之后,紧接着就是要明确应该如何优化接口,也需要明确接口中那一块依赖服务请求时间长?这个时候就可以依托与SkyWalking来分析接口内部的优化点。(SkyWalking是一个开源的框架,后面更新搭建教程)。
SkyWalking 面板:
通过SkyWalking 面板就能看出来接口内部每个服务调用方接口、数据库操作等,每个接口的具体访问时间,数据库连接时间等都可以一目了然。 从而调查代码,找到相关的调用处,进行修改。
假设从上面SkyWalking 中抽象出的一个接口如下图所示,X轴表示方法执行的时间,Y轴表示执行的顺序(从上往下看),也就是先执行 getHasNoOrders () (获取订单结果) checkData() (校验数据项) saveCheckResult() (保存数据)。可见上面三个函数之间执行方式串行执行,如果能够让他们之间的操作并行化,那么系统的性能就可以得到进一步提升了。
那么应该如何使用异步任务完成呢? 假设:getHasNoOrders () (获取订单结果) checkData() (校验数据项)这两个函数可以并行执行,在执行完之后 在执行 saveCheckResult() (保存数据),这样就可以将前面的 串行改并行了,整体响应时间就会减少,从而性能就能提高。
如何实现上述的 串行改并行呢?
异步任务:CompletableFuture
涉及到 串行关系,并行关系,聚合关系的,一般用的最多的就是CompletableFuture,CompletableFuture 是Java 8 新增加的Api,该类实现,Future和CompletionStage两个接口,提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性。它继承了FutureTask的同步任务的特点,同时新增了异步调用的特点,其中异步的方法名称都带有Async。
创建CompletableFuture对象
方式一:使用默认线程池(默认采用的是ForkJoinPoin线程池,
前提是cpu是多核的,也就是Runtime.getRuntime().availableProcessors() - 1
,例如cpu是12核心的,那么就是返回11)
/**
* 创建一个不带返回值得任务。
*/
CompletableFuture<Void> f1 = CompletableFuture.runAsync(new Runnable() {
@Override
public void run() {
//业务逻辑
}
});
方式二:使用自定义线程池(建议使用,不同的业务设定不同线程池,这样可以使性能达到最高水平)
//创建线程池
ExecutorService executor = Executors.newFixedThreadPool(10);
//创建一个不带返回值得任务。
CompletableFuture<Void> f1 = CompletableFuture.runAsync(new Runnable() {
@Override
public void run() {
}
},executor);
通过下面demo就能得到串行与并行之间的执行对比了:
public class ThreadDemo {
public static void main(String[] args) {
long start = System.currentTimeMillis();
CompletableFuture<Void> f1 = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第一个异步任务");
});
CompletableFuture<Void> f2 = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第二个异步任务");
});
CompletableFuture<Void> f3 = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第三个异步任务");
});
//全部完成,执行该函数下面的方法
CompletableFuture.allOf(f1, f2, f3).join();
long end = System.currentTimeMillis();
//大致预估时间 2 + 1 + 4 = 7
System.out.println("串行行执行最优时间:7s");
System.out.println("并行执行时间:" + (end - start) / 1000 + "s");
}
}
运行结果:
相关API
情景一:异步组合两任务都完成,在执行任务三。
情景二:异步组合两任务只要有一个完成,就执行任务三。
情景三:多任务组合完成 allOf
情景四:多任务只要有一个完成了。 anyOf
推荐详细API使用博客:
CompletableFuture中方法的各种(多任务并发场景)使用案例----详解_诗水人间-CSDN博客
最后:欢迎大家【私信】和【评论】,如果可以的话,还请关注我O。