【问题标题】:Spring Boot startup slow on Raspberry PIRaspberry PI 上的 Spring Boot 启动缓慢
【发布时间】:2018-01-06 13:42:39
【问题描述】:

将 Spring Boot 2 用于 IoT 应用程序,我注意到 Spring 的启动时间异常缓慢。该平台是 Raspberry PI 2B - 当然,这将比 PC 慢得多。对于正常的代码执行,我测量了 20 倍到 50 倍的差异。

  • 我的 PC (Win10 x64) 上的 Spring Boot 启动时间:5 秒
  • 在 PI 上的 Spring boot 启动时间(Ubuntu Server,ARM java in docker running a jar):11 分钟

如果我使用我曾经测量过的最高因子 (50x),我希望看到的启动时间不到当前状态的一半。到目前为止,我尝试过:

  • 从自动配置中排除依赖项(现在最小化,只有 spring-boot-starter-web、kotlin、undertow、webflux、reactor 和 kafka)
  • 登录 DEBUG 以查看在安静期间发生的情况(主要是设置 bean,没有任何可疑之处,尽管有些 bean 需要几秒钟才能加载)
  • ARM 上 Java 的不同 docker 映像(无效)
  • CPU 始终保持在 100%,内存在 20% 左右,磁盘空间充足

我的初步结论是加载 bean 会占用所有 CPU 周期。我想初始化一个bean不应该花费几秒钟,但确实如此。这里的瓶颈可能是什么?我能以任何方式让 Spring 加载得更快吗?


这是 PC 输出的第一部分:

2018-01-06 13:43:03.462  INFO 9144 --- [           main] c.e.b.BasestationApplicationKt           : Starting BasestationApplicationKt on GPC with PID 9144 (C:\Data\Code\app\git\basestation\out\production\classes started by User in C:\Data\Code\app\git)
2018-01-06 13:43:03.471  INFO 9144 --- [           main] c.e.b.BasestationApplicationKt           : The following profiles are active: dev
2018-01-06 13:43:03.637  INFO 9144 --- [           main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@294e5088: startup date [Sat Jan 06 13:43:03 CET 2018]; root of context hierarchy
2018-01-06 13:43:05.578  INFO 9144 --- [           main] org.xnio                                 : XNIO version 3.3.8.Final
2018-01-06 13:43:05.600  INFO 9144 --- [           main] org.xnio.nio                             : XNIO NIO Implementation Version 3.3.8.Final
2018-01-06 13:43:05.695  WARN 9144 --- [           main] io.undertow.websockets.jsr               : UT026009: XNIO worker was not set on WebSocketDeploymentInfo, the default worker will be used
2018-01-06 13:43:05.695  WARN 9144 --- [           main] io.undertow.websockets.jsr               : UT026010: Buffer pool was not set on WebSocketDeploymentInfo, the default pool will be used
2018-01-06 13:43:05.721  INFO 9144 --- [           main] io.undertow.servlet                      : Initializing Spring embedded WebApplicationContext
2018-01-06 13:43:05.722  INFO 9144 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 2088 ms
2018-01-06 13:43:05.851  INFO 9144 --- [           main] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]
2018-01-06 13:43:05.857  INFO 9144 --- [           main] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-01-06 13:43:07.323  INFO 9144 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/],methods=[GET]}" onto public com.app.basestation.model.Message com.app.basestation.BasestationController.home()
2018-01-06 13:43:07.330  INFO 9144 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2018-01-06 13:43:07.349  INFO 9144 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2018-01-06 13:43:07.509  INFO 9144 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@294e5088: startup date [Sat Jan 06 13:43:03 CET 2018]; root of context hierarchy
2018-01-06 13:43:08.519  INFO 9144 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-01-06 13:43:08.553  INFO 9144 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 2147483647
2018-01-06 13:43:08.678  INFO 9144 --- [           main] o.s.b.w.e.u.UndertowServletWebServer     : Undertow started on port(s) 11112 (http)

以及 PI 的输出:

