架构并不是发明出来的,而是持续演进的结果。
原始分布式时代
其实人们对于分布式系统的探索要比大型单体系统出现得更早,早期计算机的运算处理能力有限,如果需要运行稍大的软件则需要使用多台计算机共同协作完成。
当时 OSF(Open Software Foundation, 开放软件基金会)联合主流计算机厂商共同制定了分布式技术体系(Distributed Computing Environment, DCE),发明了众多非常重要的分布式概念,例如远程调用(Remote Procedure Call, RPC),分布式文件系统(Distributed File System, DFS),通用唯一标识符(Universally Unique Identifier, UUID)等。
OSF 本身的 UNIX 背景,使其对技术的研究具备浓厚的 UNIX 设计风格,有一个预设的重要原则是要使分布式环境中的服务调用、资源访问、数据存储等操作尽可能透明化、简单化,从而使开发人员不必过于关注他们访问的方法或其他资源是位于本地还是远程。
在这一方向上的尝试中碰到了重重困难,例如远程调用过程中需要面临服务发现,负载均衡,网络分区,异常处理(熔断,隔离,降级)等问题,每个问题都需要耗费大量的精力解决,使得人们开始思考是否存在其它通往大规模软件系统的道路:
- 一条是尽快提升单机的处理能力,避免分布式系统带来的种种问题
- 一条是找到更完美的分布式系统的解决方案
单体系统时代
恰逢20世纪80年代正是摩尔定律开始稳定发挥作用的黄金时期,计算机的性能以每两年增长一倍的惊人速度提升,硬件算力束缚软件规模的链条开始变得松动,依赖单台或者少量几台计算机作为服务器支撑大型软件系统的架构成为当时的主流,也意味着单体时代的到来。
单体意味着所有功能都由一个服务提供,在这个服务中所有的组件都采用同一技术平台进行构建,但单体并不意味着杂乱无章,内部依然可以根据逻辑进行分层,模块化,组件化。
单体系统的问题不在于“拆分”方面,而在拆分之后的隔离和自治能力。由于所有模块代码运行在同一进程中,如果任何一部分代码出现缺陷,过渡消耗了进程空间的资源,所造成的影响也是全局性的,例如内存泄漏,线程爆炸,阻塞,死循环等问题。同样因为所有模块代码都运行在同一进程中,也就没有办法做到单独停止,更新,升级某一部分代码。
综上所述,单体架构风格有一个潜在的要求是希望系统的每一个部件,每一处代码都尽量可靠,不出现缺陷,但当系统规模,团队规模越来越大时,交付一个完全可靠的单体系统就变得非常具有挑战性。
人们的理念也逐渐从“追求尽量不出错”到正视“出错时必然”的转变,才会出现后续的SOA, 微服务架构。
SOA 时代
为了避免大型单体系统存在的错误传播问题,开发者开始对大型单体系统进行拆分,让每个子系统都能独立地部署,运行,更新,尝试过很多种方案,这里列举三种比较有代表性的架构模式:
- 烟囱式架构,每个系统间没有任何数据共享和交互,仿佛一座信息孤岛
- 微内核架构,每个子系统被作为一个插件(插件具备强扩展性),将公共服务,数据,资源集中在一块放置在内核中,可以被所有子系统所共享,在这个架构模式下,各个子系统间仍然不可以进行通信
- 事件驱动架构,为了解决子系统间的通信问题,在各个子系统之间建立一套事件队列管道,子系统可以通过在事件队列收发消息的形式与其它子系统进行通信
当架构演化至事件驱动架构时,恰逢人们一直对分布式系统领域的探索也收获了成果,用于远程调用的 SOAP 协议诞生了,此时面向服务的架构(Service Oriented Architecture, SOA)已经具备登上软件架构舞台所需要的全部前置条件,SOA 时代到来。
SOA 不仅是一种架构风格,更是一套软件设计的基础平台:
- 明确采用 SOAP 作为远程调用协议
- 依靠 SOAP 协议族完成服务发布,发现,治理
- 利用企业服务总线(Enterprise Service Bus, ESB)的消息管道来实现各子系统间的交互,由于各子系统间的解耦性,也为后续进一步实施业务流程编排(Business Process Management, BPM)提供了基础
- 使用服务数据对象(Service Data Object,SDO)来访问和表示数据
- 使用服务组件架构(Service Component Architechture, SCA)来定义服务封装的形式和服务运行的容器等等
SOA 野心勃勃地想解决软件开发中的全部问题,但过于严格的规范定义带来过度的复杂性,使它自诞生的那一天起,就已经注定只能是少数系统阳春白雪式的精致奢侈品。
人们发现离最初 UNIX DCE 中提到简单,透明化的设计宗旨越来越远。
微服务时代
微服务的概念在 2005 年由 Peter Rodgers博士首次提到,指的是一种专注于单一职责的、与语言无关的细粒度Web服务,在很长一段时间里微服务的概念并没有掀起太大波澜,仅仅被认为是 SOA 的附属产物。
微服务真正崛起的时间是2014年,Martin Fowler与James Lewis合写的文章“Microservices:A Definition of This New Architectural Term” 将微服务概念重新引入大众视野,大众开始普遍了解到微服务。
原文链接:https://martinfowler.com/articles/microservices.html
该文中列举了微服务的九个核心的业务与技术特征:
- 围绕业务能力构建(Organized around Business Capability)
- 分散治理(Decentralized Governance)
- 通过服务来实现独立自治的组件(Componentization via Service)
- 产品化思维(Product not Project)
- 数据去中心化(Decentralized Data Management)
- 强终端弱管道(Smart Endpoint and Dumb Pipe)
- 容错性设计(Design for Failure)
- 演进式设计(Evolutionary Design)
- 基础设施自动化(Infrastructure Automation)
从以上微服务的定义和特征中,可以明显地感觉到微服务追求的是更加自由的架构风格,摒弃了几乎所有SOA里可以抛弃的约束和规定,与此同时也意味着需要重新面对那些在 SOA 中通过基础设施层面解决的问题,例如服务的注册发现、跟踪治理、负载均衡、故障隔离、认证授权、伸缩扩展、传输通信、事务处理等,此后也催生了大量的第三方开源框架用以解决分布式问题。
在获得技术选择自由的同时,也给技术架构者带来了更大的挑战。
技术架构者的第一职责就是决策权衡,有利有弊才需要决策,有取有舍才需要权衡,如果架构者本身的知识面不足以覆盖所需要决策的内容,不清楚其中利弊,恐怕将无可避免地陷入选择困难症的境遇之中。
后微服务时代
分布式架构所遇到的种种问题,如注册发现、跟踪治理、负载均衡、传输通信等,SOA 期望从软件基础设施层一揽子解决,而微服务则更强调由应用自治的方式解决这些问题,它们都是从软件层解决问题,那是否可以从硬件层解决这些分布式问题呢?
- 某个系统需要伸缩扩容,通常会购买新的服务器,部署若干副本实例来分担压力
- 如果某个系统需要解决负载均衡问题,通常会布置负载均衡器,选择恰当的均衡算法来分流
- 如果需要解决传输安全问题,通常会布置TLS传输链路,配置好CA证书以保证通信不被窃听篡改
- 如果需要解决服务发现问题,通常会设置DNS服务器,让服务访问依赖稳定的记录名而不是易变的IP地址
随着计算机科学多年的发展,这些问题大多有了专职化的硬件基础设施去解决,而在微服务时代,人们之所以选择在软件的代码层面而不是硬件的基础设施层面去解决这些分布式问题,很大程度上是因为由硬件构成的基础设施跟不上由软件构成的应用服务的灵活性的无奈之举。
但当虚拟化,容器化技术领域(Docker, Kubernetes, Service Mesh)有了重大突破,大大提升了“硬件”基础设施的伸缩扩展能力,也让上述假想有了实现的可能性。一旦虚拟化的硬件能够跟上软件的灵活性,那些与业务无关的技术性问题便有可能从软件层面剥离,悄无声息地在硬件基础设施之内解决,让软件得以只专注业务,真正围绕业务能力构建团队与产品。
这个时代也被称为云原生时代。
无服务时代
如果单台服务器的性能可以是无限的,那架构演进的结果肯定会与今天有很大差别,分布式也好,容器化也好,微服务也好,恐怕都未必会如期出现,最起码一定不是今天这个样子。绝对意义上的无限性能必然是不存在的,但在云计算落地已有十余年的今天,相对意义的无限性能已经成为现实。
在工业界,2012年Iron.io公司率先提出了“无服务”(Serverless,应该翻译为“无服务器”才合适,但现在称“无服务”已形成习惯了)的概念;2014年,亚马逊发布了名为Lambda的商业化无服务计算平台,并在后续的几年里逐步得到开发者认可,发展为目前世界上最大的无服务运行平台;到了2018年,中国的阿里云、腾讯云等厂商也开始跟进,发布了旗下的无服务产品,“无服务”成为近期技术圈里的“新网红”之一。
无服务主要包括两块内容:后端设施(Backend)和函数(Function)。
- 后端设施是指数据库、消息队列、日志、存储等这类用于支撑业务逻辑运行,但本身无业务含义的技术组件,这些后端设施都运行在云中,在无服务中将它们称为“后端即服务”(Backend as a Service,BaaS)。
- 函数是指业务逻辑代码,这里函数的概念与粒度都已经很接近于程序编码角度的函数了,其区别是无服务中的函数运行在云端,不必考虑算力问题,也不必考虑容量规划(从技术角度可以不考虑,从计费的角度还是要掂量一下的),在无服务中将其称为“函数即服务”(Function as aService,FaaS)。
无服务的愿景是让开发者只需要纯粹地关注业务:不需要考虑技术组件,后端的技术组件是现成的,可以直接取用,没有采购、版权和选型的烦恼;不需要考虑如何部署,部署过程完全托管到云端,由云端自动完成;不需要考虑算力,有整个数据中心支撑,算力可以认为是无限的;不需要操心运维,维护系统持续平稳运行是云计算服务商的责任而不再是开发者的责任。
但无服务架构对于前面提到的多种架构并不是取而代之的角色,无服务的机制本身决定了它适用的场景并没有特别广阔。适用于不需要交互的离线大规模计算,多数Web资讯类网站、小程序、公共API服务、移动应用服务端等都契合于无服务架构所擅长的短链接、无状态、适合事件驱动的交互形式。
但对于那些信息管理系统、网络游戏等应用,或者说对于具有业务逻辑复杂、依赖服务端状态、响应速度要求较高、需要长链接等特征的应用,至少目前是相对不那么适合的。
相关引用: