对于微服务,有很多说法,最权威的来自于Martin Fowler 的文章。对于微服务有很多讨论,有很多实践,也遇到很多问题。包装了很多新鲜的名词和概念,让人云里雾里。但我要说的是,太阳底下没有新鲜事,关于微服务的理念,实际上并不是横空出世,而是自然而然发展出的产物,历史上已经有类似的发展脉络。Martin Fowler同样也说,它可以追溯到unix设计原则。
一、单进程的发展历史
1、函数和动态库
在汇编时代,代码都是连在一起,紧凑高效却难读,到处goto跳转。这时,伟大的C语言出现了,将代码划分成各个过程函数,函数的输入是各种类型的参数,执行后输出结果。有了函数之后,提高了很多编程效率,但不幸的是,一个程序如果要引入所有的相关代码,本身也会变得臃肿不堪,于是就有了动态库的概念。
动态库暴露给外部的都是函数名,甚至没有参数。动态库被加载入内存后,函数调用时,会根据函数名转换成内存地址,这个地址是动态计算出来的。在执行过程中,都是call函数地址,不是函数名。动态库如此好用,于是在windows系统中,出现了动态库地狱,linux稍微好点,加入了版本号。windows的程序员们也学乖了,也加入了版本号,msvcrt后面都带上了8、9等数字,表示版本。
2、多线程
单进程的一个主要是问题是,一个阻塞操作会导致进程闲置,无法继续后续的处理。文件读写稍微还好点,在网络编程流行之后,这个问题愈加严重,你永远无法知道另外一台机器究竟什么时候会挂掉,什么时候会处理完。于是多进程解决方案出现了,apache是其中的杰出代表。
多进程解决方案切换代价太大,就再次引入多线程。引入多线程之后,之前被忽视的问题就暴露出来了。就以最著名的的c标准库,就有很多是不可重入,以至于后面加入同样功能的可重入函数。在之前遗留的c代码,常常使用全局变量,毕竟没有多线程的顾虑,还要处处维护拷贝,是件痛苦的事情,而全局变量就简单多了。多线程还带来同步问题,互斥锁,读写锁,条件变量。都是伴随着多线程而出现的。
3、面向对象
c++在继承c的基础上,引入了面向对象思想。强调对象内部的数据和函数是强内聚的,而对象和对象之间是松耦合的。同名函数可以有不同的输入参数,是为多态。面向对象,更多体现出来的是一种理念上的先进。
二、服务架构的发展历史
1、单机服务
在网络出现之前,单机上其实也有服务进程,这些服务多数以进程间通讯方式交换数据,比如管道。早期的数据库如Foxpro,就是一个简单的文件模式,因为格式足够简单,加上一个读写驱动就够了。
2、网络服务
得益于网络的发展,特别是网页和浏览器的发展,服务需要处理的规模远超出单机模式,服务模式以及对应的基础组件和架构呈现井喷式发展。受制于最初互联网带宽限制,局域网反而先行发展,管理信息系统以及之后的ERP,已经从二层架构发展成为三层架构。
Apache是网页服务发展的一个里程碑,后续的jsp和php的出现,从静态网页时代进入更灵活的动态网页时代。
3、数据库
抛开早期的层次型数据库和近期的NoSQL数据库,关系型数据库是数据管理系统发展的经典之作,即使经过了几十年,依然活力十足。他让开发摆脱了数据管理的桎梏,而专注于业务的开发,从而推动了三层架构的普及。
数据集中管理带来便利的同时,也造成了数据访问的瓶颈。在业务服务增多的时候,对数据库的压力也会同时呈线性增长态势。
4、SOA
SOA出现之初,主要为了解决异构系统之间的集成,所以中间件以及协议定义和转换成为重中之重,当然还包括了网络安全。也正因为异构系统之间的复杂,SOA在解决这个问题的同时,引入了很多重量级解决方案,比如WSDL。中间件是个好东西,解决位置解耦问题,但和数据库一样,存在瓶颈问题。特别是ESB,加入更多的功能,显得臃肿不堪。
5、微服务
微服务继承了SOA很多优秀的理念,同时也摈弃了很多历史负担。因为SOA已经解决异构系统问题,所以微服务就不用背这个锅了。Martin Fowler描述了很多微服务的特性,但核心就一个字“微”,其他特性都为解决因为微字出现的问题。可以想象下,原本一个进程,现在被拆成10个进程,要解决多少问题么?
三、理念对应表
1、组件化
<1>、汇编 -->【代码太多】-->函数-->【程序太大】-->动态库-->【关联太多】-->面向对象。
<2>、单机服务-->【功能太多】-->网络服务-->【数据和逻辑混合】-->数据库-->【异构太多】-->SOA-->【单服务过于复杂】-->微服务。
从上述的走向图来看,组件化的理念从未离开我们,将大工程拆成小项目,更符合人类的行为模式。
2、作用域
<1>、全局变量-->【受多点影响】-->结构成员-->【公共可见】-->对象成员-->【命名冲突】-->名空间
<2>、数据库-->【受多服务影响】-->事务隔离-->【全局可见】-->分散数据管理
数据的作用域倾向于越小越好,这在编程理念上是合理的。但是数据库以及之后分布式存储,更多考虑的是数据可靠性和安全性。再到微服务的独立数据库的做法,又回到原点。数据和代码的关系轮回是个非常有意思的话题。
3、同步
<1>、单进程-->【性能瓶颈】-->多线程-->【访问冲突】-->锁机制-->【粒度太大】-->原子操作
<2>、单体服务-->【性能瓶颈】-->多服务-->【一致性】-->分布式事务-->【粒度太大】-->独立数据库
四、总结
Martin Fowler在微服务的特性描述中,还提到的弱化通道,应该是针对于ESB臃肿不堪的功能。而基础设施自动化,更多是解决微化之后带来的后果,不然微服务就没有办法实施了。容错设计也没有什么特点,拆得越细出错概率越大,微服务的错误概率和运维成本远超过单进程。至于断路器,只能说和杀进程的作用很相似。
在看完上面理念对应表,可以看到基本原则一直存在于软件设计领域,唯一不同的是,在SOA之后,微服务将这些概念改造得更符合当前技术发展的需要。