前言
最近自己用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参数优化内存大小
> 基于 spring boot + mybatis plus + vue & element 实现的后台管理系统 + 用户小程序,支持 rbac 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能>> * 项目地址:> * 视频教程:# jvm初始分配的内存由-xms指定,默认是物理内存的1/64-xms128m> 基于 spring cloud alibaba + gateway + nacos + rocketmq + vue & element 实现的后台管理系统 + 用户小程序,支持 rbac 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能>> * 项目地址:> * 视频教程:# 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)
2 配置环境变量
针对方法1的话,上面三张图好像只用配置java_home就行,想一次成功的话建议3个都配,后续可以自行测试。
检验是否安装成功
3 安装native-image
打开新的cmd,输入以下命令,等待安装
gu install native-image
这一步我执行失败了,解决方法就是从github上手动下载native-image,然后解压、安装
jar用winrar也是可以解压的,解压后如下
在bin目录下打开cmd,输入以下命令,等待安装
$ gu install -l native-image*
4 安装 desktop for windows
具体步骤略,按照官方文档操作即可
5 配置pom.xml
前面都是准备工作,这一步开始才是重点
首先快速创建一个spring boot项目,我命名为spring-native
完整的pom如下
4.0.0 org.springframework.boot spring-boot-starter-parent 2.6.2 ltd.pcdd spring-native 0.0.1-snapshot spring-native spring-native 11 0.11.1 org.springframework.boot spring-boot-starter-web org.springframework.experimental spring-native ${spring-native.version} org.springframework.experimental spring-aot-maven-plugin 0.11.1 generate generate org.springframework.boot spring-boot-maven-plugin paketobuildpacks/builder:tiny true spring-release spring release https://repo.spring.io/release spring-release spring release https://repo.spring.io/release
本文介绍的是spring native0.11.1版本,其对应的spring boot版本必须是2.6.2,以上只是一个最基本的配置案例,实际开发中还需要在spring-boot-maven-plugin插件的configuration标签下配置其他许许多多的参数。
例如docker远程的地址和证书的路径、jvm调优参数、配置文件指定、docker镜像名端口仓库地址等等,最好的方法就是看spring-boot-maven-plugin的官方文档,这里以配置jvm参数为例
通过官方文档得知只需要在configuration标签下配置即可,例如
paketobuildpacks/builder:tiny true -xms128m -xmx128m -xss256k -xx:parallelgcthreads=2 -xx:+printgcdetails
其他的配置参数还有很多。
6 执行maven命令
mvn cleanmvn '-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,高下立判。
AGMM5三防手机正式发布 起售价399元
ZStack发布ZStack Mini超融合一体机和ZStack多云管理平台
宇电最新推出AIJK5/AIJK6移相触发器
华为5G靠实力说话,认为造福人类比赚钱更有意义
新型AI光学传感器有望给图像识别、人工智能等领域带来重大突破
用Spring Cloud Alibaba做了一个微服务架构的项目
Linux中addr2line用法介绍
电气控制柜设计的注意事项
电阻串联和并联的计算方法_电阻串联和并联的作用
除了AI,骁龙660还有哪些亮点
什么是蓄电池内阻检测仪,它的作用是什么
中国手机市场欲将迎来一场大变局
无源元件对音频质量产生不良影响的有效测试和比较方法
20年孜孜不倦的追求,创造最优质的电源管理芯片U6201
华为发布鸿蒙Beta版怎么升级
线路板出现开短路的原因及改善方法
电阻有什么样的作用
什么是数据通信的信息流量控制
苹果表示目前无法解决iPhone12 Pro/Pro Max缺货现象
3D视频会议系统VirtualCube打开未来办公的更多可能