我有一个spring引导应用程序,它在openshift集群的docker容器中运行。在稳定状态下,应用程序有N个实例(例如N=5),请求被负载平衡到这N个实例。一切运行正常,响应时间很短(约5ms,总吞吐量约60k)。
每当我添加一个新实例时,响应时间都会短暂增加(最高可达~70ms),然后恢复正常。
我能做些什么来避免这种冷启动吗?我试着通过在发送流量之前进行大约100个curl调用来预热应用程序,但这没有帮助?
我需要高并发的更好的预热脚本吗?有没有更好的方法来处理这件事?
谢谢
发布于 2019-02-27 21:21:23
如果您的应用程序在处理请求时运行状况良好,但仍然存在响应缓慢的问题,则应尝试启用分层编译
-XX:CompileThreshold -XX:TieredCompilation通常,VM使用解释器来收集有关提供给编译器的方法的分析信息。在分层方案中,除了解释器之外,客户端编译器还用于生成方法的编译版本,这些方法收集有关自身的分析信息。
由于编译后的代码比解释后的代码快很多,因此程序在分析阶段会以更好的性能执行。
发布于 2019-02-28 14:45:12
我们的微服务也遇到了类似的问题,为了预热,我们添加了一个组件
ApplicationStartup implements ApplicationListener<ApplicationReadyEvent> 在应用程序启动后立即调用服务,这对我们很有效。使用此解决方案,可以保证在有效负载中使用的所有类都将在每次启动的实例启动后加载,并且不需要外部脚本来进行调用。外部脚本也有问题,我们不能肯定地说调用是由新实例处理的。
@Component
public class ApplicationStartup implements ApplicationListener<ApplicationReadyEvent> {
@Autowired
YourService yourService;
@Override
public void onApplicationEvent(final ApplicationReadyEvent event) {
System.out.println("ApplicationReadyEvent: application is up");
try {
// some code to call yourservice with property driven or constant inputs
} catch (Exception e) {
e.printStackTrace();
}
}
} 发布于 2022-01-14 13:13:04
这个问题可以从两个方面来解决。第一种方法是在上菜前先热身。第二种方法是在开始时从外部发出更少的请求,这样就可以保留更多的计算资源来完成JVM的一些初始化(比如类加载)。无论哪种方式,这都是因为JVM需要预热才能启动。这是由JVM的操作原理决定的。特别是HotSpot虚拟机,其执行引擎由解释执行引擎和实时编译执行两部分组成。对于JIT,它需要CPU资源来实时编译字节码。此外,类的延迟加载在第一次运行时也需要更多的时间。
JVM预热主要解决类加载和实时编译两个问题。
对于类加载,只需提前运行重写代码路径即可。对于
对于上述两个方向,类加载本身将消耗更多的时间。热身这一部分将获得更大的投入产出比。
从网络层面来看,给出了一定的预热流量,可以是特定的预热流量,也可以是正常的用户请求。
这通常可以在用于流量控制的nginx层完成。当新启动的节点加入上游时,可以为新节点赋予非常低的权重。这样,在初始阶段只有少量的流量进入。因此,预留了足够的计算资源。执行代码预热,即类加载和实时编译。如果服务只提供RPC服务,而不提供HTTP服务,则RPC框架层可以进行流量预热。例如,Dubbo等RPC框架已经具备了服务预热功能。同样,预热意味着处于启动初始阶段的节点只提供少量的流量。
上述方法中都提到了预热所需的计算资源。也就是说,CPU。如果您的服务主机有足够的计算资源,您可以为每个节点分配更多的CPU资源,以加快预热过程。减少预热处理时间。
如果上面的网络层和硬件资源以及RPC框架不能改变。我们可以在SpringBoot微服务中预热。上面的答案已经提到了ApplicationReadyEvent,实际上更好的实现是侦听ContextRefreshedEvent事件。因为当ApplicationReadyEvent发生时,HTTP端口将被初始化并公开。在预热完成之前,可能会有意外的请求进入。
@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.....
}
}注意:上面的预热代码并没有预热所有的代码。因为来自控制器层的请求有一些代码路径,只有在HTTP服务器还没有准备好时才能实际执行。我们只能在服务层执行代码覆盖。简而言之,这可能是一种妥协。
https://stackoverflow.com/questions/54759652
复制相似问题