扫码打开虎嗅APP
本文来自微信公众号:阿朱说 (ID:azhushuo),作者:吕建伟,头图来自:unsplash
俗话说:
历史是由英雄定义的,但是是由广大吃瓜群众决定的。
股市是由庄家定义的,但是是由广大韭菜决定的。
技术是由天才程序员定义的,但是是由广大万金油码农决定的。
一、面向函数编程范式
在最早写程序,程序都是表现在打孔卡片上。你用专门的打孔卡片机的键盘进行输入,打孔卡片机经过何乐礼编码,输出给你的就是打好孔的卡片。你把打孔卡片按顺序放到计算机的读卡卡槽里,计算机一张张读入到计算机的内存里然后进行计算处理,最后把结果输出打印到计算机带的打印机打印纸上。
后来,存储技术、操作系统技术越来越成熟,而且计算机越来越便宜,就把计算机-键盘-屏幕全都串联在一起,程序员就和现在一样工作模式了。
便利的计算机设备也带来了能编写的代码的规模和复杂性日益提高,大流水的打孔卡片式编程习惯就Hold不住这种代码规模和复杂性了。所以,函数就产生了。其本质就是代码的可组织性。
但是,人们都声称代码搞成函数可以重用。
重用这个词,每一代技术、每一代编程范式,大家都会提到这个词,但实际上并不能做到这个目标。而且,发明一代技术、一代编程范式,也并非是为了解决重用这个目的的。
二、面向对象编程范式
世界上第一个面向对象编程语言是SmallTalk。这个编程语言是施乐实验室发明的。对,就是那个发明了GUI图形窗口界面的实验室,乔布斯和盖茨偷学的就是他们。
施乐实验室为啥要发明面向对象编程语言?就是因为咱们在屏幕上看到的菜单、按钮、输入框,其实都是像素组成的。像素一个个点点组成了一条条线、一个个圆圈。如果施乐实验室的人不发明面向对象语言,你想他怎么发明GUI图形窗口界面。你想,他会直接控制一个个像素点一点点组成一条线,一条条线再组成一个输入框。天哪,这颗粒度太低、这控制起来太复杂了。
所以施乐实验室的人必须发明面向对象编程语言,要操纵一个按钮就可以操纵一个按钮,不用去想一条条线段,更不用去想一个个像素点。
所以,面向对象编程范式发明的最初源确实是为了操作一个个对象,但是后来却被人们用成了代码的可见性-代码的可组织性,把更多的函数按照私有可见、保护继承可见、公有可见进行区隔。
还更多人误以为面向对象编程范式是为了代码重用。唉,这都误区到什么地步了。
三、DLL
DLL,动态链接库。
这个东西在Unix世界早就存在,只不过文件后缀名是.o。
为啥要发明动态链接库?没办法啊,当时的内存很贵、很小,你想实现更为强大的功能你就得腾挪躲闪想办法。所以大家就发明了动态链接库,等实际用的时候再载入,而不是在编译器就都编译成一块,那一个程序的尺寸大小得多大啊。这么大的尺寸,当时内存那么小那么贵,都载不进来啊。载不进来,CPU就没法执行指令啊。
这就是动态链接库的发明初衷。可惜,大家又误用了,把DLL当成共享重用的代码库,你也能调用我也能调用。
你看,一个技术的最后普及用途,往往和发明者的初衷是背离的。
四、组件
世界上第一家产生组件编程范式的公司是微软。Sun公司搞EJB组件模型是模仿微软的。
微软为啥搞组件模型?就是最初,Word软件研发组的人不想自己研发在Word中画表格的功能了(工期紧人手少啊),于是就想用Excel研发组的东西。于是使用Dll动态链接库的技术进行二进制代码共享重用(原来用歪的人还是微软自己人啊),用DDE进行共享内存-动态数据交换。
后来Word研发组的人给盖茨显摆,盖茨一下子兴奋起来了。因为当时微软Word受WordStar和WordPrefact竞争、Excel受VisiCalc和Lotus1-2-3竞争,盖茨一直冥思苦想怎么和它们竞争。盖茨看到Word组这个技术,灵机一动,竞争大整合—大集成—大套件。所以就猛推在微软Windows平台上的统一模型:组件,来达到windows平台上的各个应用都能互相调用其他软件的现成功能。
这似乎是为了重用而设的初源。但是,从此后,路就越走越歪。COM既然能在本机的各个应用程序间调用,那就想让它在不同机器的不同应用程序间调用,这就成了DCOM。因为在不同机器的不同程序间调用,那如果这个应用流程涉及到事务保证怎么办,于是又升级到了COM+进行分布式事务保证。后来互联网热了,微软人又想了,如何跨不同网络的不同机器的不同程序调用,于是发明了很容易使用webService进行跨网络的不同机器不同程序的调用,这就是.Net组件。
所以说,一个本来为了重用而设的技术,最后生生地走歪成了分布式计算技术。
而组件技术,不管是COM组件技术体系还是EJB组件技术体系,火了十年(1993-2003),还是被人们又活生生活回面向对象面向函数时代去了。组件技术事实上并未达到重用的目的,而且其复杂性被码农最终唾弃。
五、RPC
分布式计算技术起源于Sun公司。
Sun公司的首席科学家兼创始人之一Bill Joy,这人是个神人,在加州伯克利大学上学时就发明了著名的Unix开源发行版:BSD。
后来,还在Sun的Unix操作系统里率先实现了TCP/IP协议。他之所以搞这个,是因为他心中有一盘更大的棋。
因为Sun公司搞的不是IBM大型主机,也不是DEC的小型机,也不是苹果搞的个人电脑,而是工作站。工作站这个东西不上不下,所以Bill Joy一直想把工作站都串联起来虚拟整合成一台媲美大型主机的超级计算机。咦,这不就是最早的云计算思想么?
对,所以他说干就干:
发明了TCP/IP,先把Sun Unix工作站全都能串在一起通信。
再发明了网络文件系统NFS,让大家可以共享网络数据。
最后又发明了RPC远程过程调用,让大家写分布式计算应用变的简单。
这个RPC应用发明于1983-1986年之间,主要包含:
IDL接口定义语言:后来webService用XML标签改造成了WSDL接口定义语言;
注册-发现-路由:后来webService改造成了UDDI,在微服务时代又升级成为API网关或服务网关;
RPC应用调用协议:后来webService用了SOAP应用调用协议;
TCP/IP数据传输通信协议:后来webService用了HTTP数据传输通信协议;
二进制数据传输格式:后来webService用了XML文本数据传输格式。
所以大家看:
1983年发明的RPC;
1993年发明的COM,1995年升级为远程调用DCOM;
2003年发明的SOA(突出企业服务总线-WebService,淡化RPC调用);
2013年发明的微服务(突出注册发现路由-UDDI-API网关和服务网关)。
这一代代的前赴后继,每十年就重整搞一遍。
但很可悲很可笑的是,没有多少人写分布式计算的应用。这么多天才前赴后继40年投入设计和研发的东西,其实毛用没有。你说悲哀不悲哀,你说可笑不可笑。我们把问题想复杂了。
六、SOA
很多人是这么想的:SOA,服务比组件颗粒度大,组件比对象颗粒度大,对象比函数颗粒度大。
所以很多人也想当然地认为:SOA,是比组件更先进的技术。所以很多人也想当然地认为:组件既然初衷是为了一个应用调用另外一个应用的现成功能,那么SOA一定也是为了既可以功能重用,也可以进行跨机器跨网络地远程重用。
嘿嘿嘿,其实大家想的完全错了。
SOA的目标,既不是为了简化组件开发(当年很多人诟病EJB的复杂性),也不是为了功能重用,也不是为了分布式计算——跨机器跨网络远程调用。
SOA出台的目标是:集成。
所以IBM力推SOA的时候,打的口号是集成,落地的产品和技术是BPM-BPEL。很多人不理解IBM为啥推SOA概念时是三件套:SCA、SDO、BPEL。而很多人其实这三件套都没有使用,而实际上主要使用企业服务总线-ESB,也就是说,别管你是RPC远程调用(RPC协议+二进制+TCP/IP)还是WebService调用(SOAP协议+XML+HTTP),我都统一方式处理。
唉,好端端的应用集成,又被人们用成了不是分布式计算的分布式计算。为啥我会这样说,就是因为分布式计算本来Bill Joy的初衷是让N台工作站虚拟整合成一台超级计算机,分布式计算这个初衷大家用SOA是没实现。
另外,人家IBM推SOA,是在应用视角通过BPM-BPEL进行应用集成,大家反而不用BPM-BEPL,而是在技术视角通过RPC或WebService进行系统API打通整合。是,用了企业服务总线进行系统API打通整合确实比过去蜘蛛网互相调用要顺眼的多,但是这并不是SOA的初衷啊。真是错错错。
还有人还更以为SOA的初衷是为了重用,这更是TMD错的到家了。
七、微服务
很多人以为微服务这个东西是比SOA面向服务的颗粒度更小,就如此而已,目的肯定还是为了应用集成-系统整合打通。
哈哈哈哈,根本不是这样啊。因为微服务这个词是Spring的首席布道师在2013年提出的。
Spring这个东西诞生在SOA概念最火热的2003年。但是为啥Spring的首席布道师在2013年反而又提了微服务呢?
Spring的出现初衷本来是为了简化J2EE(有状态的Session Bean、Entity EJB-ORM持久化、事务保证)。Spring本来是和SOA没啥关系的,只不过它的出现时间和SOA概念出现的时间恰巧重合了而已啊。但是不知大家是什么脑回路逻辑,就生生把Spring和SOA就挂在了一起。甚至到了2013年以后,还有人叫嚣着:用了Spring(或者Spring Boot或者Spring Cloud for Netflix),就是微服务。
唉,错错错。
微服务出现的背景是互联网时代啊。在Web2.0之前的互联网确实比较简单,但是Web2.0之后(2004年Web2.0兴起),互联网应用也变得越来越复杂了。
所以,当时互联网公司面临两个重大难题:一是应用如何高性能运行,以便应对海量并发用户——海量数据;二是那么多研发团队在并行研发,应用异常之间如何隔离,让一个应用的错误不要蔓延到其他应用,防止某个应用的错误拖垮整个网站。
应用之间如何集成—如何API打通整合—如何API治理,这些东西,在SOA时代,互联网公司已经解决了。现在,要解决的是我上述说的两个新的更突出的问题。
所以你看VMWare公司最后思来想去,不仅并购了Spring,还并购了Cloud Foundry,并且整合他们两。而CloudFoundry当时解决高性能运行-大规模分发部署、应用之间隔离,用的方法就是Bundle。这是Cloud Foundry公司自己定义的一种打包方式,后来被Docker容器业界通用技术(来自Linux Cgroup技术)代替。
大家想想VMWare为啥要并购Cloud Foundry?大家想想虚拟机、容器(Bundle-Docker)、编程语言虚拟机(如字节码Java VM、如现在的虚拟二进制指令集wasm),嘿嘿嘿,大家是不是有种异曲同工的感觉?对,他们其实都是在不同的层面(操作系统层、语言层、应用层)切割了计算资源,目的一样,但是杀鸡各有各的擅长杀法。
所以,如果你的应用不像互联网应用那样:需要高性能运行、需要研发团队并行研发—应用异常隔离,那么你其实就不需要微服务技术。
呜呜呜,大家把技术都瞎用成啥了。居然还有人以为微服务技术也是为了重用。为啥大家这么执着一个已经幻想了半个世纪也没有实现的幻想呢?很是奇怪。
八、少服务
AWS在2015年发布了少服务Serverless:Lamda。2015年,云原生基金会CNCF也成立了。
CNCF是谷歌领导成立的。谷歌是家互联网公司,做出信息服务或软件软件服务,大家通过互联网就可以直接使用、订阅付费,谷歌一直持续改进这个信息(软件)服务就行,大家等着更新使用就行。比如大家使用的搜索信息服务、Gmail和GDocs软件服务都是这样。
所以,如何快速迭代、快速发布、大规模部署、快速弹性伸缩,这是谷歌一直关注的,这也是云原生CNCF一直关注的。所以大家看到了k8s自动化编排调度-Docker容器打包-CI持续集成工具-CD持续发布持续交付工具-DevOps工具,这条工具链成为了云原生CNCF云图中的核心。
很多人不明白云原生为啥以这条工具链为核心。很多人想着云原生的核心应该是微服务啊,或者是少服务啊。
其实不是,因为云原生目标要解决的核心问题是:快速迭代、快速发布、大规模部署、快速弹性伸缩。
如果你没有这个需求,你用云原生技术就错配了。
很多人说,那CNCF现在也力推少服务Serverless,到底是因为啥?
对,还是为了快速迭代、快速发布、大规模部署、快速弹性伸缩。
现在,CNCF为了这个目标,已经构筑成了一个完整的体系:
Service Weaver应用框架(Golang语言)
KNative(Serving、Eventing)(2021年底发布1.0正式版)
Istio-Envoy-gRPC
Tokten CI-Argo CD
Docker打包-k8s自动化编排调度
DevOps(EFK、Prometheus+Grafana、Jaeger)
不过我眼睁睁地看到业界把Serverless又用成了微服务。少服务-微服务,就差一个字嘛,都一样嘛。嗯,秀才认字认半边嘛。
本文来自微信公众号:阿朱说 (ID:azhushuo),作者:吕建伟