Spring Boot 调优

java启动时参数
内存:java -Xms64m -Xmx512m -jar xxx.jar
GC线程数:-XX:ParallelGCThreads=2
关掉CompilerThread线程 -Djava.compiler=NONE
JIT是JVM为了优化执行频率比较高的字节码设计的技术。JIT把字节码编译为机器码,之后执行则不需要解释字节码,直接运行机器码即可。如果服务没有什么负载,即使不优化也不受影响,可以优化把JIT关掉。

application.properties中配置:
并发线程数:server.tomcat.max-threads = 10
Spring boot自带的tomcat线程数默认值为200个。

更换Web容器:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>

        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-undertow</artifactId>
    </dependency>
</dependencies>

一些查看命令
jmap
jstack:jstack查看内存发现一些线程在运行,主要有GC task thread,http-nio thread,C2 CompilerThread。
GC task thread:垃圾回收线程
http-nio thread:tomcat网络处理网络请求线程
C2CompilerThread:JIT编译线程,动态编译Java运行代码,C2表示编译的是server端代码
JVM默认线程栈大小是1M。

https://blog.csdn.net/github_32521685/article/details/50463895
https://blog.csdn.net/lijingyao8206/article/details/80432402

服务器

undertow、jetty和tomcat是javaweb项目当下最火的三款服务器,spring boot 完美集成了tomcat、jetty和undertow。
jetty和undertow都是基于NIO实现的高并发轻量级的服务器,支持servlet3.1和websocket。

Spring Boot 异步

当某个请求执行非常耗时,当有大量访问该请求的时候,再访问请求其他服务时,会出现没有连接使用的情况。造成这种现象的主要原因是,容器中线程的数量是一定的,例如500个,当这500个线程都正在用来处理请求服务的时候,再有请求进来,没有多余的连接可用了,只能拒绝连接。

SpringBoot异步机制可以使请求到controller中时,容器线程直接返回,同时使用系统内部的线程来执行耗时的服务,处理结束后果再将请求返回给客户端。

Servlet 3.0 新增了请求的异步处理,Spring 3.2 也在此基础上做了封装处理。
Spring通过任务执行器(TaskExecutor)来实现多线程和并发编程。使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor。

在 Spring Boot 框架中,可以在配置类中添加@EnableAsync开始对异步任务的支持,并将相应的方法使用@Async注解来声明为一个异步任务。

对于@Transactional、@Async等注解,spring扫描时具有这些注解方法的类时,生成一个代理类,由代理类去执行,所以异步方法必须在类外部调用,并且@Async所修饰的不能是static方法。获取得到执行结果则可设置异步函数返回类型为Future。

@Component  
public class MyAsyncTask {  
    @Async  
    public Future task1() throws InterruptedException{  
        return new AsyncResult("task1执行完毕");  
    }  

Controller的方法可以很快返回一个java.util.concurrent.Callable或Deferredresult,同时Servlet容器的主线程退出和释放,这并不意味着客户端收到了一个响应。

//Callable
@Controller
public class DefaultController {
    @RequestMapping("/async/test")
    @ResponseBody
    public Callable callable() {
        //调用后生成一个非web线程来执行部分代码。
        return new Callable() {
            @Override
            public String call() throws Exception {
                Thread.sleep(3 * 1000L);
                return "finish" + System.currentTimeMillis();
            }
        };
    }
}

//DeferredResult
@RestController  
public class AsyncDeferredController {  
    private final TaskService taskService;  
      
    @Autowired  
    public AsyncDeferredController(TaskService taskService) {  
        this.taskService = taskService;  
    }  
      
    @RequestMapping(value = "/deferred", method = RequestMethod.GET, produces = "text/html")  
    public DeferredResult executeSlowTask() {  
        DeferredResult deferredResult = new DeferredResult<>();  
        CompletableFuture.supplyAsync(taskService::execute).whenCompleteAsync((result, throwable) -> deferredResult.setResult(result));  

        return deferredResult;  
    }  
}  

Callable的其它示例:

 public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable callable = new CallableImpl("my callable test!");
        FutureTask task = new FutureTask<>(callable);
        new Thread(task).start();
        //调用get()会阻塞主线程。
        String result = task.get();
    }

Callable和Deferredresult的区别:
Callable和Deferredresult效果都是释放容器线程,在另一个线程中运行长时间的任务。不同的是谁管理执行任务的线程:Callable在执行线程完毕时返回;Deferredresult是通过设置返回对象值返回,可以在任何地方控制返回。

https://blog.csdn.net/he90227/article/details/52262163
Spring MVC 异步处理请求,提高程序性能

定时任务

1.在程序入口类上添加类注解 @EnableScheduling 来启用计划任务
2.在定时任务的类上加上类注解 @Component,在具体的定时任务方法上加上注解 @Scheduled 启动该定时任务。
@Scheduled(initialDelay=10000, fixedDelay=10000) //10 seconds, or use cron express

默认所有的@Scheduled都是串行执行的,并行需要继承SchedulingConfigurer类并重写其方法,实现并行任务。

@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());
    }

    @Bean(destroyMethod="shutdown")
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(100);
    }
}

测试发现,RestController中接收处理请求每次所处的线程不一样,Mqtt处理请求也是单独的线程。

详解SpringBoot Schedule配置
http://www.cfei.net/archives/88832
Spring Boot 异步请求(Servlet 3.0)
https://blog.csdn.net/catoop/article/details/51034866

Spring Boot 应用属性配置

变量名引用

在application.properties文件中,使用${变量名}引用变量。例如:
db.name=db1
spring.data.mongodb.uri=mongodb://${db.username}:${db.password}@${db.url}:${db.port}/${db.name}
还可以自定义 application.properties 进行外部配置。
https://blog.csdn.net/fanhenghui/article/details/77447918

配置日志

#debug=true
logging.file=yirui_clock_server.log
logging.level.com.yirui.clock.server=INFO
logging.level.root=INFO
logging.level.org.springframework.data.mongodb=INFO

配置ssl

server.ssl.key-store:/etc/letsencrypt/live/xxxx/keystore.p12
server.ssl.key-store-password: jsqc
server.ssl.keyStoreType: PKCS12
server.ssl.keyAlias: tomcat

容器配置

Spring Boot 内置的容器有三个分别是Undertow、Jetty、Tomcat。Spring Boot 对这三个容器分别进行了实现,它们上层接口都是EmbeddedServletContainerFactory。

对于内置容器的定制与优化主要有两种方式:第一种方式是通过配置文件来配置,另外一种是通过码代码的方式。
配置的核心内容参考org.springframework.boot.autoconfigure.web.ServerProperties这个服务属性类。

spring boot 限制初始值大小及参数中文详解 https://www.jianshu.com/p/552e49571893