在 Web 应用程序中使用 RxJava Observables 无法解释性能改进

2023-12-24

我正在执行一些测试来评估使用基于 Observables 的反应式 API(而不是阻塞式传统 API)是否具有真正的优势。

整个例子是可以在 Github 上找到 https://github.com/codependent/spring-nio-rest

令人惊讶的是,结果表明吞吐量结果是:

  • The best:返回的 REST 服务Callable/DeferredResult包装阻塞操作。

  • 没有那么糟糕:阻止 REST 服务。

  • 最不好:返回 DeferredResult 的 REST 服务,其结果由RxJava 可观察的.

这是我的 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,但我仍然得到相同的结果。


该问题是由某个时刻的编程错误引起的。实际上问题中的例子效果很好。

防止他人出现问题的一个警告:小心使用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;
}

我开始了一个讨论RxJava 谷歌小组 https://groups.google.com/forum/#!topic/rxjava/B5s2Cm_Luko他们帮助我解决了这个问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Web 应用程序中使用 RxJava Observables 无法解释性能改进 的相关文章

随机推荐

  • 如何在 HSQLDB GUI 中执行多个命令?

    我想从 GUI 执行许多命令 我想做很多这样的小组 但我无法让一个小组工作 我想我需要以某种方式强制他们之间的提交 但我不知道如何做到这一点 如果我按顺序单独执行这些命令中的每一个 一切都会按预期进行 我正在使用EPSG dat来自 Geo
  • Google Cloud Vision 的 Advanced_ocr_options[] 是什么?

    我正在尝试查找有关的任何信息advanced ocr options under of ImageContext https cloud google com vision docs reference rest v1 ImageConte
  • uWSGI根据环境变量设置配置

    请帮助我理解uWSGI配置逻辑 我有一个环境变量ENVIRONMENT 假设它的值可以是dev or prod 我想根据以下值设置配置选项ENVIRONMENT always executes print statement doesn t
  • 重塑数组中的数组

    我有一个由 40 个数组组成的数组 每个数组都有 1x150 的形状 有没有办法重塑数组 以便我有 40 个 3x50 数组的数组 我不确定是否有一种方法可以使用 np reshape 并在一行中完成 是吗 这真的是一个arraynp ar
  • Qt 中的 QPointer、QSharedPointer 和 QWeakPointer 类有什么区别?

    我从 Qt 文档中读到了有关QPointer QSharedPointer and QWeakPointer类 它说 QPointer是一个模板类 它为 Qt 对象提供受保护的指针 其行为类似于普通的 C 指针 只不过当引用的对象被销毁并且
  • 如何限制正则表达式捕获组?

    我不明白如何限制捕获组 如果我有这样的正则表达式 w 2 s w 2 4 15 我认为这会捕获任何字符串 正好两个字 每个单词至少 2 个字符长 并且整个字符串不超过 15 个字符 但是我的捕获组的限制不起作用 我可以限制捕获组吗 附言 我
  • 使用golang http包时如何限制客户端IP地址

    我正在使用 golanghttp包裹 服务器如何限制客户端IP地址 func s Worker Run c chan error apiMux http NewServeMux apiMux HandleFunc test s test a
  • 如何向 NSDictionary 添加布尔值?

    好吧 对于整数我会使用NSNumber 但我猜 YES 和 NO 不是对象 AFAIK 我只能将对象添加到NSDictionary right 我找不到任何布尔值的包装类 有没有 您使用 NSNumber 它有 init 和 number
  • 如何在 debian 64 位上正确安装 wkhtmltopdf?

    我正在尝试安装 wkhtmltopdf 但是当我这样做时 sudo dpkg i wkhtmltox 0 12 1 linux trusty amd64 deb I get Preparing to unpack wkhtmltox 0 1
  • 如何在 C++ 中使用 MethodInvoker?

    我有一个 C CLI 应用程序 它有一个后台线程 我经常希望它把结果发布到主 GUI 上 我读了SO 上的其他地方 https stackoverflow com questions 1136399 how to update textbo
  • 在 Linq 组中查找最大和最小日期时间

    我正在尝试找到最大值和最小值DateTime来自 CSV 导入 我有这个来从临时导入数据DataTable var tsHead from h in dt AsEnumerable select new Index h Field
  • 圆中矩形的最大堆积

    我在一家纳米技术实验室工作 负责硅晶圆切割 晶圆锯仅切割平行线 当然 我们正在努力最大化我们切割的芯片的产量 所有芯片的尺寸都相同 无论是矩形还是正方形 并且芯片都是从圆形晶圆上切下来的 本质上 我试图将最大的矩形打包成一个圆 我对 MAT
  • 连接两个表的查询

    我是MYSQL的新手 对此的任何帮助将不胜感激 我有两个表 Airports 和 Posts 其中包含以下字段 Airports id Airport code Airport name Posts id Source Airport co
  • 将 Velocity 的 WebappResourceLoader 与 Spring 结合使用

    我正在尝试使用 Velocity 创建一个由 Spring 的 JavaMailSender 类邮寄的电子邮件模板 我决定使用 WebappResourceLoader 在我的 Web 应用程序中查找 Velocity 模板 它位于 Vel
  • R 中的数字列名

    我有一个数据框如下 structure list 104 c NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA yes NA NA NA NA 15 c NA NA NA NA gt 4 0 gt 4
  • 在Qt中,对于上下文菜单项,如何隐藏图标的空间

    我正在使用添加上下文菜单QAction对于一个小部件 现在 操作文本旁边有一些空白 我认为这是一个空间QIcon与QAction应该在那里 现在我该如何隐藏这个空间 我尝试这样做 action gt setIcon QIcon 但似乎仍然不
  • 为什么 proguard 只是混淆了没有扩展任何内容的类

    我正在尝试用 proguard 来混淆我的 Android 应用程序 但问题是 当我反编译 apk 时 它只显示更改的变量名称 但类名称与源中的相同 只有一个类的名称发生了更改 这不会扩展任何其他类 我搜索了很多选项 但没有任何效果 所以我
  • 您可以在哪里找到或者如何创建 Chrome 扩展密钥并将其放入您的 manifest.json 文件中?

    希望在我的 Chrome 扩展中实现 Oauth2 我一直在研究如何在 chrome 扩展上实现 oauth2 我已经被困了很长一段时间了 我最终获得了在 background ts 文件中使用 chrome identity 的信息 这是
  • SelectListItem selected = true 在视图中不起作用

    我有一个性别选择字段 选择 男性 女性 我将其填充到我的控制器中 页面加载时 我想要在模型中选择的性别pm Gender页面加载时自动选择 值来自pm Gender回来时为 M F View 控制器 gender new Select Ma
  • 在 Web 应用程序中使用 RxJava Observables 无法解释性能改进

    我正在执行一些测试来评估使用基于 Observables 的反应式 API 而不是阻塞式传统 API 是否具有真正的优势 整个例子是可以在 Github 上找到 https github com codependent spring nio