在GraalVM上开发实用程序

问题陈述


我定期执行一项任务,例如与项目同事共享本地网络上的文件。


可以有很多解决方案-Samba / FTP / scp。 您只需将文件上传到Google云端硬盘等公共场所,将其附加到Jira中的任务上,甚至通过电子邮件发送即可。


但是所有这一切在某种程度上都是不灵活的,需要进行初步调整并且有其自身的局限性(例如,最大投资规模)。


您想要更轻便,更灵活的产品。


Linux总是有机会使用可用的方法快速构建实用的解决方案,这使我始终感到惊喜。


说,我经常使用以下单行代码使用系统python解决上述任务


$ python3 -mhttp.server Serving HTTP on 0.0.0.0 port 8000 ... 

此命令将在当前文件夹中启动Web服务器,并允许您获取文件列表并通过Web界面下载它们。 这些东西更多的可以在这里倾销


有一些不便之处。 现在,为了将下载链接传送给同事,您需要知道网络上的IP地址。


使用命令很方便


 $ ifconfig -a 

然后从结果的网络接口列表中选择适当的接口,并手动组成一个http:// IP:8000形式的链接,您可以发送该链接。


第二个不便之处:此服务器是单线程的。 这意味着,虽然您的一位同事下载了文件,但第二位同事甚至无法下载文件列表。


第三,它不灵活。 如果您只需要传输一个文件,它将打开整个文件夹,即 您将必须执行以下手势(然后清理垃圾):


 $ mkdir tmp1 $ cp file.zip tmp1 $ cd tmp1 $ python3 -mhttp.server 

第四个不便之处-没有简单的方法可以下载文件夹的全部内容。


为了传输文件夹的内容,他们通常使用称为tar pipe的技术。


他们这样做:


 $ ssh user@host 'cd /path/to/source && tar cf - .' | cd /path/to/destination && tar xvf - 

如果突然不清楚,我将解释其工作原理。 tar cf - .命令的第一部分tar cf - . 创建当前文件夹内容的存档,并写入标准输出。 此外,此输出通过安全ssh通道通过管道传输到类似的tar xvf -的输入tar xvf -tar xvf -执行相反的过程,即 读取标准输入并解压缩到当前文件夹。 实际上,文件存档已传输,但未创建中间文件!


这种方法的不便之处也很明显。 我们需要从一台机器到另一台机器的ssh访问,而在一般情况下几乎从来没有这样做。


是否可以实现上述所有条件,但没有上述问题?


因此,是时候正式确定我们将要构建的内容了:


  1. 易于安装的程序(静态二进制)
  2. 这将使您既可以传输文件又可以传输所有内容的文件夹
  3. 带有可选压缩
  4. 允许主机仅使用标准* nix工具(wget / curl / tar)下载文件
  5. 该程序将在启动后立即发出确切的命令进行下载

解决方案


不久前我参加的JEEConf会议上, Graal主题反复提出。 这个话题不是什么新鲜事物,但是对我来说,这是一个触发,让我终于可以亲手感受到这头野兽。


对于那些尚未参与主题讨论的人(真的有这样的事情吗?OO),让我提醒您,GraalVM是Oracle提供的具有许多附加功能的JVM,其中最引人注目的是:


  1. Polyglot JVM-无缝运行Java,Javascript,Python,Ruby,R等的功能。 代号
  2. 支持AOT编译-将Java直接编译为本地二进制文件
  3. 一个不太引人注目但非常酷的功能-C2编译器从C ++重写为Java,以便更方便地进行进一步的开发。 这已经产生了明显的结果。 该编译器在将Java字节码转换为本地代码的阶段进行了更多优化。 例如,它能够更有效地消除分配。 只需启用此设置,Twitter就能将CPU消耗减少11%,这在其规模上可显着节省资源(和金钱)。

例如,您可以在此habr文章中刷新Graal的想法。


我们将用Java编写,因此对我们而言,最相关的功能是AOT编译。


实际上,开发结果在此Github存储库中给出


传输单个文件的用法示例:


 $ serv '/path/to/report.pdf' To download the file please use one of the commands below: curl http://192.168.0.179:17777/dl > 'report.pdf' wget -O- http://192.168.0.179:17777/dl > 'report.pdf' curl http://192.168.0.179:17777/dl?z --compressed > 'report.pdf' wget -O- http://192.168.0.179:17777/dl?z | gunzip > 'report.pdf' 

