over 5 years ago
紀錄一下因壓力測試做過各種調整
就用預設的 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 - 博客园