这样做优化,实现 0.059s 启动一个SpringBoot项目!
大家好,我是老赵!
前言
最近自己用Spring Cloud Alibaba做了一个微服务架构的项目,部署的时候遇到了难题:内存不够。目前该项目有7个微服务,因为我只有一台阿里云的服务器(2C 4G),所以我只能把所有的微服务部署在一台服务器上,部署方式是使用docker制作springboot的fat jar镜像,每个微服务在不加任何JVM调优参数的情况下所占内存约500M。
由于是微服务所以肯定还要部署:nacos,除此之外还用到了redis、sentinel、rocketmq、elk等(mysql买的阿里云的),光是运行这些应用就占用内存2个多G,剩下的1个多G内存在部署4个微服务后就满了,于是开始对springboot应用的内存进行初步优化:
添加JVM参数优化内存大小
# JVM初始分配的内存由-Xms指定,默认是物理内存的1/64
-Xms128m
# JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4
-Xmx128m
# 规定了每个线程虚拟机栈及堆栈的大小,一般情况下,256k是足够的,此配置将会影响此进程中并发线程数的大小。
-Xss256k
# 指定并行GC线程的数量,一般最好和CPU核心数量相当
-XX:ParallelGCThreads=2
默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx
的最大限制;空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制。
因此服务器一般设置-Xms
、-Xmx
相等以避免在每次GC 后调整堆的大小。对象的堆内存由称为垃圾回收器的自动内存管理系统回收。
默认情况下,当 CPU 数量小于8, ParallelGCThreads
的值等于 CPU 数量,我的服务器是2C的所以这个参数可省略。配置完成后,启动服务发现内存确实变小了,由原来的500M降至100~200M,但不是我想要的效果,我期望的效果是达到几十M的级别。
经网上查阅大量资料得知可以使用Spring Native这门新技术来实现我的需求。(该技术正处于快速迭代阶段,变动较大,建议用于个人学习,不要用于生产)
SpringBoot项目使用Spring Native后:
应用启动速度特别快,毫秒级别
运行时更低的内存消耗,官方展示的含有Spring Boot, Spring MVC, Jackson, Tomcat的镜像大小是50M
为了达到前面的效果,代价是构建时间更长(即使是一个Hello Word构建也需要2分钟,不过主要取决于电脑配置,我的是2min左右)
Spring Native是什么
简而言之就是为了提高Java在云原生的竞争力(个人理解)。
以下内容摘抄自GitHub上Spring Native的自述文件:
Spring Native 为使用GraalVM 原生映像编译器将 Spring 应用程序编译为原生可执行文件提供 beta 支持,以提供通常设计为打包在轻量级容器中的原生部署选项。实际上,目标是在这个新平台上支持几乎未修改的 Spring Boot 应用程序。
以下内容摘抄自其他博客:
近几年“原生”一词一直泛滥在云计算、边缘计算等领域中,而原生宠幸的语言也一直都是Golang,Rust等脱离Sandbox运行的开发语言。Java得益于上世纪流行的一次编译,到处执行的理念,流行至今,但也因为这个原因,导致Java程序脱离不了JVM运行环境,使得不那么受原生程序的青睐。在云原生泛滥的今天,臃肿的JVM使Java应用程序对比其他语言显得无比的庞大,各路大神也想了很多方式让Java变的更“原生”。
实战
本次实战相关的环境信息如下:
OS:Windows10 21H1
IDE:IntelliJ IDEA 2021.2.3
JDK:graalvm-ce-java11-21.3.0
Maven:3.6.3
Docker Desktop for Windows: 20.10.12
Spring Boot:2.6.2
Spring Native:0.11.1
从官方文档得知(上图)
使用 Spring Native 的应用程序应该使用 Java 11 或 Java 17 编译。
构建 Spring Boot 原生应用程序有两种主要方法:
使用Spring Boot Buildpacks 支持生成包含本机可执行文件的轻量级容器。
使用GraalVM 原生镜像 Maven 插件支持生成原生可执行文件。
经过各种踩坑后在本机上成功的使用了方法1和方法2。简单来说:
方法1就是在SpringBoot2.3后,可以使用spring-boot-maven-plugin
插件来构建docker镜像,使用mvn spring-boot:build-image
命令结合Docker的API来实现Spring Boot 原生应用程序的构建,成功执行后会直接生成一个docker镜像,然后run这个镜像就可以了,不用我们再写Dockerfile
了,相关的参数配置都在pom.xml
中配置(该插件的configuration
标签下,和fabric8
或spotify
的docker-maven-plugin
很相似)。
方法2不需要安装docker,但要安装Visual Studio
,然后执行mvn -Pnative package
命令后会生成一个可执行文件(.exe),运行即可。
主要区别如下
1 环境依赖不同
方法1需要安装Docker
方法2需要安装Visual Studio(需要用到部分单个组件:2个MSVC,1个Windows 10 SDK)
2 执行的maven命令不同
方法1是
mvn spring-boot:build-image
方法2是
mvn -Pnative package
因为每个微服务使用Docker部署而不是exe文件,所以方法1正好符合我的需求,所以后文使用Spring Boot Buildpacks的方式构建Spring Boot原生应用程序。
1 安装Graal VM(graalvm-ce-java11-windows-amd64)
官方下载地址:
https://www.graalvm.org/downloads/
2 配置环境变量
针对方法1的话,上面三张图好像只用配置JAVA_HOME就行,想一次成功的话建议3个都配,后续可以自行测试。
检验是否安装成功
3 安装native-image
打开新的cmd,输入以下命令,等待安装
gu install native-image
这一步我执行失败了,解决方法就是从github上手动下载native-image
,然后解压、安装
https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.3.0/native-image-installable-svm-java11-windows-amd64-21.3.0.jar
jar用WinRAR也是可以解压的,解压后如下
在bin目录下打开cmd,输入以下命令,等待安装
$ gu install -L native-image*
4 安装 Desktop for Windows
具体步骤略,按照官方文档操作即可:
https://docs.docker.com/desktop/windows/install/
5 配置pom.xml
前面都是准备工作,这一步开始才是重点
首先快速创建一个Spring Boot项目,我命名为spring-native
完整的pom如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.2</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>ltd.pcdd</groupId><artifactId>spring-native</artifactId><version>0.0.1-SNAPSHOT</version><name>spring-native</name><description>spring-native</description><properties><java.version>11</java.version><repackage.classifier/><spring-native.version>0.11.1</spring-native.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.experimental</groupId><artifactId>spring-native</artifactId><version>${spring-native.version}</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.experimental</groupId><artifactId>spring-aot-maven-plugin</artifactId><version>0.11.1</version><executions><execution><id>generate</id><goals><goal>generate</goal></goals></execution></executions></plugin><!--Spring Boot 2.3发布后带来了新特性之一就是对构建镜像的便捷支持--><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><image><builder>paketobuildpacks/builder:tiny</builder><env><BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE></env></image></configuration></plugin></plugins></build><repositories><repository><id>spring-release</id><name>Spring release</name><url>https://repo.spring.io/release</url></repository></repositories><pluginRepositories><pluginRepository><id>spring-release</id><name>Spring release</name><url>https://repo.spring.io/release</url></pluginRepository></pluginRepositories></project>
本文介绍的是Spring Native0.11.1
版本,其对应的Spring Boot版本必须是2.6.2,以上只是一个最基本的配置案例,实际开发中还需要在spring-boot-maven-plugin
插件的configuration
标签下配置其他许许多多的参数。
例如docker远程的地址和证书的路径、jvm调优参数、配置文件指定、docker镜像名端口仓库地址等等,最好的方法就是看spring-boot-maven-plugin
的官方文档,这里以配置jvm参数为例
通过官方文档得知只需要在configuration
标签下配置即可,例如
<image><builder>paketobuildpacks/builder:tiny</builder><env><BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE><BPE_DELIM_JAVA_TOOL_OPTIONS xml:space="preserve"> </BPE_DELIM_JAVA_TOOL_OPTIONS><BPE_APPEND_JAVA_TOOL_OPTIONS>-Xms128m</BPE_APPEND_JAVA_TOOL_OPTIONS><BPE_APPEND_JAVA_TOOL_OPTIONS>-Xmx128m</BPE_APPEND_JAVA_TOOL_OPTIONS><BPE_APPEND_JAVA_TOOL_OPTIONS>-Xss256k</BPE_APPEND_JAVA_TOOL_OPTIONS><BPE_APPEND_JAVA_TOOL_OPTIONS>-XX:ParallelGCThreads=2</BPE_APPEND_JAVA_TOOL_OPTIONS><BPE_APPEND_JAVA_TOOL_OPTIONS>-XX:+PrintGCDetails</BPE_APPEND_JAVA_TOOL_OPTIONS></env>
</image>
其他的配置参数还有很多。
官方文档:
https://docs.spring.io/spring-boot/docs/2.6.2/maven-plugin/reference/htmlsingle/#build-image
6 执行maven命令
mvn clean
mvn '-Dmaven.test.skip=true' spring-boot:build-image
下载完相关依赖后,电脑风扇就开始呼呼的转,查看任务管理器发现CPU利用率100%,内存使用量飙升,最后稳定在90%+。
构建成功
7 创建并运行容器
查看所有镜像
spring-native
就是构建的镜像
创建并运行容器
在Docker Desktop
查看日志,发现应用成功启动,启动仅耗时。,也就是59ms,果然印证了Spring Native
启动是毫秒级别这句话。
成功调用接口
在Docker Desktop
查看占用内存,仅28M左右。
不使用Spring Native
启动应用
启动耗时3s,占用内存高达511M,高下立判。
文章仅供参考,建议结合Spring Native官方最新文档学习。
https://docs.spring.io/spring-native/docs/current/reference/htmlsingle/index.html
来源:blog.csdn.net/weixin_43553153/article/details/122486769
精彩推荐
1.大数据扫黄,是怎样发现你的?
2.JetBrains官宣:干掉微软VS Code,推出Fleet!
3.撸了一个电子文件签字+合同系统,爽!
4.只会用 Spring Boot 创建微服务?那你太Low了,这 4 种替代方案绝了!
5.Excel300万数据导入导出优化方案,从80s优化到8s(实测)
6.为什么建议大家使用 Linux 开发?有那么爽吗?7.4 行代码写 3 个bug,我被当场开除!8.惨,外包员工上班戴耳机被开除。。。。
9.因为日报,架构师绩效被打C了!
这样做优化,实现 0.059s 启动一个SpringBoot项目!相关推荐
- linux进程管理工具supervisor安装卸载、子配置文件详解、遇到的问题、supervisor group群组管理、启动一个springboot项目示例、update命令注意点
简介 Supervisor是用Python开发的一套通用的进程管理程序,能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启. 它是通过fork/exec的方式把这些被管 ...
- eclipse启动一个Springboot项目
1.准备一个Springboot项目 2.配置好maven 注:本地的maven-repository默认路径是在系统盘的.m文件夹.如果想要修改可参考: eclipse修改maven仓库的位置_本本 ...
- 0.07 秒启动一个 SpringBoot 项目!
写一段简单的 Java 程序. public class Hello {public static void main(String[] args) {System.out.println(" ...
- 今天带你体验79毫秒启动一个SpringBoot项目
大家好,我是雷小帅,今天来个项目实战. 先抛一个问题,大家在自己电脑上启动一个 spring boot 项目需要花费多久? 根据项目大小和机器环境,花费几秒到几十秒的人应该都有. 最近 spring ...
- 手把手教你从0开始搭建一个vue项目(完结)
前言 上一节webpack实战之(手把手教你从0开始搭建一个vue项目)最后我们完成了css样式的配置: webpack.config.js: const path = require("p ...
- 准备启动一个开源项目 - 技术族谱 - 先期利用Goolge云计算平台
准备启动一个开源项目:技术族谱 . 是什么? 技术族谱 ,该项目提供一种手段,描述技术领域中的概念和知识点的关系,并以此关系网为基础,扩展相关应用. 为什么? 我是做计算机行业的,就先从我看到的现象说 ...
- 全栈深度学习第1期:如何启动一个机器学习项目?
一 起 追 剧 鸭 ! 简介 Berkeley全栈深度学习追剧计划是由夕小瑶的卖萌屋发起的优质公开课打卡项目,通过微信群为同期追剧的小伙伴提供交流平台.关于该计划的详请见这里. 1. Berkeley ...
- 在ubuntu上启动一个vue项目
在ubuntu上启动一个vue项目 本地: npm install npm run dev npm run build 然后发现报错,大面积报错,原来是被npm给墙了 经过 npm install - ...
- IDEA快速构建一个SpringBoot项目
IDEA快速构建一个SpringBoot项目 1.new一个Spring Initialiar 项目 2.设置项目名字等 3.选择依赖,随便选几个就行,后面再到POM加依赖就行 4.POM文件加依赖, ...
最新文章
- layui树形父子不关联_DP专题7 | 没有上司的舞会 洛谷1352(树形DP)
- 控制结构(1)-判断控制
- 对象的软、弱、和虚引用
- applet实现大文件ftp上传(三)
- .Net Core手撸一个基于Token的权限认证
- case when 多条件_3年前的设计如今被iPhone强推 PITAKA磁吸生态设计的前瞻性到底有多可怕?...
- 第2课 贝贝的图形(vhist)-2019-07-11《聪明人的游戏-提高篇》
- 酷爆了!阿里预测2020十大科技趋势
- 吉大计算机考研分数线2021,吉林大学2021考研分数线
- 一步一步学solr:什么是solr?
- CMFCPropertyGridCtrl 的简单教程
- 安卓udp发包工具_Sendip 命令行发包工具,支持IP、TCP、UDP等
- mis是商科还是计算机专业,MIS是什么?管理信息系统MIS和计算机科学CS有什么区别?...
- 一个WEB应用的开发流程 供学习用!
- python,list元素倒置
- vscode开发小程序需要安装的插件集合
- 基于微信小程序的个人电台系统的设计与实现
- hive建表报错 character ‘ ‘ not supported here
- C++ 时间计算器 之 超级无敌小白版 刚入门的快点看过来!
- 推荐系统 (一): 推荐系统的架构
热门文章
- 啥是BGP机房啊,被科普一下!
- 《平凡的世界》之我看
- DiscoNet:基于Distilled Collaboration Graph的V2V协同感知
- [PTA]习题3-5 三角形判断
- ps photoshop cc 2015 Extract Assets(生成器)切图大法
- (c语言)哈利·波特的考试 (25分)
- 各种音视频编解码学习详解 h264 ,mpeg4 ,aac 等所有音视频格式 详解
- 咖说 | 潘超:数字货币「矩阵」里的「盗梦空间」
- [词性] 十七、介词 7 [ to ] [ since ] [ through ] [ under ] [ up ] [ with ]
- 读懂这些你的婚姻才会幸福