我正在执行一些测试来评估使用基于 Observables 的反应式 API(而不是阻塞式传统 API)是否具有真正的优势。
整个例子是可以在 Github 上找到 https://github.com/codependent/spring-nio-rest
令人惊讶的是,结果表明吞吐量结果是:
这是我的 Spring Web 应用程序:
应用:
@SpringBootApplication
public class SpringNioRestApplication {
@Bean
public ThreadPoolTaskExecutor executor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
return executor;
}
public static void main(String[] args) {
SpringApplication.run(SpringNioRestApplication.class, args);
}
}
同步控制器:
@RestController("SyncRestController")
@Api(value="", description="Synchronous data controller")
public class SyncRestController {
@Autowired
private DataService dataService;
@RequestMapping(value="/sync/data", method=RequestMethod.GET, produces="application/json")
@ApiOperation(value = "Gets data", notes="Gets data synchronously")
@ApiResponses(value={@ApiResponse(code=200, message="OK")})
public List<Data> getData(){
return dataService.loadData();
}
}
异步控制器:具有原始 Callable 和 Observable 端点
@RestController
@Api(value="", description="Synchronous data controller")
public class AsyncRestController {
@Autowired
private DataService dataService;
private Scheduler scheduler;
@Autowired
private TaskExecutor executor;
@PostConstruct
protected void initializeScheduler(){
scheduler = Schedulers.from(executor);
}
@RequestMapping(value="/async/data", method=RequestMethod.GET, produces="application/json")
@ApiOperation(value = "Gets data", notes="Gets data asynchronously")
@ApiResponses(value={@ApiResponse(code=200, message="OK")})
public Callable<List<Data>> getData(){
return ( () -> {return dataService.loadData();} );
}
@RequestMapping(value="/observable/data", method=RequestMethod.GET, produces="application/json")
@ApiOperation(value = "Gets data through Observable", notes="Gets data asynchronously through Observable")
@ApiResponses(value={@ApiResponse(code=200, message="OK")})
public DeferredResult<List<Data>> getDataObservable(){
DeferredResult<List<Data>> dr = new DeferredResult<List<Data>>();
Observable<List<Data>> dataObservable = dataService.loadDataObservable();
dataObservable.subscribeOn(scheduler).subscribe( dr::setResult, dr::setErrorResult);
return dr;
}
}
数据服务实现
@Service
public class DataServiceImpl implements DataService{
@Override
public List<Data> loadData() {
return generateData();
}
@Override
public Observable<List<Data>> loadDataObservable() {
return Observable.create( s -> {
List<Data> dataList = generateData();
s.onNext(dataList);
s.onCompleted();
});
}
private List<Data> generateData(){
List<Data> dataList = new ArrayList<Data>();
for (int i = 0; i < 20; i++) {
Data data = new Data("key"+i, "value"+i);
dataList.add(data);
}
//Processing time simulation
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return dataList;
}
}
我已经设置了一个Thread.sleep(500)
延迟以增加服务响应时间。
负载测试的结果是:
异步与可调用:700 rps,无错误
>>loadtest -c 15 -t 60 --rps 700 http://localhost:8080/async/data
...
Requests: 0, requests per second: 0, mean latency: 0 ms
Requests: 2839, requests per second: 568, mean latency: 500 ms
Requests: 6337, requests per second: 700, mean latency: 500 ms
Requests: 9836, requests per second: 700, mean latency: 500 ms
...
Completed requests: 41337
Total errors: 0
Total time: 60.002348360999996 s
Requests per second: 689
Total time: 60.002348360999996 s
Blocking:大约 404 rps 但会产生错误
>>loadtest -c 15 -t 60 --rps 700 http://localhost:8080/sync/data
...
Requests: 7683, requests per second: 400, mean latency: 7420 ms
Requests: 9683, requests per second: 400, mean latency: 9570 ms
Requests: 11680, requests per second: 399, mean latency: 11720 ms
Requests: 13699, requests per second: 404, mean latency: 13760 ms
...
Percentage of the requests served within a certain time
50% 8868 ms
90% 22434 ms
95% 24103 ms
99% 25351 ms
100% 26055 ms (longest request)
100% 26055 ms (longest request)
-1: 7559 errors
Requests: 31193, requests per second: 689, mean latency: 14350 ms
Errors: 1534, accumulated errors: 7559, 24.2% of total requests
与 Observable 异步: 不超过 20 rps,并且更快出错
>>loadtest -c 15 -t 60 --rps 700 http://localhost:8080/observable/data
Requests: 0, requests per second: 0, mean latency: 0 ms
Requests: 90, requests per second: 18, mean latency: 2250 ms
Requests: 187, requests per second: 20, mean latency: 6770 ms
Requests: 265, requests per second: 16, mean latency: 11870 ms
Requests: 2872, requests per second: 521, mean latency: 1560 ms
Errors: 2518, accumulated errors: 2518, 87.7% of total requests
Requests: 6373, requests per second: 700, mean latency: 1590 ms
Errors: 3401, accumulated errors: 5919, 92.9% of total requests
Observable 执行时的 corePoolSize 为 10,但将其增加到 50 也没有任何改善。
可以作什么解释呢?
UPDATE:根据 akarnokd 的建议,我做了以下更改。在服务中从 Object.create 移至 Object.fromCallable 并在控制器中重用 Scheduler,但我仍然得到相同的结果。