转载

Springboot 效能調整紀錄

紀錄一下因壓力測試做過各種調整

就用預設的 tomcat ,我懶得換,其他的我也不熟

反正 tomcat 資料好找很多

調整 tomcat threadpool

server:

  tomcat:

    max-threads: 256

    min-spare-threads: 64

有用,但是很難抓數值要配多少

這兩個值預設都是0,但在實際壓測下來可以發現會越測越快,感覺是有在擴充 pool 的大小

在現代很多擁有動態擴充能力的架構下,固定值實在不是很好用,就讓他吃到 cpu 80% 後自動水平擴展會是比較好的做法

程式寫法

是否要異步

A寫法

@ResponseStatus(HttpStatus.ACCEPTED)
@PostMapping(value = "v1/activity/{activityid}/signup", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ActivitySignupRs signup(
        @PathVariable("activityid") String activityid,
        @Valid @RequestBody ActivitySignupRq activitySignupRq) {
    Long sequenceNumber = twitterSnowFlake.nextId();
    return new ActivitySignupRs(sequenceNumber);
}

B寫法

@ResponseStatus(HttpStatus.ACCEPTED)
@PostMapping(value = "v1/activity/{activityid}/signup", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public CompletableFuture<ActivitySignupRs> signup(
        @PathVariable("activityid") String activityid,
        @Valid @RequestBody ActivitySignupRq activitySignupRq) {
    CompletableFuture<ActivitySignupRs> cf = CompletableFuture.supplyAsync(() -> {
        Long sequenceNumber = twitterSnowFlake.nextId();
        return new ActivitySignupRs(sequenceNumber);
    });
    return cf;
}

測試下來 A寫法的吞吐量比較高也比較快,沒必要的 Future 會增加額外的 thread 切換

應該是要把 IO 耗時的部分(讀檔或呼叫API)包起來就好了

Future 用在同時呼叫多個耗時作業效果會很好

已經異步了但總吞吐量不高

異步處裡也還是需要 thread 來作業,但是我們並沒有關心是誰的 thread 來作業,

其實是由 tomcat 的 threadpool 來支援,這樣對內對外都是共用一個pool,thread的總量是一樣的

你可以在 springboot @EnableAsync

並配置一個額外的 ThreadPool

@Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
    ThreadPoolExecutor threadpool = new ThreadPoolExecutor(
            64,
            256,
            5,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue(2000),
            new ThreadPoolExecutor.CallerRunsPolicy());
    return threadpool;
}

然後在運行時指定 threadpool 來提供 thread 資源

@Async(value = "threadPoolTaskExecutor")
public void signup(String activityid, ActivitySignupRq activitySignupRq, Long sequenceNumber) {
    //.....

}

這樣你的 tomcat thread 就可以釋放回去

也可以用在 spring data 上

@Repository
public interface UserRepAsync extends PagingAndSortingRepository<User, Long> {
    @Async("threadPoolTaskExecutor")
    CompletableFuture<List<User>> findByCardNo(String cardNo);
}

需要回傳值的時候

@Async
public CompletableFuture<User> findUser(String user) throws InterruptedException {
    String url = String.format("https://api.github.com/users/%s", user);
    User results = restTemplate.getForObject(url, User.class);
    // Artificial delay of 1s for demonstration purposes

    Thread.sleep(1000L);
    return CompletableFuture.completedFuture(results);
}

多任務並行

// Kick of multiple, asynchronous lookups

CompletableFuture<User> page1 = gitHubLookupService.findUser("PivotalSoftware");
CompletableFuture<User> page2 = gitHubLookupService.findUser("CloudFoundry");
CompletableFuture<User> page3 = gitHubLookupService.findUser("Spring-Projects");

// Wait until they are all done

CompletableFuture.allOf(page1,page2,page3).join();

// Print results, including elapsed time

logger.info("Elapsed time: " + (System.currentTimeMillis() - start));
logger.info("--> " + page1.get());
logger.info("--> " + page2.get());
logger.info("--> " + page3.get());

參考資料

【并发】基于 @Async和 CompletableFuture 实现并发异步操作 - ssslinppp - 博客园

← springboot create ThreadPool

原文  http://samchu.logdown.com/posts/2286646-springboot-performance-turning
正文到此结束
Loading...