在软件架构演化历程中,每一种风格的架构诞生并非一蹴而就,而是经历了持续的演变和优化。本部分内容主要探讨软件架构设计的演化史以及不同时代的演化过程。
一、原始分布式时代的 Unix 设计哲学下的服务探索
1 、Unix 的分布式设计哲学
Simplicity of both the interface and the implementation are more important than any other attributes of the system — including correctness, consistency, and completeness.
保持接口与实现的简单性,比系统的任何其他属性,包括准确性、一致性和完整性,都来得更加重要。
—— Richard P. Gabriel,The Rise of 'Worse is Better,1991
Unix 的分布式设计哲学奠定了分布式架构演化的基石,正如 Richard P. Gabriel 在 1991 年所言:“保持接口与实现的简单性,比系统的任何其他属性,包括准确性、一致性和完整性,都来得更加重要。”这一观念强调了系统的简洁性,使得接口和实现的简单化成为系统设计的核心。
目标:构建更大型的系统
原始分布式时代的目标是通过多个独立的分布式服务协同工作,构建更大型的系统。当时,计算机硬件的运算能力相对有限,限制了单台计算上信息系统软件所能达到的规模。为了突破这一限制,各个高效、研究机构和软硬件厂商纷纷开始尝试用多台计算机共同协作来支撑软件系统的运行。
探索与研究
原始分布式时代标志着对分布式架构最初步的探索与研究。由于硬件限制,将系统拆分到不同的机器上引发了一系列的问题,包括服务发现、跟踪、通信、容错、隔离、配置、传输、数据一致性和编码复杂度等多方面的挑战。然而,正是这个阶段,许多技术和概念被提出,对 Unix 系统和今天的计算机科学的多个领域产生了深远的影响。
影响与贡献
80 年代初期,惠普提出的网络运算架构(Network Computing Architecture,NCA)成为未来远程服务调用的雏形。
卡内基·梅隆大学提出的 AFS 文件系统(Andrew File System)是分布式文件系统的最早实现。
麻省理工学院提出的 Kerberos 协议,是服务认证和访问控制(ACL)的基础性协议,是分布式服务安全性的重要支撑,目前包括 Windows 和 macOS 在内的众多操作系统的登录、认证等都会利用到这个协议。
2 、挑战与教训
尽管原始分布式时代取得了显著的成就,但由于硬件限制,将系统强行分布到不同机器中导致了许多问题。
在这一时期,计算机科学家 Kyle Brown 回顾道:“这次尝试最大的收获就是对 RPC、DFS 等概念的开创,以及得到了一个价值千金的教训:某个功能能够进行分布式,并不意味着它就应该进行分布式,强行追求透明的分布式操作,只会自寻苦果。”
原始分布式时代为软件架构的后续演化奠定了基础,同时也为我们提供了宝贵的经验教训,为更高层次的架构设计奠定了基础。
二、单体系统时代的架构风格
在软件架构的演进中,单体架构是最早出现、应用最广泛、使用最为普遍、统治历史最长的架构风格之一。
1 、单体架构的地位
首先,我们需要澄清一个思维误区:单体架构并不等同于落后的系统架构,也并非注定会被微服务所取代。在许多关于微服务的文献中,单体架构往往被描绘成反派,但很多时候他们指的是大型的单体系统。
对于小型系统来说,仅需单台机器支撑其运行的情况下,采用单体架构风格是完全合理的选择。这种架构不仅易于开发、易于测试、易于部署,而且由于各功能、模块、方法的调用在同一进程内完成,避免了进程间通信,提高了程序的运行效率,相较于分布式系统更具优势。
在探讨单体架构系统缺陷的时候,是要基于软件系统的性能需求超过了单机,软件研发人员规模明显超过了“2 Pizza Teams”范畴的前提下,这样的单体架构缺陷讨论才更有价值。
2 、两个披萨原则
“两个披萨原则”最初由亚马逊的CEO贝索斯提出,他认为如果两个披萨无法满足一个项目团队的需求,那么这个团队可能规模太大。人数过多的项目团队会阻碍决策的形成,而小团队更有利于形成共识,有效推动企业内部的创新。
3 、单体系统的可拆分性
单体系统具备纵向和横向两个方向的拆分能力:
纵向拆分
在过去的工作经历和现代信息系统中,几乎不可能找到一个完全不分层的大型系统。
分层架构是广泛采用的软件设计方法,无论是单体还是微服务,都会对代码进行纵向拆分,外部请求在各层之间以不同形式的数据结构进行流转,最终返回响应。
横向拆分
横向拆分指的是单体架构支持按技术、功能、职责等角度将系统拆分为各种模块,以便于重用和团队管理。
通过在负载均衡之后同时部署多个单体系统的副本,可以达到分摊流量压力的效果,使单体架构在横向上也能够轻松实现扩展。
4 、非独立的单体
然而,单体系统的缺陷并非在于如何拆分,而在于拆分后存在隔离与自治能力的不足。
在单体架构中,所有代码运行在同一个进程空间内,任何一部分代码出现问题都可能影响全局。内存泄漏、线程爆炸、阻塞、死循环等问题难以隔离。此外,由于共享同一进程空间,无法单独停止、更新、升级某一部分代码,导致缺乏动态可维护性。
在单体系统的潜在观念中,每个部件都应尽量可靠,致力于构建一个 7 * 24 小时不间断的可靠系统。在小规模软件上,这种观念运作良好。然而,随着系统规模的增大,构建可靠系统的观念开始从追求尽量不出错转变为正视出错是必然。实际上,这正是微服务架构能够挑战并逐步取代单体架构的根本驱动力。
三、SOA 时代的探索与挑战
在软件架构的历史演进中,Service Oriented Architecture(SOA)时代标志着对分布式服务构建信息系统的广泛应用。
SOA 架构具有完善的理论和工具,被认为解决了分布式系统中的许多关键技术问题。然而,尽管具备一系列成功的理论,SOA 并没有成为一种普适的软件架构,而在实践中也面临了一些挑战。
1 、三种服务拆分架构模式
烟囱式架构(Information Silo Architecture)
信息烟囱,又称为信息孤岛,使用这种架构的系统,也被称为孤岛式信息系统或者烟囱式信息系统。
指系统完全不会跟其他相关的系统之间进行协调工作,各自使用独立的数据库和服务器。
实际中,很难找到在一家公司内完全不交互的系统。
微内核架构(Microkernel Architecture)
亦称为插件式架构(Plug-in Architecture),将不同系统共享的公共数据、服务、资源集中到一个核心系统,业务系统则以插件模块的形式存在。
微内核架构适用于产品型应用系统,支持灵活扩展和增量开发。
事件驱动架构
为了实现子系统之间的通信,通过建立事件队列管道,将系统外部的消息以事件形式发送到管道中。每个消息处理者都是独立解耦的,通过事件管道进行互动。
2 、SOA 架构时代的探索(Service Oriented Architecture,SOA)
在 SOA 时代,很多概念思想已经在微服务中找到了应用,如服务之间的松散耦合、注册、发现、治理、隔离和编排等。
SOA 针对分布式服务的困难进行了多方面的探索,包括具体的技术标准和软件设计原则。
- 更具体的探索
- 拥有领导制定技术标准的组织 Open CSA:SOA 不仅仅是一种架构风格了,而是一套软件架构的基础平台
- 具有清晰的软件设计的指导原则,比如服务的封装性、自治、松耦合、可重用、可组合、无状态等
- 明确了采用 SOAP 作为远程调用的协议,依靠 SOAP 协议族(WSDL 、 UDDI 和一大堆 WS* 的协议)来完成服务的发布、发现和治理
- 利用企业服务总线(Enterprise Service Bus,ESB)的消息通道来实现各个子系统的通信,在 ESB 的调度下不需要互相依赖就可以实现通信,既松耦合,又为实现业务流程编排(Business Process Management,BPM)提供基础
- 使用服务数据对象(Service Data Object,SDO)来访问和表示数据,使用服务组件架构(Service Component Architecture,SCA)来定义服务封装的形式和服务运行的容器
- 更系统的探索
- SOA 最根本的目标是希望总结出一套自上而下的软件研发方法论,解决研发过程中的各种问题,包括需求挖掘、业务能力分解、已有服务的编排、新功能的开发测试等
- 21 世纪最初十年,有 IBM 为其助威,盛极一时,但最终沉寂
SOA 架构虽然可以实现多个异构大型系统之间的复杂集成交互,但由于过于严格和复杂的规范定义,给架构设计带来了过多的复杂性。
SOA 并非一种具有普适性的架构风格,这在实际应用中变得明显。
此外,SOA 在 21 世纪初的十年中失去了活力,尽管提出了许多理念和思想,但并未在实践中广泛应用。这也让人们开始思考更为灵活和可行的架构模式,为接下来的演进铺平道路。