検証環境
- Spring Boot環境
- v2.5.0
- OS Windows10
- OpenJDK 16.0.1
- PostgreSQL環境
- v10.15
- OS Red Hat Enterprise Linux 8.4
- 仮想化環境 vmware workstation player 16.1.2 4core/メモリ8GB割り当て
- JMeter環境
- v5.4.1
- OS Windows10(Spring Bootと同居構成=本当はよくない。)
- jdk-8u291-windows-i586(最新版だと動かないので意図的に古い版を利用)
検証コード
package com.example.demo.controller;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(path="/jdbc")
public class JDBCController {
@Autowired
JdbcTemplate jdbcTemplate;
@RequestMapping(path="/id", method=RequestMethod.GET)
public String index() {
List<Map<String,Object>> list;
list = jdbcTemplate.queryForList("select name from test"); // indexのないキー検索
int recordCount = list.size();
return "HelloWorld:" + recordCount;
}
@RequestMapping(path="/id/{id}", method=RequestMethod.GET)
public String read(@PathVariable String id) {
List<Map<String,Object>> list;
list = jdbcTemplate.queryForList("select id from test where id = ?", id); // PK検索
return "HelloWorld:" + list.toString();
}
@RequestMapping(path="/process", method=RequestMethod.GET)
public String prooscess() {
String line = "";
int exitCode = 0;
try {
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("cmd.exe", "/c", "echo HelloWorld");
Process process = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String temp = null;
while ((temp = reader.readLine()) != null) {
line = line + temp;
}
exitCode = process.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
return line+ " rc:" + exitCode;
}
@RequestMapping(path="/hello", method=RequestMethod.GET)
public String hello() {
return "HelloWorld";
}
}
検証結果
検証シナリオ | 性能 | 備考 |
---|---|---|
"HelloWorld"を返すRESTコントローラ | 37000tps | |
PK検索結果を返すRESTコントローラ | 6800tps | |
indexなしで10000件スキャンして件数を返すRESTコントローラ | 340tps | |
indexなしで20000件スキャンして件数を返すRESTコントローラ | 160tps | 下記と同tpsを出すのに苦労しました。 |
ProcessBuilderでOSコマンド実行するRESTコントローラ | 160tps | OSプロセス起動のオーバーヘッドが大半 |
※いずれのシナリオも同じJMeter(Number of threads 200/Loop Count 500/Ramp-up 0)で負荷掛け実行。
結論
「JavaからのOSプロセス起動を多用する設計にしてしまうとCPUが何個あっても足りません!」ということを数字をもって示すことができました。