现在,越来越多的人了解 Go 语言,学习 Go 语言,越来越多的公司开始尝试采用 Go 语言。我也是一直在用 Go 作为服务端开发的主力语言,也了解过 Java 和 Spring 那一整套服务端开发体系,时常在想,Java 的这一套体系,在长时间的迭代下,技术沉淀和业务覆盖已经非常完善,为什么 Go 还能脱颖而出?让大家所熟知。我知道,这中间存在一些从众效应,尤其是大公司的带头使用带来的引领作用,这为 Go 的声名带来了正向反馈,使 Go 越来越被人们所了解。
抛开这些不谈,Go 本身也是有一些独门绝技,否则,它活不过开头,也就没有后续的正向反馈作用了。我想,找出这些独门绝技绝不是无用的思维内耗,它可以让我们这些 Gopher 找到未来发展的方向,确定未来学习的思路。
当我们比较 Java 和 Go,我们在比较什么?
2007 年 9 月,像往常一样,一位程序员正靠在椅子上喝着咖啡,他在等着自己提交的代码被编译结束。这是一个巨大的工程,整个编译过程大约要持续 45 分钟,而他现在能做的也只有等待。这时,桌面上弹出的待办事项引起了他的注意,这是一次即将开始的宣讲会,几位 C++ 的同事将宣讲有关即将发布的 C++11 的新特性,他自然不能错过,于是他离开工位,坐到了会议室。
讲台上,负责宣讲的同事神采飞扬,滔滔不绝地介绍着整整 35 项新特性。据他们透露,这还只是其中一部分。他抿了一口咖啡,仔细地听着,右值引用,这是什么鬼?可变参数模版,听起来倒很 C++...... 突然他感觉有些厌烦,C++真的需要这么多新特性吗?他想,有人说语言升级的更大成就不是添加了多少东西,而是减少了什么东西,尽管这话有些片面,但不失为有一定的道理。
他的思绪回到了几个月前,那时候他在宣讲一个由他创造的语言 Newsqueak,这个语言使用了 CSP 并发模型,这是一个很优雅的模型,他想把它加入到 C++ 中,可总是没办法协调的很完美,问题出在哪?似乎 C++ 太过复杂了,他也不敢说自己完全理解了 C++。
讲台上的声音突然停止了,这打断了他的思绪。另一位同事上来介绍一个新特性:原子类型。这是语言层面支持的原子性,通过硬件来保证的原子性。听到这里,他突然握紧了自己的咖啡杯,是的,问题出在这里,将这样一组微观定义的细节放入一个已经不堪重负的类型系统中,是短视的。因为底层的硬件在未来十年可能会发生翻天覆地的变化,将语言与当下的硬件紧密结合是不明智的。
他应该设计一门新语言,一门面向未来的语言,它简约、易懂、使用 CSP 模型。这个想法使他热血澎湃,他想着会议一结束就去和坐在他旁边的 Robert Griesemer 交流这个想法。当主持人宣布会议结束时,他迫不及待的走回办公桌,看到桌上自己的电脑已经提示编译完成,耗时 45 分钟。
对了,他想,这个新语言还要有个功能,那就是编译快。
这篇小短文不是我的杜撰,而是 Go 语言的作者之一 Rob Pike 的真实经历,尽管经过了艺术加工,但我们也可以看到文中主角敏锐的判断力。是的,十年过去了,软件的运行环境发生了翻天覆地的变化,原先你可以确切地说,我的程序运行在什么架构 CPU、几 G 内存的机器上。现在,容器和 Kubernetes 的变革已经让你回答不了这个问题。它可能这一秒运行在这台机器,下一秒被调度到其它机器;甚至机器本身,也可能是虚拟机、或者虚拟机虚拟出来的虚拟机。硬件已经被抽象,变成了一个被称作“云”的庞然大物。
让我们从 Go 诞生的故事回到当下,Java 语言依旧是服务端当之无愧的王者,而 Go 语言会是那颗闪着银白色寒芒的天狼星吗?很多人在发问,也有很多人从语法、框架、面向对象和面向接口......层面去对比,去分析。
我也一直在思考这个问题,我现在的答案是,会,但有前提条件。
如果我们一直从语法、框架、面向对象的层面去对比,那么永远也不会有结果,“术”的层面总是各有优劣的,我们要一起往更深一层次去分析。
于 Java 而言,核心是 Spring,以及那句名言:“一切皆对象”。很多 Java 程序员最爱干的,应该就是“抽象”这个事儿,所以如何合理的设计和抽象,让代码可读,成为了衡量 Java 程序员最重要的指标之一。从公司的角度看,日积月累的抽象,也让内部的框架越来越复杂,功能越来越多,甚至最后,这个框架本身都可以拿去 2B 的市场去卖个好价钱。框架,也成为了Java最大的护城河,很多刚从 Java 转 Go 的程序员都会问一个可爱的问题:“Go 有类似于 Java 这种 Spring 的框架吗?”
请大家等等,请大家停下来想想,如果 Go 有这种框架,那么转 Go 的意义是什么呢?Go 的 CSP 模型这么吸引人,Java 难道就没有吗? Java 以前不够快,现在还不够快吗?容器镜像大?能大多少,这点差距对你的业务真的很重要吗?
如果这些问题无法回答,那么转 Go 只不过是一次内耗,或者是某人的一次 KPI 行动。
事实上,我认为,如果不是一样东西的横空出世,Go 是不可能取代 Java 的,你不可能在竞争对手的优势领域打败它。
这样东西叫微服务(Microservices),谈到它,大家应该很不陌生。微服务嘛,那就得拆,把服务拆散,怎么拆呢?网上搜,有人说:“这么办,单体服务,我们竖着给它一刀,把它按业务拆分,这叫 SOA 架构;再横着给它一刀,把它按代码层次拆分,这叫水平分层架构。好了!这就是微服务了。”当年我看到这句话,豁然开朗,原来,SOA+水平分层就是微服务,简单,这就把单体服务按在手术台上大卸八块。
等等,各位,我们还是要停下来想想,就这么一个服务拆分方案,有必要搞得这么火吗?
有人又说,那是因为你切的不对,你得按照 DDD(领域驱动设计) 的法则来切。
让我们先放下手中的手术刀,回顾一下微服务的定义:“微服务是一种通过多个小型服务组合来构建单个应用的架构风格,这些服务围绕业务能力而非特定的技术标准来构建。各个服务可以采用不同的编程语言,不同的数据存储技术,运行在不同的进程之中。服务采取轻量级的通信机制和自动化的部署机制实现通信与运维。”这个定义到底在说什么?
不同语言?不同进程?轻量通信?那我 Java 的 Spring 怎么办,别的语言不一定有。我框架封装的通信不可能轻量啊,要实现那么多功能:负载均衡、限流、健康检查、监控等等等等,难道我每个语言都实现一遍吗?
想到这里,我们回到本节的开头之问,我们的比较,本质并不是 Java 和 Go 之争,而是以 SDK、Libary为代表的框架思想,和微服务代表的服务思想之争。这是一场思想上的革命,在微服务看来,整个系统是由一个一个的服务组成的,服务和服务之间相互解耦,各自完成自己的职责,共同对外提供服务。在这个世界里,不存在一种上帝般的框架,所有服务都要接入,都要信仰。
失去了框架的束缚,各服务可以自由迭代,自由选择语言,自由替换,自由伸缩。容器和 Kubernetes 会保证这些服务的有序调度,ServicesMesh 会保证负载均衡、限流、健康检查、监控等一系列事项的正确运行。
因此,正是因为现在流行的这些技术,催生了微服务的土壤。这是一种思想观念的转变,从重框架,重设计的思想,转变为重服务,重Sidecar的思想,而我们正处在这一时代的变革之中,Java社区、Java的维护者,这些世界顶级的聪明人,他们何尝不知道,Java也在改变,也想顺应这个时代的变化,变得轻量、快速。但有个人告诉过我们,看待事物要辩证的看待,当年Java搭建的护城河,那些让它登顶的技术,同样也是它现在要改变所碰到的最大壁垒。
在这个时代的转变中,Go语言成为了其中的基石,不是因为它设计的多么精妙(事实上,比它设计的精妙的语言多的是),而是因为它是其中一些技术的关键语言。
编程历史学
我一直在想,为什么我们的大学没有这样一门学科,从世界第一台计算机埃尼阿克开始,编程经历了多少令人心醉的故事,衍生出了多少技术分支。其中一些分支永远也不会有人提交了,它输在了时代的竞争中;其中一些分支被合并到主线,成为了我们的主流技术。也许是编程技术发展的太快,相比回溯过去,我们更向往未来的提交。
但回溯真的不仅仅是一种怀念,它让我们了解到一个技术的由来,而不仅仅是通过它的官网简介,我们要知道它为什么出现,要解决什么问题。通过历史的经验,我们可以总结出,它能不能解决这些问题。
是的,我已经从事编程5年了,也时常听到这些问题,有人说,技术更新换代太快,学不动了;有人说,技术没什么用的,不要沉迷技术;有人说,我们要学习底层技术,才不会被时代淘汰。
各位读者还记得自己第一次运行成功的喜悦吗?为什么,为什么越到后面越悲观了呢?为什么35岁淘汰论总是围绕着技术人?
如果在技术范围内找问题的答案,永远也不会有答案。学习更多的技术防止淘汰?如果你学的技术本身就要被时代淘汰,这和49加入国军有什么区别。花心思学习底层技术?各位如果是编程新手,我想说,现在市场上这种岗位非常少,专门为这些底层,如操作系统、算法、网络设计的专门岗位,即使有,要求也非常高。你可以让底层技术作为你的优势科目,但千万不能想着光靠它吃饭。
一定要跳出技术看技术。本质上,技术就是一种工具,谁的工具?市场、公司的工具。它们用技术为自己盈利,用技术制造护城河,打败竞争对手。虽然和“技术改变世界”的口号不一样,我们技术人似乎是时代的弄潮儿,其实不是,从古至今,盈利才是时代的本质。技术可以很重要,也可以很不重要,取决于它们用技术作为自己的核心盈利点还是边缘辅助业务。
请先不要去痛骂资本,痛骂它们是金钱的奴隶。辩证地想一想,正是因为它们想盈利,它们选择了先进的技术,技术才能改变世界。
那么,未来它们需要什么样的技术,学了这些技术的人就不会被淘汰,反而会成为自己的核心竞争力。
怎么样,以上是不是一句废话,你可能会说,我要是知道未来它们会用什么技术,我还干技术干什么,我去买彩票不好吗?稍安勿躁,各位:我们虽然不是东方朔,但是我们可以了解历史,去思考“一门技术的创造原因是什么?被选择的原因是什么?它在那个历史条件下被选择,在如今的环境下还会被选择吗?或者是被淘汰?我该不该选择学习这门技术?”
以史为鉴,可以知兴衰。这就是编程历史学的魅力。
Gopher 的真正核心竞争力
到了这儿,各位Gopher是不是有点激动,计算机和编程已经深入了各行各业,程序员再也不是原来那个神秘、高收入、令人尊敬的工程师,也只不过是一个普通的技术人员。下一步,时代的车轮滚滚转动,市场选择微服务,选择一种更进退自如、能够自愈的架构方式,代替原来万能框架,又会带来一次新的变革。
在这场变革中,Gopher如果不能转变观念,还是以学习java那一套来学习go世界,应该很快会碰到一个问题,那就是go本身也没什么好学的。
go面试就没有Java面试那么丰富的知识点,没有23种设计模式,没有JVM,语法层面也没有什么特别多的问题,更没有统一的框架可以问。也只能问问Channel、GC 这块。
所以既要学好 Go 本身,更要学好微服务,学好实现微服务要用到的各种工具:容器、Kubernetes、ServicesMesh。由于这些工具很多都是用 Go 编写,这就为我们的阅读、学习、改造提供了便利。近水楼台先得月,这就是Gopher的核心竞争力。
微服务的优与劣
总结一下,微服务是一场架构层面的变革,而 Go 由于其简单实用的语法、编译快、可执行文件小等特点,是微服务所依赖的底层基础设施常用语言,这也许会为 Go 开发者进一步学习提供一定的基础,但“千里之行始于足下”,如果不认真去学,一步一个脚印,知识也不会凭空而来。
我在前面的篇幅着重介绍了微服务,似乎它就是未来软件开发的首选,以后每个开发、每个公司都会选择它,但我们都知道:“软件开发没有'银弹'”,一个事物,如果它的优势越明显,那么它的劣势也越明显,而且一般来说,它的劣势就是它优势的反面。
微服务优势可以总结有如下几点:
- 业务代码和技术代码分离
原先在框架内部的代码如负载均衡、服务注册、熔断限流、链路追踪等等,均沉淀到技术底层,对业务的开发人员透明化,业务开发人员可以更好的思考用什么语言、什么存储去实现服务逻辑,而不必受到框架的限制。
- 快速迭代,稳定发布
微服务专注于一项功能,且有清晰的接口边界。这样,无论是迭代升级,还是完全推到重来,改造的成本都比较小。而且,由于底层调度系统的支持,发布服务时再也不用等到凌晨用户量少的时候偷偷更新一下,发布变得更快速更稳定。
- 简化开发步骤,提升效率
微服务化以后,对于普通开发人员而言,负担是更轻了的,技术代码的抽离使底层技术成为黑盒,开发新服务只需要一个轻量的框架,快速配置一下即可马上开始开发,梦回 SpringBoot 时代。
而微服务的劣势,同样也是三点:
- 沉重的技术架构带来的考验
代码的分离势必导致团队内对底层服务的了解更少了,即使团队内有人愿意去学习,一方面可能了解的人不愿意花心思科普;另一方面自己也有沉重的业务开发负担,精力不够。
所以有关微服务的书籍都会不约而同的提到“康威定律”,就是要求这些分离出去的技术设施需要独立团队维护。自从阿里提出“中台化”战略后,这些基础设施也有高大上的名字:“技术中台”。
但理想很丰满,现实很骨感。就我的角度看,这样一个团队在中小型公司存活的概率不大,一方面这些设施的建设是长期工程,短期难见成效;另一方面,这个团队在内部推行新设施的阻力也是比较大的,容易遭到业务侧的反对。
可是这个团队无法成立,微服务就只能沦为拆服务的游戏。
- DevOps 的要求
微服务同样对运维团队提出了更高的要求,也就是现在常听的“DevOps”。原先发布可能就是丢个包上去就行,那些“build once , run anywhere”什么的口号都是广告,实际上普通的公司也没那么多的平台需求。
现在发布要搭建一套自动化发布流,与“技术中台”团队有更多的重合部分。实际上问题和“技术中台”团队碰到的差不多,效益和推广问题。
但 DevOps 稍微温和一些,因为实打实的能在短期内看到效果(发布变快了)。
- 固化程序员的阶层
普通开发者能更快的开发程序,关注更少的架构侧的变化,对公司是好事,对个人不见得是好事。技术团队由人人都可能成为精英,变成了少量精英带领大量技术工人。原先人人开发,线上出现问题,大家各自解决 bug。现在,bug 先由基础设施过滤一遍,一些可能不会出现,一些可能基础设施本身就解决了。导致工人们无法处理更多的 bug,获得更多的实践经验。
举个例子,一个新手后端开发,原先写的代码可能会导致流量过大时出现内存泄露,本来是一个严重的错误,但是在微服务架构下,流量变大时,服务自动扩容,可能内存泄露根本不会被触发,那这位新手后端开发永远也不会知道自己的代码哪里出现了问题。
那么,精英们在优化基础设施的过程中越来越巩固自己的知识,工人们却已经无法通过实践更新自己的认知,这种马太效应会越来越分化精英和工人之间的差距。
工人们能通过学习改变自己吗?就软件学科而言,很难。没有实践,看再多书,学再多的东西,只不过是什么时候会忘记的问题。
参考文献
- 《凤凰架构》 icyfenix.cn/architectur…
- 《微服务设计》
作者正在找工作,在新的一年,希望能迎接更多的技术挑战,深入云原生领域学习,尤其是服务治理和可观测性,如有相关岗位可与我沟通~