云原生之下的Java

自从公司的运行平台全线迁入了 Kubenetes 之后总是觉得 Devops 变成了一个比以前更困难的事情,反思了一下,这一切的困境居然是从现在所使用的 Java 编程语言而来,那我们先聊聊云原生。

Cloud Native 在我的理解是,虚拟化之后企业上云,现在的企业几乎底层设施都已经云化之后,对应用的一种倒逼,Cloud Native是一个框,什么都可以往里面扔,但是有些基础是被大家共识的,首先云原生当然和编程语言无关,说的是一个应用如何被创建/部署,后续的就引申出了比如Devops之类的新的理念,但是回到问题的本身,Cloud Native提出的一个很重要的要求,应用如何部署 这个问题从以前由应用决定,现在变成了,基础设施 决定 应用应该如何部署。

让我们回到一切的开始,首先云原生亦或者是Devops都有一个基础的要求,当前版本的代码能够在任何一个环境运行,看起来是不是一个很简单的需求,但是这个需求有一个隐喻所有的环境的基础设施是一样的,显然不能你的开发环境是 Windows 测试环境Debian生产环境又是Centos那怎么解决呢,从这一环,我们需要一个工具箱然后往这个工具箱里面扔我们需要的工具了。首先我们需要的就是 Cloud Native工具箱中最为明显的产品 Docker/Continar,经常有 Java 开发者问我,Docker 有什么用,我的回答是,DockerJava 不是必须的,但是对于其他的语言往往是如果伊甸园中的苹果一样的诱人,打个比方,一个随系统打包的二进制发行版本,可以在任何地方运行,是不是让人很激动,对于大部分的Java开发者可能无感,对于C语言项目的编写者,那些只要不是基于虚拟机的语言,他们都需要系统提供运行环境,而系统千变万化,当然开发者不愿意为了不同的系统进行适配,在以前我们需要交叉编译,现在我们把这个复杂的事情交给了Docker,让Docker如同Java一样,一次编写处处运行,这样的事情简直就像是端了Java的饭碗,以前我们交付一个复杂的系统,往往连着操作系统一起交付,而客户可能买了一些商业系统,为了适配有可能还要改代码,现在你有了Docker,开发者喜大普奔,而这里的代价呢?C&C++&GO他们失去的是枷锁,获得全世界,而Java如同被革命一般,失去了 Once Code,Everywhere Run,获得的是更大的 Docker Image Size,获得被人诟病的 Big Size Runtime

当我们从代码构建完成了镜像,Cloud Navtive的故事才刚刚开始,当你的Team Leader要求你的系统架构是MicroServices的,你把原来的项目进行拆分了,或者是开发的就拆分的足够小的时候,你发现因为代码拆分开了,出现了一点点的代码的重复,有适合也避免不了的,你的依赖库也变的 xN,隔壁Go程序员想了想,不行我们就搞个 .so 共享一部分代码吧,然后看了构建出来的二进制文件才 15MB,运维大手一挥,这点大小有啥要共享的,Java 程序员望了望了自己的 Jar 包,60MB还行吧,维护镜像仓库的运维同事这个时候跑出来,你的镜像怎么有 150MB 了, 你看看你们把磁盘都塞满了,只能苦笑,运维小哥坑次坑次的给打包机加了一块硬盘,顺便问你马上部署了,你需要多大的配额,你说道 2C4G,运维一脸嫌弃的问你,为什么隔壁GO项目组的同事才需要 0.5C512MB。你当然也不用告诉他,SpringBoot 依赖的了 XXX,YYY,ZZZ 的库,虽然一半的功能你都没用到。

部署到线上,刚刚准备喘口气,突然发现新的需求又来了,虽然是一个很小的功能,但是和现在的系统内的任何一个服务都没有什么直接关联性,你提出再新写一个服务,运维主管抱怨道,现在的服务器资源还是很紧张,你尝试着用现在最流行的 Vertx开发一个简单的Web服务,你对构建出来的jar 只有 10MB 很满意,可是镜像加起来还是有 60 MB,也算一种进步,你找到QA主管,准备Show一下你用了Java社区最酷的框架,最强的性能,QA主管找了一个台 1C2G 的服务让你压测一下,你发现你怎么也拼不过别人Go系统,你研究之后发现,原来协程模型在这样的少核心的情况下性能要更好,你找运维希望能升级下配置,你走到运维门口的时候,你停了下来,醒醒吧,不是你错了,而是时代变了。


云原生压根不是为了 Java 存在的,云原生的时代已经不是 90 年代,那时候的软件是一个技术活,每一个系统都需要精心设计,一个系统数个月才会更新一个版本,每一个功能都需要进行完整的测试,软件也跑在了企业内部的服务器上,软件是IT部分的宝贝,给他最好的环境,而在 9012 年,软件是什么?软件早就爆炸了,IT从业者已经到达一个峰值,还有源源不断的人输入进来,市场的竞争也变的激烈,软件公司的竞争力也早就不是质量高,而是如何更快的应对市场的变化,Java就如同一个身披无数荣光的二战将军,你让他去打21世纪的信息战,哪里还跟着上时代。

云原生需要的是,More Fast & More Fast 的交付系统,一个系统开发很快的系统,那天生就和精心设计是违背的,一个精心设计又能很快开发完的系统实在少见,所以我们从 Spring Boot 上直接堆砌业务代码,最多按照 MVC进行一个简单的分层,那些优秀的OOP理念都活在哪里,那些底层框架,而你突然有一天对Go来了兴趣,你按照学 juc 的包的姿势,想要学习下 Go 的优雅源码,你发现,天呐,那些底层库原来可以设计的如此简单,Cache只需要使用简单的 Map 加上一个 Lock 就可以获得很好的性能了,你开始怀疑了,随着你了解的越深入,你发现GO这个语言真是充满了各种各样的缺点,但是足够简单这个优势简直让你羡慕到不行,你回想起来,Executors 的用法你学了好几天,看了好多文章,才把自己的姿势学完,你发现 go func(){} 就解决你的需求了,你顺手删掉了 JDK,走上了真香之路。虽然你还会怀念 SpringBoot 的方便,你发现Go也足够满足你 80%的需求了,剩下俩的一点点就捏着鼻子就好了。你老婆也不怪你没时间陪孩子了,你的工资也涨了点,偶尔翻开自己充满设计模式的 Old Style 代码,再也没有什么兴趣了。


PS:今天被查出来肾结石 17MM 了,兄弟们还是多注意身体,多喝水,保持锻炼。