添加更多控制器时 Spring mvc 性能显着下降

Posted

技术标签:

【中文标题】添加更多控制器时 Spring mvc 性能显着下降【英文标题】:Spring mvc performance drops significantly when adding more controllers 【发布时间】:2017-06-06 21:14:12 【问题描述】:

在我提出问题之前,请注意,实际数字并不代表性能。重要的是它们相对于彼此的价值,以及我在两次运行之间得到一致的数字(当然是在一个小范围内)这一事实。

所以,我在 Jetty 上运行了以下 Spring Boot 应用程序:

// Application.java
package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application 
    public static void main(String[] args) 
        SpringApplication.run(Application.class, args);
    


// HelloController1.java
package hello;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/v1/foo/foo/bar/bar/dog")
@RestController
public class HelloController1 
    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity<String> m() 
        return ResponseEntity.ok("dog");
    


使用这些 Maven 依赖项:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>LATEST</version>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jetty</artifactId>
        <version>LATEST</version>
    </dependency>
</dependencies>

唯一的配置属性集是:logging.level.org.springframework.web=ERROR


我使用wrk 对应用程序进行基准测试:

wrk -t 10 -c 10 -d 40s http://localhost:8080/v1/foo/foo/bar/bar/dog

我每秒收到一致的 45K 请求。

现在,我再添加 4 个控制器,除了类名和请求路径之外,与上面的相同:

    HelloController2 -> /v1/foo/foo/bar/bar/giraffe HelloController3 -> /v1/foo/foo/bar/bar/cat HelloController4 -> /v1/foo/foo/bar/bar/tacocat HelloController5 -> /v1/foo/foo/bar/bar/parrot

现在,如果我再次运行测试,我平均只能获得 35K RPS。

我希望第二个测试得到更低的值,尤其是因为这 5 个路由共享相同的前缀 - 我可以想象一些实现可能比其他实现更差 - 但 20 % 似乎很多。

在我开始深入研究 spring (boot) 源代码之前,我希望这里可能有人熟悉路由器/匹配器的实现并能弄清楚发生了什么。为什么会有这么大的 RPS 差异?


浏览一下 Spring 源代码后进行编辑。如果我错了,请纠正我:

似乎路由路径匹配器对每个请求的所有可用路由路径进行线性搜索。对于每个路由路径,如果它没有模式,它只是进行字典查找,一切都很好。但是,如果路径有参数(如我的示例中的foobar),它必须转到AntMatcher 以匹配实际路径。匹配器进行从左到右的搜索,因此一旦找到不匹配的内容就会失败。由于我的所有路由都以相同的模式开始,因此必须在每条路由上做很多工作,因此添加更多路由时性能会变差。

顺便说一句,我愿意接受有关如何使其表现更好的建议。我们的应用程序因此受到影响。

【问题讨论】:

您的编辑听起来很正确。这方面有一些改进;见jira.spring.io/browse/SPR-14544 【参考方案1】:

您可以在不更改 Spring 代码的情况下,重构您的代码以仅使用一个匹配所有有问题的模式的 RequestMapping,并自己编写一些性能算法以将调用委托给正确的类并传递参数。

你可以用 if 树和一些正则表达式开始算法,不要忘记编译正则表达式并将其保存到一个常量,这样你就不会有performance issues。

【讨论】:

【参考方案2】:

您可以通过以下几种方式表现得更好:

编写单个控制器并手动处理路径/v1/foo/foo/bar/bar/animal,并在控制器的每个方法中执行一个switch case 使用单个控制器并将模式委托给单个方法而不是类。如果有一个方法比其他方法执行得更频繁,请将其放在类的开头,以便将其作为第一个进行检查

【讨论】:

以上是关于添加更多控制器时 Spring mvc 性能显着下降的主要内容,如果未能解决你的问题,请参考以下文章

Spring MVC 和 javascript(添加 Rows 函数) 绑定

WebGL 警告:“属性 0 已禁用。这会显着降低性能”

Spring MVC 请求映射不起作用

spring MVC概述

如何在 Spring.Net 应用程序上下文中添加 ASP.NET MVC 控制器?

spring拦截器