云原生时代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
从8u131
(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之后的一些感想,如有问题请留言或者关注后拉你进群讨论,希望能够帮助到大家,谢谢!
推荐阅读
原创不易,随手关注或者”在看“,诚挚感谢!