Spring Boot是一个纯粹的“运行时”框架。
如果我理解你的问题正确,你描述的情况如下:
比如说你有一个带有JDK和一些jar包的容器A。但这本身并不意味着你有一个正在运行的进程。所以更像是一个准备重复使用的文件卷(或者在docker镜像方面的一个层)。
此外,你还有另一个容器B,其中包含一个应该以某种方式启动的Spring Boot应用程序(可能使用容器A中的OpenJDK或其专用JDK)。
现在你到底想要“加速”什么?镜像大小(更小的镜像意味着在CI/CD流水线中更快的部署)?Spring Boot应用程序启动时间(从生成JVM到Spring Boot应用程序启动运行的时间间隔)?或者你试图在运行时加载更少的类?
解决这些问题的技术是不同的。但总的来说,我认为你可能需要查看Graal VM集成,其中包括创建本机映像并加速启动时间的功能。这些东西相当新,我自己还没有尝试过。我相信这还在进行中,Spring将努力推动这一进展(这只是我的猜测,所以不要过分相信)。
无论如何,您可能会对阅读这篇文章感兴趣
然而,我怀疑它与您描述的研究有关。
更新1
根据您的评论-让我给出一些额外的信息,可能有所帮助。此更新包含来自“现实生活”工作经验的信息,我发布它是因为它可能有助于在您的论文中找到方向。
所以,我们首先有一个spring boot应用程序。
默认情况下,它是一个JAR文件,并且Pivotal建议提供WAR选项(正如他们的开发者代言人Josh Long所说:“制作JAR而不是WAR”)
这个spring boot应用程序通常包括一些Web服务器-传统的Spring Web MVC应用程序默认使用Tomcat,但您可以将其切换为Jetty或undertow。如果您正在运行“反应式应用程序”(Spring WebFlux自spring boot 2以来支持),则默认选择为Netty。
需要注意的是,并非所有使用Spring Boot驱动的应用程序都必须包含某种嵌入式Web服务器,但我将忽略这个微妙的点,因为您似乎针对Web服务器的情况(您提到了Tomcat,更快地处理请求等),因此我假设您是在关注此方面。
现在,让我们尝试分析启动Spring Boot应用程序JAR时发生的情况。
首先,JVM本身开始运行 - 进程启动,堆分配,内部类加载等等。这可能需要一些时间(大约需要1秒甚至更长时间,具体取决于服务器、参数、硬盘速度等)。
这个线程讨论了JVM是否真的启动缓慢,我可能无法为此添加更多内容。
好的,现在是时候加载Tomcat的内部类了。这又可以在现代服务器上花费几秒钟。Netty似乎更快,但您可以尝试下载Tomcat的独立发行版并在计算机上启动它,或者创建一个没有Spring Boot但有嵌入式Tomcat的示例应用程序来看看我在说什么。
到目前为止,我们的应用程序还没有出现问题。正如我在开始时所说,Spring Boot 是一个纯运行时框架。因此,必须加载 Spring/Spring Boot 本身的类,然后加载应用程序本身的类。如果应用程序使用某些库,它们也会被加载,有时甚至会在应用程序启动期间执行自定义代码:Hibernate 可以检查模式和/或扫描数据库模式定义,甚至更新底层模式,Flyway/Liquidbase 可以执行模式迁移等等,Swagger 可能会扫描控制器并生成文档等等。
现在,在“现实生活”中,这个过程甚至可能需要一分钟甚至更长时间,但这并不是因为 Spring Boot 本身,而是因为应用程序中创建的 bean 具有“构造函数”/“post-construct”中的一些代码——这是在 Spring Boot 应用程序上下文初始化期间发生的事情。另外一个副注,我不会真正深入研究 Spring Boot 应用程序启动过程的内部工作原理,Spring Boot 是一个非常强大的框架,在幕后进行了许多事情,我假设您以某种方式使用过 Spring Boot——如果没有,请随时就此提出具体问题——我/我的同事将尝试解决。
如果您访问
start.spring.io,可以创建一个示例演示应用程序 - 它将加载得非常快。因此,这完全取决于您的应用程序bean。
在这种情况下,到底应该优化什么?
您在评论中提到可能会有一个tomcat运行一些JAR文件,以便它们不会在spring boot应用程序启动时加载。
好吧,正如我们的同事所提到的那样,这更像是我们这个行业“使用了大约20年”的“传统”Web Servlet容器/应用服务器模型。
这种部署方式确实有一个“始终运行”的JVM进程,它随时准备好接受你的应用程序的WAR文件 - 一种包含应用程序的归档文件。一旦检测到WAR文件被投放到某个文件夹中,它将通过创建分层类加载器并加载应用程序的JAR/类来“部署”该应用程序。在你的情况下,有趣的是可以将库“共享”给多个WAR,以便只加载一次。例如,如果你的Tomcat托管了3个应用程序(读取3个WAR),并且所有应用程序都使用Oracle数据库驱动程序,你可以将这个驱动程序的jar放到某个共享的
libs
文件夹中,它将仅由类加载器加载一次,这是每个“WAR”创建的类加载器的“父级”。这个类加载器层次结构非常重要,但我相信它超出了问题的范围。
我曾经使用过两种模型(基于Spring Boot驱动的嵌入式服务器模型,没有Spring Boot的嵌入式Jetty服务器和“老派”的Tomcat/JBoss部署)。
根据我的经验,并且随着时间的证明,我们许多同事都同意这一点,Spring Boot 应用在操作方面有很多更方便的原因(再次强调,这些原因超出了问题的范围,在我看来,请告诉我如果您需要更多信息),这就是为什么它是当前的“趋势”,而“传统”的部署方式仍然存在于行业中,因为有许多非纯技术原因(历史原因、系统已被定义为维护模式、您已经拥有部署基础设施、一支“系统管理员”团队“知道”如何进行部署等等,但归根结底没有纯粹的技术原因)。
现在有了所有这些信息,您可能更好地理解为什么我建议看一下 Graal VM,它将通过本地映像加快应用程序启动速度。
还有一个可能相关的问题。如果您选择能够快速启动的技术,那么您可能会进入 Amazon Lambda 或其他云提供商提供的替代方案。
这个模型允许“计算”能力(CPU)的无限扩展,他们会在幕后“启动”容器,并在检测到容器实际上没有什么事可做时立即“杀死”它们。对于这种应用来说,Spring Boot 简单地不能胜任,而基本上 Java 也是如此,因为 JVM 进程相对较慢启动,所以一旦像这样启动容器,直到它变得可操作,需要太长时间。
你可以阅读
这里 了解 Spring 生态系统在这个领域所提供的内容,但这并不与你的问题相关(我正在提供方向)。
当您需要一个可能需要一些时间来启动的应用程序,但一旦启动就可以非常快速地完成工作时,Spring Boot 发挥作用。是的,如果应用程序没有“占用”,则有可能停止应用程序(我们使用术语“扩展/缩减规模”),这种方法也是比较新的(~3-4年),最适合在像 kubernetes、amazon ECS 等“管理”的部署环境中使用。
容器
意味着隔离
。这就回答了你如何在容器之间使用共享库的问题。但是你可以通过阶段创建你的Docker镜像,比如一个库的镜像、一个应用程序的镜像、一个第三方应用程序的镜像,在运行时只需调用创建容器的组合即可。 - Dupinder Singh