2018-01-06 12:48:41.689  INFO 1 --- [           main] c.e.b.BasestationApplicationKt           : Starting BasestationApplicationKt on ubuntu with PID 1 (/app.jar started by root in /)
2018-01-06 12:48:42.019  INFO 1 --- [           main] c.e.b.BasestationApplicationKt           : The following profiles are active: prd
2018-01-06 12:48:49.827  INFO 1 --- [           main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@128c152: startup date [Sat Jan 06 12:48:49 UTC 2018]; root of context hierarchy
2018-01-06 12:54:05.276  INFO 1 --- [           main] org.xnio                                 : XNIO version 3.3.8.Final
2018-01-06 12:54:08.404  INFO 1 --- [           main] org.xnio.nio                             : XNIO NIO Implementation Version 3.3.8.Final
2018-01-06 12:54:15.847  WARN 1 --- [           main] io.undertow.websockets.jsr               : UT026009: XNIO worker was not set on WebSocketDeploymentInfo, the default worker will be used
2018-01-06 12:54:15.852  WARN 1 --- [           main] io.undertow.websockets.jsr               : UT026010: Buffer pool was not set on WebSocketDeploymentInfo, the default pool will be used
2018-01-06 12:54:19.930  INFO 1 --- [           main] io.undertow.servlet                      : Initializing Spring embedded WebApplicationContext
2018-01-06 12:54:19.934  INFO 1 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 330155 ms
2018-01-06 12:54:42.544  INFO 1 --- [           main] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]
2018-01-06 12:54:43.206  INFO 1 --- [           main] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-01-06 12:57:18.683  INFO 1 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/],methods=[GET]}" onto public com.app.basestation.model.Message com.app.basestation.BasestationController.home()
2018-01-06 12:57:19.734  INFO 1 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2018-01-06 12:57:19.758  INFO 1 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2018-01-06 12:57:44.597  INFO 1 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@128c152: startup date [Sat Jan 06 12:48:49 UTC 2018]; root of context hierarchy
2018-01-06 12:59:36.677  INFO 1 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-01-06 12:59:37.807  INFO 1 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 2147483647
2018-01-06 12:59:42.664  INFO 1 --- [           main] o.s.b.w.e.u.UndertowServletWebServer     : Undertow started on port(s) 11112 (http)

【问题讨论】:

  • 我注意到使用 OpenJDK 和 Oracle SDK(特别是 Linux ARM 32 Hard Float ABI)之间的巨大差异。对于我执行的 Spring Boot 应用程序,使用 OpenJDK 加载大约需要 5 分钟,使用 Oracle SDK 大约需要 10 秒。
  • @snodnipper 嗯,我想我必须研究一个 Oracle 替代方案。我确实在使用resin/raspberry-pi-openjdk:8-jdk
  • 这张图片似乎更快:jsurf/rpi-java

标签: performance spring-boot raspberry-pi


【解决方案1】:

更新:

对于那些阅读本文的人,由于新的 Oracle 政策,我在 2019 年回到了 OpenJDK。我注意到的是,OpenJDK 最近取得了显着的性能改进。如果您使用 OpenJDK 11 及更高版本,它具有与 Oracle JDK 相似的性能,您可以轻松配置其语言级别以使用 Java 8 代码。也就是说,如果这对您不起作用,请尝试以下方法。


我移到了一个新映像:Oracle JDK 而不是 @snodnipper 建议的 OpenJDK。

我必须做几件事,包括安装比标准存储库中可用版本更新的 Java 8 版本。这是最终为我工作的 Dockerfile,现在应用程序在 2 分钟后启动。

FROM resin/raspberrypi3-buildpack-deps:jessie-scm

ENV LANG C.UTF-8
ENV JAVA_HOME /usr/lib/jvm/java-8-oracle

RUN ["cross-build-start"]
RUN echo "deb http://archive.raspberrypi.org/debian/ jessie main ui staging" > /etc/apt/sources.list.d/raspi.list
RUN rm -f /usr/bin/entry.sh
RUN wget -qO - http://archive.raspberrypi.org/debian/raspberrypi.gpg.key | apt-key add -

RUN { \
        echo '#!/bin/bash'; \
        echo 'set -e'; \
        echo; \
        echo 'dirname "$(dirname "$(readlink -f "$(which javac || which java)")")"'; \
    } > /usr/local/bin/docker-java-home && \
    chmod +x /usr/local/bin/docker-java-home

RUN apt-key adv --recv-key --keyserver keyserver.ubuntu.com C2518248EEA14886 && \
    echo "deb http://ppa.launchpad.net/webupd8team/java/ubuntu xenial main" >> /etc/apt/sources.list.d/raspi.list

RUN set -x && \
    apt-get update && \
    apt-cache madison oracle-java8-installer && \
    echo debconf shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && \
    apt-get install -y oracle-java8-installer oracle-java8-set-default && \
    rm -rf /var/lib/apt/lists/* && \
    [ "$JAVA_HOME" = "$(docker-java-home)" ]

RUN [ "cross-build-end" ]

ADD build/libs/app-0.0.1-SNAPSHOT.jar /app.jar

ENV JAVA_OPTS=""
ENTRYPOINT exec java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar

【讨论】:

    猜你喜欢
    • 2015-10-25
    • 2020-04-22
    • 1970-01-01
    • 1970-01-01
    • 2014-04-02
    • 1970-01-01
    • 2011-07-08
    • 2018-07-26
    • 2018-11-14
    相关资源
    最近更新 更多