Springboot2吞吐量優化的一些解決方案

優化吞吐量目前我能想到的有3點。web

  • Docker隔離
  • 異步執行
  • 增長內嵌Tomcat的最大鏈接數

Docker隔離就不說了,很簡單,先來看一下異步執行吧,不少人作異步執行的時候都寫的千奇百怪的,其實JDK 8自己有一個很是好用的Future類——CompletableFuture。api

先大概說一下CompletableFuture的用法tomcat

@AllArgsConstructor
public class AskThread implements Runnable{
    private CompletableFuture<Integer> re = null;

    public void run() {
        int myRe = 0;
        try {
            myRe = re.get() * re.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(myRe);
    }

    public static void main(String[] args) throws InterruptedException {
        final CompletableFuture<Integer> future = new CompletableFuture<>();
        new Thread(new AskThread(future)).start();
        //模擬長時間的計算過程
        Thread.sleep(1000);
        //告知完成結果
        future.complete(60);
    }
}

在該示例中,啓動一個線程,此時AskThread對象尚未拿到它須要的數據,執行到 myRe = re.get() * re.get()會阻塞。咱們用休眠1秒來模擬一個長時間的計算過程,並將計算結果告訴future執行結果,AskThread線程將會繼續執行。app

執行結果:異步

3600   (此處是一個整數)優化

public class Calc {
    public static Integer calc(Integer para) {
        try {
            //模擬一個長時間的執行
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return para * para;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        final CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> calc(50))
                .thenApply((i) -> Integer.toString(i))
                .thenApply((str) -> "\"" + str + "\"")
                .thenAccept(System.out::println);
        future.get();
    }
}

CompletableFuture.supplyAsync方法構造一個CompletableFuture實例,在supplyAsync()方法中,它會在一個新線程中,執行傳入的參數。在這裏它會執行calc()方法,這個方法多是比較慢的,但這並不影響CompletableFuture實例的構造速度,supplyAsync()會當即返回。而返回的CompletableFuture實例就能夠做爲此次調用的契約,在未來任何場合,用於得到最終的計算結果。supplyAsync用於提供返回值的狀況,CompletableFuture還有一個不須要返回值的異步調用方法runAsync(Runnable runnable),通常咱們在優化Controller時,使用這個方法比較多。這兩個方法若是在不指定線程池的狀況下,都是在ForkJoinPool.common線程池中執行,而這個線程池中的全部線程都是Daemon(守護)線程,因此,當主線程結束時,這些線程不管執行完畢都會退出系統。this

運行結果:線程

"2500"    (因爲流式計算,此處是字符串)server

這樣,咱們就能夠在咱們的Controller要異步執行的代碼寫成一個方法,放到CompletableFuture中,好比對象

CompletableFuture.runAsync(() ->
   this.afterBetProcessor(betRequest,betDetailResult,appUser,id)
);

最後就是增長內嵌Tomcat的最大鏈接數,此處只針對Springboot 2的,Springboot 1.x的是不一樣的,請勿使用。

首先在資源文件中註釋掉Server下的配置

#server:
#  port: 8005
#  servlet:
#    context-path: /api-g

寫一個專門的tomcat的配置類

@Configuration
public class TomcatConfig {
    @Bean
    public ConfigurableServletWebServerFactory webServerFactory() {
        TomcatServletWebServerFactory tomcatFactory = new TomcatServletWebServerFactory();
        tomcatFactory.addConnectorCustomizers(new MyTomcatConnectorCustomizer());
        tomcatFactory.setPort(8005);
        tomcatFactory.setContextPath("/api-g");
        return tomcatFactory;
    }
    class MyTomcatConnectorCustomizer implements TomcatConnectorCustomizer {
        public void customize(Connector connector) {
            Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
            //設置最大鏈接數               
            protocol.setMaxConnections(20000);
            //設置最大線程數               
            protocol.setMaxThreads(2000);
            protocol.setConnectionTimeout(30000);
        }
    }

}

通過以上的優化,Controller的吞吐量大概能夠提高2到3倍。

相關文章
相關標籤/搜索