SpringBoot之系统优化
前言
使用springboot开发项目,一个普通的项目,简单的项目,启动起来轻轻松松就到了500m以上,在本地开发不成问题,本地开发有16个G的内存,可是部署到服务器上,服务器上的内存很贵啊,特别是阿里云的服务器,只有4核8G内存,部署几个java程序就直接把内存撑满了,系统都启动不了了。
1.Spring Boot 这样优化,让你的项目飞起来! 需要考虑:线程数、超时时间、jvm优化。
2.优化spring boot应用后6s内启动内存减半 1.关于SPRING DATA REPOSITORY SCANNING;2.关于WEBAPPLICATIONCONTEXT;3.关于SERVLET容器;4.关于ARCHAIUS配置组件;
3.记spring boot线上项目内存优化 通过设定Xmx(程序运行期间最大可占用的内存大小)、Xss(jvm启动的每个线程分配的内存大小)、XX:ParallelGCThreads(GC线程数)以及关闭了JIT功能,达成了降低内存占用的目的,java -Xmx128m -Xss256k -XX:ParallelGCThreads=2 -Djava.compiler=NONE -jar build/libs/XXX.jar
4.为何 Java 内存占用比.Net 内存占用高这么多? 这里有进行相关的讨论。
5.spring-boot内存占用过高 除了设置Xmx,还设置了 export MALLOC_ARENA_MAX=8
1.监测工具
springboot应用占用很大的内存,内存这个问题,在单机开发其实显示不出来,但是部署到服务器上,就会有了显著的限制,一个空的 springboot 项目,也会占用很大的内存,
1.jvisualvm 工具使用
2.惊呆了,Spring Boot居然这么耗内存!
3.减少Spring boot启动内存(开发环境) 1.修改tomcat的启动线程数,-XX:ParallelGCThreads调整GC线程的大小。2.修改jvm大小。这里要注意的是,register项目不需要太多资源(我这里设置128M),Gateway和config服务可以比register多一点(256M)。其它业务性服务才需要更多的资源(512M)。
4.Spring Boot Memory Performance 这里还提到了一些查看内存使用的工具
2.jvm参数优化
比较典型的配置如下:
1 | JAVA_OPTS="-Xms512m -Xmx2048m -Xss256k" |
我尝试了修改Xss为256k,结果内存占用减少的并不明显,好像也没有怎么减少。其他的一些说明如下:
1 | ## 初始Heap大小,使用的最小内存,cpu性能高时此值应设的大一些 |
1.轻松永远记住经典jvm参数 这里也不是说明了全部的jvm参数。
2.Spring cloud开发内存占用过高解决方法 这里也是针对每一个应用程序添加了jvm参数进行修改。
4.springboot降低内存占用 这里就是上面的配置
5.springboot项目启动内存占用过高问题如何解决 和上面的配置差不多
6.The stack size specified is too small, Specify at least 228k
7.一定要记住的14个JVM内存配置参数 对每一个参数都进行了相应的说明
8.Linux系统线程的Xss设置不生效原因
3.关闭JIT
至于在线上环境到底要不要关闭JIT功能,我现在还没有一个确定的概念,但是下面的方法可以关闭jit。
1 | java -Djava.compiler=NONE your_main_class_file_name |
1.如何关闭JIT 在启动JVM的时候,只需增加-Xint或者-Djava.compiler=NONE选项即可
2.禁用 JIT
3.看了这篇【JIT编译器】,你也能说你会java性能优化了!
4.SpringBoot应用刚启动时服务报大量超时的问题 有了JIT技术之后,JVM还是通过解释器进行解释执行。但是,当JVM发现某个方法或代码块运行时执行的特别频繁的时候,就会认为这是“热点代码”(Hot Spot Code)。然后JIT会把部分“热点代码”翻译成本地机器相关的机器码,并进行优化,然后再把翻译后的机器码缓存起来,以备下次使用。
5.为什么 SpringBoot 应用刚启动的时候比较卡,过一会就好了? 1.提升JIT优化的效率,在提升JIT优化效率的设计上,大家可以了解一下阿里研发的JDK——Dragonwell。2.降低瞬时请求量,就是说在应用刚刚启动的时候,通过调节负载均衡,不要很快的把大流量分发给他,而是先分给他一小部分流量,通过这部分流量来触发JIT优化,等优化好了之后,再把流量调大。
4.GraalVM
这个另外开一篇文章单独进行学习和介绍吧,目前(2022年08月04日)来说可能还有很多的问题。SpringBoot之GraalVM
5.OpenJ9
除了上面的GraalVM之外,还有一种技术就是使用OpenJ9替换默认的OpenJDK,也可以显著的减少内存占用。我尝试了将基础镜像 openjdk:8-jre 换成 adoptopenjdk/openjdk8-openj9:alpine-slim,确实好像有一些提升。
1 | # 基础镜像 |
使用openj9之后的内存占用
使用openjdk:8-jre之前的内存占用
可以看到,上面的对比,同样的代码,确实好像占用的内存不一样。
1.JDK 的另一个选择:OpenJDK with Eclipse OpenJ9 这里做了一个简单的测试,对比了使用 Hotspot 和 OpenJ9 的区别,这里看出来,OpenJ9确实可以减少内存占用,虽然不是很多,但也是30%的样子。
2.Docker环境下Spring Boot应用内存飙升分析与解决 这里讲了关于jvm内存的初始分配内存原理,并使用了 exec java 限制了内存的大小。同时提供了三种docker镜像的优化,OpenJ9、GraalVM和Fabric8。
问题
(1) java.lang.NoClassDefFoundError: sun.awt.X11FontManager
使用了openj9之后,可能一些字体就被阉割掉了,这个时候就需要重新进行安装字体。在dockerfile文件中加入下面的内容。
1 | RUN apk add --update ttf-dejavu fontconfig && rm -rf /var/cache/apk/* |
这里还有一个问题,就是安装的时候会非常的慢,甚至有时候会卡在 ttf-dejavu 的部分
1.遇到 Could not initialize class sun.awt.X11FontManager 不要怕
2.如何解决Alpine Docker镜像字体的问题 这里解决了问题,我没有执行 COPY ./simhei.ttf /usr/share/fonts/simhei.ttf
3.如何在Docker容器中安装Linux软件包? 这里是ubuntu类的docker镜像安装软件
4./bin/sh: apt-get: not found
5.解决docker alpine缺少字体的问题 缺点是每次打包都要安装 ttf-dejavu 比较慢 , 因此该方法不推荐
6.记录一次解决openjdk8-openj9:alpine-slim缺少字体的经历
(2) OCI runtime exec failed: exec failed: unable to start container process: exec: “/bin/bash”: stat /bin/bash: no such file or directory: unknown
在使用OpenJ9镜像的时候,进入容器的时候,总是无法进入,因为没有/bin/bash命令行,需要使用 /bin/sh 命令行
1 | ## 错误 |
(3) java获取的时区不正确
在使用docker镜像进行部署的时候,出现了容器中java获取到的系统当前时间和宿主机系统时间相差八个小时的问题,我在dockerfile中进行了设置,但是不知道是不是因为我使用的是 FROM adoptopenjdk/openjdk8-openj9:alpine-slim 镜像,所以下面的语句不生效,使用 date -R 获取到的时间还是不对。
1 | # 设置时区 |
【尝试】
我发现/etc/配置文件中没有localtime文件,只有/et/timezone文件,应该是我上面输出的内容,后来我改成了
1 | # 时区设置 |
结果出现了问题: unable to select packages: tzdata (no such package):The command ‘/bin/sh -c apk add -U tzdata’ returned a non-zero code,后来我改了dockerfile文件。
1 | # 时区设置 |
结果还是出现 :tzdata (no such package) 。
【解决】
最后通过修改alpine的镜像改为阿里云的镜像解决了这个问题
1 | # 时区设置 |
1.Docker镜像时区不对问题的解决【ubuntu】【centos】
2.解决docker容器内时区无法调整
3.centos7查看修改时区 这个好像没什么参考价值,因为我的镜像并不是基于centos的
4.Docker openjdk-8-jdk-alpine 容器时间与jdk时区不同修改方法 RUN echo “Asia/Shanghai” > /etc/timezone 这个没有什么用,我已经在dockerfile中配置了相关的内容,但是没有起作用
5.alpine镜像修改docker的时区 转
6.docker 时区调整 这里有 Alpine、Debian、Ubuntu和CentOS不同系统的时区设置。
7.修改nginx镜像时区 这里镜像是基于nginx:alpine的
8.如何查看docker容器里的操作系统 使用 cat /etc/issue 查看系统版本
9.docker: Apline configure timezone RUN apk update && apk add –no-cache tzdata
10.Alpine Docker images no longer have tzdata package in 3.0
11.校正alpine镜像的时区 RUN apk add tzdata && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo “Asia/Shanghai” > /etc/timezone && apk del tzdata