Spring WebFlux性能真的超过Spring Servlet ? - Gavin


如何构建高性能系统一直是开发人员感兴趣的话题。很多业内人士提倡非阻塞编程的范式,表示基于非阻塞编程的应用相比传统的阻塞技术命令式编程,可以更高效地利用资源,实现更高的性能。
许多文章解释了非阻塞编程的好处,它似乎是一种优越且面向未来的解决方案。但是,如果没有第一手经验来证明,我不相信。为了找出真相,我使用 2 个不同的框架构建了同一个 Java 应用程序——Spring WebFlux(非阻塞)和 Spring Servlet(阻塞),然后进行了一系列实验,以比较两种实现之间的系统性能。令人惊讶的是,研究结果表明,在某些环境设置中,非阻塞编程并不总是比阻塞编程更好。
在本文中,您将了解有关 Spring WebFlux 的真相。我将与您分享我的实验细节和性能测试结果的分析。
 
什么是阻塞和非阻塞?
回到基础。什么是阻塞?在传统的计算机编程中,每一行程序代码都是一条同步指令执行。换句话说,机器一个接一个地运行程序逻辑,直到当前指令完全执行后才会执行下一行代码。
使用阻塞编程实现的此类系统通常性能非常好。但是,如果任何进程的执行需要时间才能完成,系统线程就会卡住,如果情况恶化,将导致系统崩溃。
相反,非阻塞编程以发布-订阅模式实现程序逻辑。主程序流运行进程并订阅结果。主程序不会被当前流程执行“阻塞”,而是继续流程并立即运行下一个流程。流程执行完成后,通过回调通知主程序,以继续执行程序逻辑。
理论上,非阻塞编程实现了并行性。更重要的是,它不会阻塞任何不专用于任何请求的系统线程,并且线程池处理任何已发布的回调。
 
 
Java Spring 如何支持这两种范式?
Java Spring 在 2 个独立的技术栈中支持阻塞和非阻塞编程——Spring Servlet(阻塞)和 Spring WebFlux(非阻塞)。由于系统线程模型的机制不同,两种实现的底层技术有很大的不同。
 
性能测试实现
示例应用程序是一个 Spring Boot API,它提供了外汇汇率查询和外币交易功能。该系统依靠外部 API 获取最新汇率并提供货币对的买入和卖出价格。
现在,让我们看看性能测试设计。负载测试是使用强大的工具 Gatling 构建的。在 30 秒内将用户每秒的负载注入量从 10 个增加到 40 个,然后在 30 秒内保持每秒 40 个用户的恒定注射量。
为了模拟现实生活中的情况,每个用户都被分配了一个用户旅程来提交用于汇率查询、汇率预订和交易提交的 API 请求。
有关测试场景设计以及如何使用 Gatling 构建负载测试的详细信息,请参阅本文
..更多点击标题
  
假设有一个非常慢的外部 API,在更重的工作负载下有什么区别?
预计当工作量增加一倍而外部 API 仍然很慢时,情况会更糟。哪种实施可以在艰难的情况下幸存下来?
要使工作负载加倍,请运行此命令行以使用参数来触发 Gatling 负载测试,以指定每秒初始用户数和每秒目标用户数。
结果表明,Spring Servlet 无法处理大部分请求,失败率高达 89%。相反,Spring WebFlux 仍然可以在恶劣的条件下生存,尽管失败率增加了 17%,响应时间在 30 秒左右。
 
结论
测试证明,基于非阻塞技术的应用总体上优于传统的阻塞技术。尽管在 I/O 进程访问外部API很快的理想环境中,非阻塞技术的威力是看不出来的,但这种技术是有优势的,在现实生活中肯定会实现更快的响应时间和更低的故障率,因为外部 API 和持久存储可能由于各种原因,并不总是达到预期的服务水平,尤其是服务因大量传入流量而不堪重负。
因此,在使用 Java 进行 API 开发时,Spring WebFlux 是优于 Spring Servlet 的推荐框架。在您的新 API 开发中采用此框架是值得投入时间和资源的。