一、背景
腾讯 KonaJDK 团队最近对外开源了KonaJDK11, 该版本 JDK 是通过外部超大规模生产环境验证的定制 JDK,该版本在启动性能、峰值性能以及事物解决能力方面,绝对于前一版本 Kona JDK8 都有了综合性晋升,积淀了腾讯云与大数据团队在大数据/机器学习、云原生场景下的深度优化,并且通过了 JCK 验证,确保充沛的 Java SE 规范兼容。通过工业规范 Benchmark 表明,Kona JDK11 比照 Kona JDK8 大多数场景在峰值性能上具备非常明显的晋升,个别性能晋升靠近 50%。
KonaJDK11 如此优良,咱们能不能把它引入到Serverless呢? 另外,最近笔者也在思考怎么样让 Java spring 框架在 SCF 中顺滑的跑起来,所以借着这个机会,索性来一把 KonaJDK + Spring 在 SCF 上的实际总结。
多说无用,Show you my code!
二、SCF应用JDK11
腾讯云Serverless云函数SCF产品中内置Java8反对,然而并没有高版本JDK的环境反对,那么如何实现SCF的Java11云函数呢?
实际上,SCF云函数提供的CustomRuntime性能曾经解锁了用户应用编程语言的限度,目前曾经有webassembly,swift,rust等胜利例子。咱们能够同样借助这个性能来将KonaJDK11引入SCF,从而实现高版本Java的反对。
过程如下:
- 下载KonaJDK11,https://github.com/Tencent/Te...
- 因为KonaJDK11的二进制包比拟大,须要应用SCF层的概念来上传KonaJDK11程序包
首先须要创立层,因为KonaJDK11程序包超过50MB,所以能够抉择COS形式,现将KonaJDK11安装包上传到腾讯云COS,之后在创立层时指定门路即可, 具体应用能够参考产品阐明https://cloud.tencent.com/doc...
- 创立云函数, 留神这里须要应用CustomRuntime,咱们抉择Shell函数示例,再次根底上拓展咱们的KonaJDK11的反对.
进入【高级配置】->【层配置】->【增加层】
依照下图所示配置好【层】【超时工夫】与【内存】点击【实现】
- 依据SCF CustomRuntime的应用阐明,须要编写CustomRuntime的启动文件 Bootstrap,SCF CustomRuntime会在函数启动时第一步找到并执行这个名为bootstrap的可执行文件。
- 咱们的bootstrap中须要配置环境变量,并启动Java程序. 咱们先假如我写了一个名为Hello的class,外面只打印hello SCF 字符串。 之后将bootstrap文件和Hello.class文件一起打包成一个zip文件,上传到SCF部署,这时bootstrap的内容如下:
能够看到就是简略的环境变量配置和执行java -version 与 Hello程序。
之后点击【测试】触发执行,之后咱们能够看到函数执行日志如下:
咱们曾经能够从日志里看到 openjdk version "11.0.9.1-ga"的 Java版本,并且看到了Hello程序失常输入。至此,KonaJDK 11 曾经顺利跑在了云函数环境中。
留神此处显示【测试失败】是失常的,因为咱们还没有编写解决【函数事件】的逻辑,也就是还没有实现具体的云函数。
三、实现spring云函数
当初让咱们来用spring框架实现一个能跑在KonaJDK11上的云函数。为了清晰,咱们写一个最简略的springboot Demo, 它的controller长这样:
入口函数长这样:
OK,目前这个Demo能够承受 http Get localhost:8080/hello
申请并返回 hello, this is a springboot demo!
字符串。 那么如何将它改编成云函数呢?
从 SCF CustomRuntime 文档以及一些公开的材料,能够看到编写CustomRuntime的函数,只须要两个关键步骤:
- 编写可执行启动程序bootstrap,在bootstrap外面启动咱们的spring云函数
- 编写云函数。这一步首先须要理解CustomRuntime工作的流程,从这篇文章能够看到,次要流程如下:
具体说来,就是在bootstrap启动云函数当前,sping云函数在本身初始化时须要先POST一个Ready的httpRequest给 SCF服务端, 目标是告诉SCF函数初始化结束,能够取得下发的事件了。
之后,spring须要一个循环,循环外部通过向SCF服务端发送HTTP GET申请,取得待处理事件,再调用外部逻辑,解决完事件之后通过POST申请发送给SCF服务端,循环期待下一次事件下发。
针对Springboot, 咱们的云函数次要有以下几个须要解决的中央:
- 事件下发: Springboot云函数次要是启动并监听云函数外部的一个自定义http端口,通过http申请实现解决工作。 SCF云函数目前http申请次要通过API Gateway事件下发,也就是说,spring云函数的逻辑外面,须要将API Gateway事件转换成http事件之后再发给函数外部的springboot监听的端口。好在整个这一套逻辑的转换SCF其实曾经提供给了咱们,就在SCF java event的代码中,能够从 https://github.com/tencentyun... 这个代码间接抽取复用。
- 初始化: 也就是在第一次启动云函数的时候,咱们须要启动springboot,另其建设httpserver并监听端口。 之后每次事件下发,只须要发送httprequest即可。
- 监听事件: 这里就是依照 SCF CustomRutime 的要求,写一个循环,应用http GET申请获取event,并发送给外部springboot监听的端口。
通过下面的梳理,逻辑曾经基本上清晰了:首先,须要在 cold launch阶段启动springboot入口函数, 告诉SCF服务端,springboot云函数初始化结束,期待接管音讯。之后就是一个大循环,循环外面工作如下:
- 通过
Http GET
申请从SCF服务端取得 ApiGateway 下发的event
- Api GW event转换成 http request 并发送到 springboot 监听的端口,期待返回处理结果
- springboot 返回的 event 转换为 ApiGateway Response, 通过POST申请返回给SCF 服务端
- 进入下一次循环,期待下一次事件下发.
解决流程代码也很简略:
至此,咱们曾经实现了云函数的编写,之后咱们能够测试一下,将bootstrap和编译后的 springboot-application.jar
打包到一个zip文件,而后上传到SCF云函数进行部署。
之后依照如下配置 apiGW 的 event,留神这里配置 Get,“/hello” 是因为咱们的springboot 云函数的controller配置成了接管Get, “/hello” 申请并打印和返回字符串,实际上用户须要依据本人的业务,批改apiGW这里event相应的内容。
而后点击[测试]: 稍等一下就能够看到如下log:
springboot曾经启动, 而后咱们还能够看到:
函数曾经失常响应了GET /hello的申请。
四、利用appCDS个性提速降存
在下面的springboot云函数中,咱们能够看到一次冷启动耗时和内存如下:
同时log中也蕴含了springboot的启动工夫
总体来说就是耗时6秒多,应用了168MB的内存。
那么,如何进步启动速度缩小内存应用呢?
JDK11外面自带appCDS性能,具openJDK官网说法,该性能能够缩小java类加载工夫同时缩小内存占用量,进步启动速度。 这不正是咱们想要的么,咱们当初曾经有了KonaJDK+springboot的云函数,那么怎么在KonaJDK中应用起来这个性能呢?
- appCDS性能应用步骤:
依照JDK官网文档, appCDS应用形式次要是以下几个步骤:
- 生成待
dump
的类文件列表, 应用-Xshare:off -XX:+UseAppCDS -XX:DumpLoadedClassList=classes.lst
JVM选项运行程序,会生成classes.lst文件 - 应用
-Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=classes.lst \ -XX:SharedArchiveFile=dump.jsa
生成dump.jsa文件 - 应用appCDS失常启动java程序,应用JVM选项
-Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=dump.jsa
- 云函数中enable appCDS
针对云函数SCF的场景,次要须要以下适配工作
- 因为在云函数中,目前只有/tmp目录是可写目录,所以1中的步骤咱们须要将所有波及到的文件门路变更为
/tmp/classes.list
和/tmp/dump.jsa
- 因为咱们冀望最终生成的dump.jsa能够在多个云函数实例中应用,咱们须要失去/tmp/dump.jsa文件,而后将其和云函数一起打包,这样在应用时候,咱们只须要指定Jvm参数
-XX:SharedArchiveFile=dump.jsa
即可复用dump.jsa
文件。 所以咱们须要取得生成的/tmp/dump.jsa
文件,因为SCF不能间接下载/tmp
目录的文件,所以咱们依据COS的文档写了一小段程序,帮忙咱们在生成/tmp/dump.jsa
文件后上传到指定的COS中,具体能够参考COS java 的sdk - 在失去
dump.jsa
之后,咱们就能够对整个云函数从新打包,最终打包的文件中蕴含3个子文件, 云函数 CustomRuntime的启动脚本bootstrap, springboot云函数的实现SCF-springboot-web-1.0-SNAPSHOT.jar
,以及appCDS的archive文件 dump.jsa,咱们将这3个文件打包重新部署。 - 再部署之后,咱们须要增加
JAVA_TOOL_OPTIONS
环境变量JAVA_TOOL_OPTIONS=-Xshare:on -XX:SharedArchiveFile=dump.jsa
这样就能够在启动云函数时应用这些 jvm 选项了。
- 成果
在应用AppCDS之后登程云函数的冷启动,能够看到如下成果:
- 内存应用 从原来的169MB升高到了100MB
- springboot启动工夫从原来的6.137s进步到了4.772s
总结
至此,咱们在腾讯 Serverless 云函数上借助 CustomRuntime 实现了KonaJDK11 + SpringBoot云函数的应用,并利用KonaJDK11中AppCDS个性优化了云函数冷启动的速度与内存损耗。 文中利用CustomeRuntime引入KonaJDK11的办法能够作为腾讯云Faas上解锁多语言或高版本Java语言runtime的一种通用形式。
在将来腾讯KonaJDK团队会进一步针对腾讯云业务Faas场景的特点提供更多的性能与性能晋升,敬请关注。