vlambda博客
学习文章列表

云原生时代Java面临的不适与挑战

Java优势

Java已经有20多年的历史,广泛应用于各行各业,凭借自身活跃的开源社区和完善的生态优势,给组织以及个人带来切实价值。第一点、借助于虚拟机解决了编程语言上的一个巨大问题,允许我们编写一次代码并在多个平台和操作系统上运行。

第二点、Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言广泛应用于各行各业,从整体上来说,Java是面向大规模、长时间运行的服务而设计的,囿于自身封装良好的特性约束所有人写出比较一致的代码,有利于软件规模得到提升。代码量提升起来之后,可以借助于基于Java生态的第三方优秀框架比如SpringCloud、dubbo、netty等,把现有服务拆分为一个个微服务,在以Java技术栈为基础互联网公司更倾向于各个微服务都采用Java语言开发,以求最大程度上降低研发成本,研发人员根据服务请求数量把服务部署为一份或者多份,从而实现服务动态扩缩容。

以上都是Java编程语言的优势,而来到云原生的今天,Java的这些优势变得不值一提,有些特性反而变成了自己的劣势,为什么呢?

Java劣势

第一点、Java的一次编译到处运行,在云原生时代我们可以将应用程序、库和操作系统资源打包到可以在任何地方运行的单个容器中,可以保证各个环境的严格一致性。因为JVM本身占用存储空间较大,导致最终镜像文件变大,使得镜像拉取和运行效率降低; 再者JVM本身是一个运行在操作系统上虚拟机系统,JVM 以及在 JVM上跑的应用程序所消耗的内存较大,是造成资源利用率低的最主要原因,不仅如此当把虚拟机打包成镜像之后会出现对容器化服务资源(CPU、内存)亲和性存在问题,虚拟机过去的优势反而成为今天的一个劣势。

第二点、因为java自身是解释性语言,所以Java启动和运行速度相对较慢,它不像C++那样直接被编译为可执行的机器代码运行。Java是通过虚拟机运行字节码,再加上spring等重型依赖注入框架,这就导致整个服务启动需要很长时间,往往几十秒,特别是以Java技术栈划分微服务时,每一个服务运行时都需要消耗较多资源和时间,容器启动生命周期拉长,在云原生时代今天,Serverless正在吞噬整个世界,在启动和运行速度都有新的要求,架构讲究的是轻量级、服务不需要常驻内存,当请求到来时,服务才会被激活。相较于JavaScript、go、python, Java的表现让人不可接受。

当然Java历史悠久,拥有大量用户和完善的生态,这同时是Java的优势,也是Java编程语言的一个沉重包袱,Java如何甩掉这个沉重包袱,进军云原生,同时Java针对这些问题做出了什么改变?

Java做出的改变

支持容器 https://blogs.oracle.com/java-platform-group/java-se-support-for-docker-cpu-and-memory-limits云原生时代Java面临的不适与挑战这段话大概意思是说:Java8u131 (17 年 4 月发布)开始通过选项支持对容器内存和CPU的限制,主要是CPU层面支持GC线程数和JIT编译线程数以及内存层面Heap大小限制。但其实打开jdk8u131 release notes发现并没有容器相关的变化,确切来说131的版本并没有说明解决容器相关问题, 但从jdk8u191才真正解决了之前Java服务运行在容器中的问题,还可以通过 -XX:ActiveProcessorCount=count 自定义CPU数量,并且新版本还支持对Java Heap设置百分比。建议升级到该版本以及以上版本。如果在Kubernetes平台上延用类似于jdk1.7老版本,就需要配置虚拟机本身的资源占用,否则就会出现JVM不能感知到Pod的资源分配情况,如下所示:

JDK9 实现了模块化,可以将代码进行模块化的组装,需要用到什么模块再引用什么模块.减少了不必要的内存消耗和资源浪费,同时镜像体积大大缩小。

SpringBoot 基于Spring Boot 2.3以上版本方便创建分层Docker镜像,这样在构建镜像的时候就可以复用上一次构建产生的镜像,而不是重新构建,这样大大提升镜像的构建效率。

GraalVM 为了全面面对容器化的转型,Oracle推出了GraalVM,该vm支持多个编程语言的运行时,并可以使Java代码编译为机器码,这意味着Java代码可以直接编译为机器特定的代码。生成的程序不在Java HotSpot VM上运行,而是在机器上直接运行,实际上这就是AOT编译相对JIT编译带来的性能优势,不过Java早期版本运行时的类加载,反射,代理等功能的严重限制AOT编译的推进,(比如我们常用spring框架很多功能都是运行时动态加载完成的,而AOT却要求编译期完成所有类的加载。)该项目目前活跃度和关注度都很高。

总结

当然在微服务、云原生大行其道的今天,一个服务可以按照职能或者业务等方式垂直拆分为多个业务,之后新产生业务我们可以选择更适合云原生的编程语言或者技术。但我更希望Java自身能够朝着云原生和微服务的环境靠拢和适应。这是听了周志明老师讲解云原生时代Java之后的一些感想,如有问题请留言或者关注后拉你进群讨论,希望能够帮助到大家,谢谢!

推荐阅读



原创不易,随手关注或者”在看“,诚挚感谢!