传输文件夹内容(包括附件的所有文件!)时使用的示例:


 $ serv '/path/to/folder' To download the files please use one of the commands below. NB! All files will be placed into current folder! curl http://192.168.0.179:17777/dl | tar -xvf - wget -O- http://192.168.0.179:17777/dl | tar -xvf - curl http://192.168.0.179:17777/dl?z | tar -xzvf - wget -O- http://192.168.0.179:17777/dl?z | tar -xzvf - 

是的,很简单!


请注意-程序本身将确定可下载文件的正确IP地址。


意见/想法


显然,创建程序的目标之一就是程序的紧凑性。 这是已实现的结果:


 $ du -hs `which serv` 2.4M /usr/local/bin/serv 

令人难以置信的是,整个JVM以及应用程序代码可容纳几兆字节! 当然,一切都有些错误,但稍后会更多。


实际上,Graal编译器生成的二进制文件的大小略大于7兆字节。 我决定用UPX进一步压缩它


事实证明,这是一个好主意,因为启动时间增加了,但时间却微不足道:


未压缩的选项:


 $ time ./build/com.cmlteam.serv.serv -v 0.1 real 0m0.001s user 0m0.001s sys 0m0.000s 

压缩后:


 $ time ./build/serv -v 0.1 real 0m0.021s user 0m0.021s sys 0m0.000s 

为了进行比较,发射时间以“传统方式”:


 $ time java -cp "/home/xonix/proj/serv/target/classes:/home/xonix/.m2/repository/commons-cli/commons-cli/1.4/commons-cli-1.4.jar:/home/xonix/.m2/repository/org/apache/commons/commons-compress/1.18/commons-compress-1.18.jar" com.cmlteam.serv.Serv -v 0.1 real 0m0.040s user 0m0.030s sys 0m0.019s 

如您所见,速度是UPX版本的两倍。


通常,启动时间短是GraalVM的优势之一。 这以及较低的内存消耗,导致对该技术在微服务和无服务器环境中的使用表现出极大的热情。


我试图使程序逻辑尽可能少,并使用最少的库。 原则上,这种方法通常是合理的,在这种情况下,我担心添加第三方maven依赖项会极大地“加权”生成的程序文件。


例如,这就是为什么我不对Java Web服务器使用第三方依赖项(并且每种口味和颜色都有很多依赖项),但是我使用了com.sun.net.httpserver.*服务器的JDK实现。 实际上,使用com.sun.*软件包被认为是一种com.sun.* ,但是在这种情况下,我认为这是允许的,因为我正在编译为本机代码,因此,JVM之间没有兼容性问题。


但是,我的恐惧完全没有用。 在程序中,为了方便起见,我使用了两个依赖项


  1. commons-cli用于解析命令行参数
  2. commons-compress生成文件夹tarball和可选的gzip压缩

同时,文件大小非常微小地增加。 我冒昧地建议Graal编译器非常聪明,不要将所有插件jar-nicks都放在可执行文件中,而只需将其中的代码实际用于应用程序代码中即可。


通过本机图像实用程序将其编译为本机Graal代码。 值得一提的是,此过程需要大量资源。 说,在我的板载Intel 7700K CPU不太慢的配置下,此过程需要19秒。 因此,我建议在开发时,像往常一样(通过java)运行程序,并在最后阶段收集二进制文件。


结论


在我看来,该实验非常成功。 在使用Graal工具包进行开发时,我没有遇到任何无法克服甚至重大的问题。 一切都可以预期且稳定地进行。 尽管几乎可以肯定,如果您尝试以这种方式构建更复杂的东西,例如Spring Boot上应用程序 ,一切都不会那么顺利。 尽管如此,已经提出了许多平台,其中宣布了对Graal的本地支持。 其中包括MicronautMicroprofileQuarkus


至于该项目的进一步开发,已经准备了针对0.2版计划的改进清单 。 另外,目前,最终二进制文件的汇编仅针对Linux x64实现。 我希望这一遗漏会在将来得到解决,特别是因为Graal的native-image编译器支持MacOS和Windows。 不幸的是,它还不支持交叉编译,这会使事情变得容易得多。


我希望提出的实用程序至少对著名的habr社区中的某人有用。 如果有人愿意为该项目做出贡献我将倍加高兴。

Source: https://habr.com/ru/post/zh-CN451574/


All Articles