@Component
public class StartWarmUpListener implements ApplicationListener<ContextRefreshedEvent> {
/**
* Handle an application event.
*
* @param event the event to respond to
*/
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// do something about warm-up here.....
}
}
@Component
public class WarmUpListener implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
// Warm up
}
}
6条答案
按热度按时间qltillow1#
我们的微服务也遇到了类似的问题,为了预热,我们添加了一个组件
在应用程序内,在应用程序启动后立即调用服务,这对我们很有效。使用此解决方案,可以保证在您启动的每个示例中,将在有效负载中使用的所有类都将在示例启动后立即加载,并且您不需要外部脚本来进行调用。外部脚本的问题也是如此,我们无法确定调用是否由新示例处理。
ma8fv8wu2#
如果在向应用程序提供请求时应用程序运行正常,但仍然存在响应缓慢的问题,则应尝试启用分层编译
通常,VM使用解释器来收集方法的分析信息,这些信息被馈送到编译器中。在分层方案中,除了解释器之外,客户端编译器被用来生成方法的编译版本,这些方法收集关于它们自身的分析信息。
由于编译的代码比解释的代码快得多,因此程序在性能分析阶段的执行性能更好。
9w11ddsr3#
这个问题可以从两个方面来解决,第一种方法是在服务之前先预热一下自己,第二种方法是在开始的时候少给予一些外界的请求,这样就可以预留更多的计算资源来完成JVM的一些初始化(例如类别载入)。无论哪种方式,因为JVM启动需要预热,这是由JVM的工作原理决定的,特别是HotSpot虚拟机,它的执行引擎由两部分组成:解释执行引擎和实时编译执行(JIT)。对于JIT,需要CPU资源来实时编译字节码。此外,类的延迟加载在第一次运行时也需要更多的时间。
JVM预热主要解决类加载和实时编译两个问题。
对于以上两个方向,类加载本身会消耗更多的时间,预热这部分会得到更大的投入产出比。
1.网络层预热。
从网络级,给定一定量的预热流量,其可以是特定预热流量或正常用户请求。
这一般可以在nginx层进行流量控制,当一个新启动的节点加入上游时,可以给这个新节点一个很低的权值,这样在初始阶段只进入少量的流量,这样就预留了足够的计算资源,要做代码预热,也就是类加载和即时编译,如果服务只提供RPC服务,而不是HTTP服务,RPC框架层可以做流量预热,比如杜博等RPC框架已经有了服务预热功能,同样预热也是指启动初期的节点只给予少量的流量。
预热所需要的计算资源在上面的方法中都提到了,那就是CPU,如果你的服务主机有足够的计算资源,你可以给每个节点分配更多的CPU资源来加快预热的速度,减少预热处理的时间。
如果上面的网络层和硬件资源以及RPC框架都无法更改,我们可以在SpringBoot微服务内部预热一下,上面的答案已经提到了
ApplicationReadyEvent
,实际上更好的实现是侦听ContextRefreshedEvent
事件。因为当ApplicationReadyEvent发生时,HTTP端口将被初始化并公开。在warm-向上完成。注意:上面的预热代码并没有预热所有的代码。因为来自控制器层的请求有一些代码路径在HTTP服务器没有准备好之前不能实际执行。我们只能在服务层执行代码覆盖。简而言之,这可能是一种妥协。
eqfvzcg84#
首先,我会尝试启用JIT compilation并比较结果。这里有一个good article in Baeldung比较Graal与默认的C1和C2 JIT编译器的性能--您可能希望针对您的工作负载运行一些测试。基本上,在运行Java应用程序时,您需要设置以下选项:
-XX:+解除锁定实验VM选项-XX:+启用JVMCI-XX:+使用JVMCI编译器
此外,请确保您已经使用Sping Boot 的actuator健康检查URL(/actuator/health)进行了configured readiness probe in OpenShift。否则,您的容器可能会在准备好提供服务之前收到流量。
就绪探测确定容器是否已准备好为请求提供服务。如果就绪探测使容器失败,端点控制器将确保容器的IP地址已从所有服务的端点中删除。就绪探测可用于向端点控制器发出信号,表明即使容器正在运行,它不应接收来自代理的任何通信。通过配置Pod配置的template.spec.containers.readinessprobe节来设置就绪检查。
最后,让NGINX或其他反向代理缓存您的响应也会有所帮助。
pftdvrlh5#
在我的场景中,我模拟了100多个curl请求来初始化那些客户机池、预加载缓存或其他惰性加载工具。
我在
WarmupHealthIndicator implements HealthIndicator
上完成了这项工作,它实现了一个Spring执行器健康检查端点。最后,在预热完成之前,Nginx(或其他负载均衡器)的任何健康检查都将获得5xx状态代码,以及以下正文消息。2并且在状态启动后,应用程序初始化将不需要任何流量。
此外,
NGINX Plus
有一个付费功能slow_start,可以为您的兴趣做同样的事情。t40tm48m6#
当Sping Boot 应用程序启动时,JVM需要加载各种类进行初始化,导致HTTP请求的响应时间较长。
如果要预热http组件,可以参考:
或者试试这个 Boot 器:warmup-spring-boot-starter,可以在应用程序提供外部服务之前对HTTP相关组件进行预热,从而减少HTTP请求响应时间。