你如何使用Spring 5的反应式编程实际“管理”最大网络线程数?
作者:互联网
使用经典的Tomcat方法时,您可以为服务器提供可用于处理来自用户的Web请求的最大线程数.使用Reactive Programming范例和Spring 5中的Reactor,我们能够更好地垂直扩展,确保我们最小化.
在我看来,这使得它比传统的Tomcat方法更易于管理,在经典的Tomcat方法中,您只需定义最大并发请求数.当您有最大并发请求数时,可以更轻松地估计应用程序所需的最大内存并相应地进行扩展.当你使用Spring 5的Reactive Programming时,这似乎更麻烦.
当我向系统管理员朋友讨论这些新技术时,他们会担心应用程序耗尽RAM,甚至是操作系统级别的线程.那么我们如何更好地处理这个问题呢?
解决方法:
在所有情况下都没有阻止I / O.
首先,如果您没有任何阻塞操作,那么您根本不应该担心我应该为管理并发提供多少线程.在这种情况下,我们只有一个工作程序异步和非阻塞地处理所有连接.在这种情况下,我们可以轻松扩展连接服务工作者,它们处理所有连接而没有争用和一致性(每个工作者都有自己的接收队列,每个工作者都在自己的CPU上工作),在这种情况下我们可以更好地扩展应用程序(没有任何设计).
简介:在这种情况下,您可以像以前一样,通过配置应用程序 – 容器(Tomcat,WebSphere等)或类似Netty或非混合Undertow等非Servlet服务器的类似方式来管理最大数量的webthread.好处 – 您可以处理muuuuu更多用户请求但具有相同的资源消耗.
阻止数据库和非阻塞Web API(例如NetF上的WebFlux).
如果我们应该以某种方式处理阻塞I / O,为了与DB通过阻止JDBC进行即时通信,尽可能保持应用程序的可扩展性和高效性,我们应该使用专用的线程池进行I / O.
线程池要求
首先,我们应该创建与JDBC连接池中的可用连接数量完全相同的线程池.因此,我们将拥有完全相同数量的线程,它将阻塞等待响应,并且我们尽可能有效地利用我们的资源,因此不再需要为实际需要的Thread堆栈消耗内存(换句话说,每个线程连接模型).
如何根据连接池的大小配置线程池
由于对特定数据库和JDBC驱动程序的属性访问是不同的,我们可能总是将该配置外部化到特定属性上,这反过来意味着它可以由devops或sysadmin配置.
Threadpool的配置(在我们的示例中,它配置Project Reactor 3的Scheduler)可能如下所示:
@Configuration
public class ReactorJdbcSchedulerConfig {
@Value("my.awasome.scheduler-size")
int schedulerSize;
@Bean
public Scheduler jdbcScheduler() {
return Schedulers.fromExecutor(new ForkJoinPool(schedulerSize));
// similarly
// ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
// taskExecutor.setCorePoolSize(schedulerSize);
// taskExecutor.setMaxPoolSize(schedulerSize);
// taskExecutor.setQueueCapacity(schedulerSize);
// taskExecutor.initialize();
// return Schedulres.fromExecutor(taskExecutor);
}
}
...
@Autowire
Scheduler jdbcScheduler;
public Mono myJdbcInteractionIsolated(String id) {
return Mono.fromCallable(() -> jpaRepo.findById(id))
.subscribeOn(jdbcScheduler)
.publishOn(Schedulers.single());
}
...
可以注意到,使用该技术,我们可以将共享线程池配置委托给外部团队(实例的sysadmins),并允许它们管理用于创建的Java线程的内存消耗.
保留阻塞I / O线程池仅用于I / O工作
此语句表示I / O线程应仅用于阻塞等待的操作.反过来,这意味着在线程完成等待响应之后,您应该将结果处理移动到另一个线程.
这就是为什么在上面的代码片段中我把.publishOn放在.subscribeOn之后.
总而言之,通过该技术,我们可以允许外部团队通过相应地控制线程池大小来控制连接池大小来管理应用程序大小调整.所有结果处理将在一个线程内执行,因此不会有冗余的,不受控制的内存消耗.
最后,阻塞API(Spring MVC)和阻塞I / O(数据库访问)
在这种情况下,根本不需要反应范式,因为你没有从中获得任何利润.首先,反应式编程需要特别的思维转移,特别是在理解使用RxJava或Project Reactor等Reactive库的功能技术时.反过来,对于未准备好的用户来说,它会带来更多复杂性并导致更多“这里有什么****** ???”.因此,如果从两端阻止操作,您应该三思而后行,这里真的需要Reactive Programming.
此外,没有免费的魔法. Reactive Extensions带有很多内部复杂性并使用所有神奇的.map,.flatMap等,你可能会失去整体性能和内存消耗,而不是像端到端非阻塞,异步通信那样获胜.
这意味着旧的良好命令式编程将更适合这里,并且使用旧的良好Tomcat配置管理更容易控制应用程序在内存中的大小调整.
标签:project-reactor,spring,tomcat,reactive-programming 来源: https://codeday.me/bug/20190823/1699552.html