在Web应用程序中使用RxJava可观测项无法解释的性能改进不足
我正在执行一些测试,以评估使用基于可观察的反应式API,而不是阻塞传统API是否有真正的优势 整个例子是 令人惊讶的是,结果显示,thoughput结果如下:在Web应用程序中使用RxJava可观测项无法解释的性能改进不足,java,reactive-programming,rx-java,netflix,Java,Reactive Programming,Rx Java,Netflix,我正在执行一些测试,以评估使用基于可观察的反应式API,而不是阻塞传统API是否有真正的优势 整个例子是 令人惊讶的是,结果显示,thoughput结果如下: 最佳:返回包装阻塞操作的可调用/延迟结果的REST服务 还不错:阻止REST服务 最差的:返回延迟结果的REST服务,其结果由RxJava Observable设置 这是我的Spring WebApp: 应用程序: @SpringBootApplication public class SpringNioRestApplication
- 最佳:返回包装阻塞操作的
/可调用
的REST服务延迟结果
- 还不错:阻止REST服务
- 最差的:返回延迟结果的REST服务,其结果由RxJava Observable设置
@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();
}
}
同步控制器:
@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();
}
}
阻塞:大约404 RPM,但会产生错误
>>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
与可观察的异步:不超过20 rpm,并更快地获取错误
>>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以10的corePoolSize执行,但将其增加到50也没有任何改善
原因是什么
更新:根据阿卡诺克的建议,我做了以下更改。在服务中从Object.create移动到Object.fromCallable,并在控制器中重新使用了调度程序,但仍然得到了相同的结果。该问题是由某个点的编程错误引起的。实际上,问题中的例子非常有效 防止其他人出现问题的一个警告是:当心使用
Observable.just(func)
,func实际上是在创建Observable时调用的。因此,放置在那里的任何Thread.sleep都将阻止调用线程
@Override
public Observable<List<Data>> loadDataObservable() {
return Observable.just(generateData()).delay(500, TimeUnit.MILLISECONDS);
}
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);
}
return dataList;
}
@覆盖
公共可观察负载DataObservable(){
返回Observable.just(generateData()).delay(500,TimeUnit.ms);
}
私有列表生成数据(){
List dataList=new ArrayList();
对于(int i=0;i<20;i++){
数据数据=新数据(“键”+i,“值”+i);
dataList.add(数据);
}
返回数据列表;
}
我在他们帮助我解决问题的地方开始了讨论。你能用
可观察的。fromCallable
代替可观察的。创建?您对create
的使用似乎有些奇怪。此外,Thread.sleep不能保证精确的睡眠量,但取决于操作系统。在getVideoInfoAsync
中,您正在不必要地反复创建调度程序包装。您好,阿卡诺克,谢谢您的评论。有几件事,使用Observable.create有什么不对?我也不明白你所说的“一遍又一遍地创建调度器包装器”是什么意思。为了实现它,我遵循了我所看到的,一开始不调用s.onCompleted(),但是缺少处理取消订阅也可能有问题。此外,您应该了解故障是什么,这也可能表明性能损失的来源。您有一个TaskExecutor作为成员字段,但随后使用Scheduler.wrap对getVideoInfoAsync
的每次调用进行包装,我猜每秒会发生数百次。嗯,我还在原始示例中添加了s.onCompleted()
,但也没有改进。我在控制台中看到的唯一错误是o.a.c.c.c.[Tomcat].[localhost]:异常处理错误页[errorCode=0,location=/error]java.lang.IllegalStateException:提交响应后无法转发
我会将observable更改为observable.just并返回一些模拟对象,以排除RxJava的任何缺陷。由于RxJava不做网络,我想您应该有一个框架来做它。根据错误消息,这个框架可能配置错误、过时或只是有缺陷。那么,最终结果是什么呢?结果是Observable的性能比使用Callable略好。
@Override
public Observable<List<Data>> loadDataObservable() {
return Observable.just(generateData()).delay(500, TimeUnit.MILLISECONDS);
}
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);
}
return dataList;
}