为啥 Spring Rest 服务在第一次请求时很慢?

Posted

技术标签:

【中文标题】为啥 Spring Rest 服务在第一次请求时很慢?【英文标题】:Why are Spring Rest services slow on the first request?为什么 Spring Rest 服务在第一次请求时很慢? 【发布时间】:2020-11-11 03:06:41 【问题描述】:

所以这个问题已经被问过几次了,但似乎没有人以可以帮助我的方式回答它。我目前正在为处理产品数据的简单应用程序制作后端。它甚至没有 JSP,只是一个普通的 Rest 后端。使用 Spring 的 RestControllers。

“问题”是:启动后的第一个请求从服务器获得响应所需的时间比其他所有请求都要长。 (我只是用一个简单的 JPA 用户实体用 Postman 进行测试)

需要考虑的一些事项:

这本身可能不是数据库问题,因为它显然只是在第一次传入请求而不是启动时初始化某些内容 在日志中,当第一个实际请求进入(通过 Postman)时,它会显示“正在初始化 Spring DispatcherServlet 'dispatcherServlet'”。 如果我从数据库中拉出所有用户(目前只有一个用户),启动后的第一个请求需要 140 毫秒(根据 Postman)。之后,相同的请求始终需要最多 10 毫秒。 对于类似问题的建议有一个标志:spring.mvc.servlet.load-on-startup=1。虽然这只会删除上面提到的(DispatcherServlet 初始化的)日志记录。 这似乎是标准行为,与我实际编写实体和/或 RestController 的方式无关。

如何使第一个请求更快/如何强制 Spring 在第一个请求到来之前实际初始化所有内容?

还是有一些代码:

User.java:

@Entity
@Table(name = "users")
@Data
public class User 

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @NonNull
    private String firstName;
    @NonNull
    private String lastName;

    @NonNull
    @OneToOne(cascade = CascadeType.ALL)
    private Address billingAddress;

    //a bit more. a list and another address

UserController.java:

@RestController
@RequestMapping("users")
public class UserController 

    private final UserRepository userRepository;

    @Autowired
    public UserController(UserRepository userRepository) 
        this.userRepository = userRepository;
    

    @GetMapping()
    public List<User> getAllUsers() 
        return (List<User>) userRepository.findAll();
    

    //more stuff

【问题讨论】:

你是如何运行/部署应用程序的? IntelliJ 刚刚为我创建了一个运行配置。 (Spring Boot 应用程序) Spring 还是 Spring Boot?这会产生很大的不同,无论是否启用调试/开发工具(这也会产生影响)。您应该测试一个实际部署的,而不是一个需要调试等的。另外,您应该真正将 spring.mvc.servlet.load-on-startup 设置为 1 或更高(否则它将被延迟)。它不会删除日志记录,但现在它会被急切地实例化并启动。 是的,我的意思是 Spring Boot。而且 afaik 它没有开发工具,只是正常的日志记录。 K,我将它设置为 1。¯_(ツ)_/¯ 【参考方案1】:

你自己回答了这个问题。 Spring 中的很多东西都是惰性初始化,用于性能和资源消耗优化。用户真的会注意到一个请求需要 140 毫秒而不是 10 毫秒。可能不是。请注意,这不是每个用户一个请求,而是每次启动每个初始化路径一个请求。

话虽如此……您还回答了如何“修复”它。部署后(我假设这是通过 CI/CD 自动化的),您提交一个或多个请求(CI/CD 的一部分),这将触发您需要的所有路径的初始化。 IE。如果您有 5 个 db 连接,您可能需要提交 5 个请求来初始化所有内容。

这是完全可以接受的,并且是一个称为“系统预热”的过程。

【讨论】:

嗯,好的,我明白为什么这种延迟加载可能很好,但我仍然不明白为什么我不能在应用程序属性中设置一个标志,所以它不这样做。手动发送请求似乎是一种解决方法。但是,是的,你是对的,如果它只是第一个,那就没那么重要了。 @Panossa“热身”不是一种解决方法。它在基准标记、部署、汽车发动机、烤箱/烧烤(预热)、熨斗等方面的标准程序可以继续进行。很少有东西可以立即发挥全部性能。

以上是关于为啥 Spring Rest 服务在第一次请求时很慢?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在建立 httpSession 后 Wildfly 服务器不能处理并发 REST 请求

Spring Boot REST 服务:JSON 反序列化不起作用

为啥我的 REST 服务 .NET 客户端会在没有身份验证标头的情况下发送每个请求,然后使用身份验证标头重试?

使用 Spring Security 'hasPermission()' 在未经授权的 REST 服务请求上返回 JSON

如何在 Spring Boot 服务应用程序中的 REST 服务调用之间按原样传递请求参数?

如何将列表发布到 Spring Data Rest?