面对高并发可以记住这五点:
本文将介绍如何缩短API接口的响应时间、提升系统单位时间内的并发量和吞吐量,内容有
注:本文基于springboot2.1.3.RELEASE 版本
这类接口按传统的编程思维,会串行调用所有后端api,然后再组装,这样会导致接口响应时间会随着聚合的接口数呈比例增长,时间复杂度O(N)
优化方案
分析:这样优化后,我们的聚合查询类接口响应时间最多只是与最慢的那个后端api接口速度相当而已,时间复杂度降到了O(1)
。
注意事项:此方式要求聚合查询接口内的各个业务接口间无依赖关系。
这类接口面对巨大流量压力时,往往表现为服务并发和吞吐量上不去,但服务器CPU、内存等资源充足
优化方案
分析:优化思想就是,先砍掉部分和接口响应处理关系不大的业务,让他们在后台异步处理;再将其他业务操作按照业务操作间有无依赖关系进行拆分,可以并行的就尽量异步并行执行;最终统一处理响应内容再返回。
这类接口往往耗费非常多的CPU,导致服务器并发和吞吐量上不去。
优化方案
如DB、缓存、队列、或者一些服务器组件的性能瓶颈不在本篇文章内容,以后会有篇幅做专门讲解;学习资料:Java进阶视频资源
该工具可以为你的应用提供方便快捷的异步化执行业务的能力,只需要添加一个注解@Async
既可以使你的业务异步执行,这里的异步执行,指的是新开一个线程执行你的业务;该注解可以使用到类上,也可以使用在方法上。
1,@EnableAsync
启用异步化能力注解
推荐该注解配置在springboot的Config类或者启动类上,用于开启异步化能力,做一些异步化线程池和相关组件的初始化工作。
2,@Async
开启异步化模式注解
基于@Async
标注的方法,称之为异步方法;这些方法将在执行的时候,将会在独立的线程中被执行,调用者无需等待它的完成,即可继续其他的操作。
该注解标注在类上,就代表调用该类的所有方法均会自动异步执行;标注在方法上,该方法就会异步执行;当调用该方法时,Async
的切面会先向异步线程池申请一个线程,然后使用该线程执行该方法内的业务逻辑。
3,AsyncConfigurer
全局配置接口
用于配置自定义异步线程池和异步线程执行异常捕获器,灵活定制合适的线程池和异常处理规则。
4,AsyncUncaughtExceptionHandler
异步化运行时全局异常捕获接口
自定义异步线程池运行时异常统一处理方案。
5,AsyncExecutor
异步化执行线程池
自定义异步执行线程池的大小、线程存活时间、队列信息等等,详情可以参考线程池的使用说明,这里就不展开讨论。学习资料:Java进阶视频资源
说明:
void
或者Future<T>
@Async
所修饰的方法不要定义为static类型,这样异步调用不会生效@Async
所修饰的方法不能和@Transactional
一起使用,因为会启用新的子线程来执行方法内的业务,主线程内的事务注解无法控制子线程的业务操作,原因就是事务存在线程隔离的原因,如果要加事务,请在方法内嵌套其他事务标注后的方法即可生效示例:
无参数异步化接口
@Async
public void executeTask(){
//业务操作
}
带参数异步化接口
@Async
public Future<Dto> task2(){
//业务操作
//返回操作结果
return new AsyncResult<>(new Dto("danyuan",22));
}
@Data
@AllArgsConstructor
public class Dto implements Serializable{
/**
*serialVersionUID
*/
private static final long serialVersionUID = 1L;
private String name;
private Integer age;
}
应用配置启动类示例如下:
/**
* Title StartAsyncServer.java
* Description
* @author danyuan
* @version 1.0.0
* site: www.danyuanblog.com
*/
package com.danyuanblog.test;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@SpringBootApplication
@EnableAsync
public class StartAsyncServer implements AsyncConfigurer {
public static void main(String[] args) {
SpringApplication.run(StartAsyncServer.class, args);
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new ExceptionHandler();
};
@Slf4j(topic="异步线程池运行时异常捕获器")
static class ExceptionHandler implements AsyncUncaughtExceptionHandler{
/**
* @author danyuan
*/
@Override
public void handleUncaughtException(Throwable e, Method method,
Object... params) {//全局捕获异步执行异常并处理
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);
PrintStream printStream = new PrintStream(outputStream);
e.printStackTrace(printStream);
log.error(outputStream.toString());
}
}
/**
* @author danyuan
*/
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(400);
executor.setQueueCapacity(10000);
executor.setThreadNamePrefix("TestAsyncExecutor-");
executor.initialize();
return executor;
}
}
业务场景是这样的,task1、task2之间无依赖关系,task3依赖与task2的操作结果,代码示例如下:
AsyncTestService.java
/**
* Title AsyncTestService.java
* Description
* @author danyuan
* @version 1.0.0
* site: www.danyuanblog.com
*/
package com.danyuanblog.test.asyc;
import java.util.concurrent.Future;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
@Service
public class AsyncTestService {
@Async
public void task1(){
System.out.println("task1 execute begin .....");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task1 execute success !");
}
@Async
public Future<Dto> task2(){
System.out.println("task2 execute begin .....");
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task2 execute success !");
return new AsyncResult<>(new Dto("danyuan",22));
}
@Async
public void task3(Dto dto){
System.out.println("task3 execute begin .....");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(dto.getAge() > 18){
System.out.println(dto.getName() "已成年!");
}else{
System.out.println(dto.getName() "未成年!");
}
System.out.println("task3 execute success !");
}
}
AsycTestController.java
/**
* Title AsycTestController.java
* Description 业务异步化测试
* @author danyuan
* @version 1.0.0
* site: www.danyuanblog.com
*/
package com.danyuanblog.test.asyc;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AsycTestController {
@Autowired
private AsyncTestService asyncTestService;
/**
* 测试异步化任务
* @author danyuan
*/
@GetMapping("/testAsync")
public void testAsync(){
asyncTestService.task1();
Future<Dto> result = asyncTestService.task2();
while(true){//task3需要等待task2执行完成
if(result.isDone() || result.isCancelled()){
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
asyncTestService.task3(result.get());
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}
}
如果您发现该资源为电子书等存在侵权的资源或对该资源描述不正确等,可点击“私信”按钮向作者进行反馈;如作者无回复可进行平台仲裁,我们会在第一时间进行处理!
加入交流群
请使用微信扫一扫!