第1章 服务架构演进史
1.1 原始分布式时代
调用远程方法(Remote Method Invocation,RMI)
调用远程方法虽然与调用本地方法只有两字之差,但复杂度却不可同日而语。
且不说远程方法不能再依靠本地方法那些以内联为代表的传统编译优化来提升速度,光是“远程”二字带来的网络新问题,都值得反复思考:
- 远程的服务在哪里(服务发现)
- 有多少个机器可以提供服务(负载均衡)
- 网络出现分区、超时或者服务出错了怎么办(熔断、隔离、降级)
- 方法的参数与返回的结果如何表示(序列化协议)
- 信息如何传输(传输协议)
- 服务权限如何管理(认证、授权)
- 如何保证通信安全(网络安全层)
- 如何令调用不同机器的服务返回相同的结果(分布式数据一致性)
通过大量学者对分布式运算环节(Distributed Computing Environment,DCE)的研究,得出了一个价值千金的教训:
某个功能是否能够进行分布式,并不意味着它就应该进行分布式,强行追求透明的分布式操作,只会自寻苦果。
1.2 单体系统时代
单体架构也是大部分软件开发者都学习、实践过的一种软件架构,在许多地方也将这种架构成为“巨石架构”(Monolithic Application)。
对于小型系统,单台机器就足以支撑其良好运行的系统,不仅易于开发、测试、部署,且由于系统中各个功能、模块、方法的调用都是进程内调用,不会发生进程间通信(Inter-Process Communication,IPC),因此连运行效率也是最高的。
但是单体应用也存在着比较多的缺陷:
- 牵一发而动全身。所有代码都在同一个进程内,当其中任何一部分代码出现缺陷,过度消耗了进程空间内的资源,所造成的影响也是全局性的、难以隔离的。(内存泄漏、线程爆炸、阻塞、死循环等),这都会影响整个程序,而不仅仅是影响某一个功能、模块本身的运行。
- 隔离性差。所有代码共享一个进程,不能隔离,也就无法做到单独停止、更新、升级某一部分代码,当需要升级一部分功能时,往往需要制定专门的体积更新计划,对于可维护性而言,单体系统也不占优势。
- 技术异构性差。每个模块的代码通常都需要使用一样的程序语言,乃至一样的编程框架去开发。
1.3 SOA时代
面向服务架构(SOA)是一个组件模型,它将应用程序的不同功能单元(称为服务)进行拆分,并通过这些服务之间定义良好的接口和协议联系起来。
这里主要介绍三种有代表性的架构模式。
烟囱式架构
这种架构方式也称为信息孤岛,即将一个公司中两个完全没有交互的部门分拆到不同的楼里办公,让他们使用独立的数据库和服务器。但是这里有个致命的问题,企业中真的存在完全没有交互的部门吗,这种“老死不相往来”的系统,显然不可能是企业所希望见到的。
微内核架构
既然在烟囱架构中,没有业务往来关系的系统也可能需要共享人员、组织、权限等一些公共的主数据,那不妨将这些主数据,连同其他可能被各个子系统用到的公共服务、数据、资源集中到一块,组成一个被所有业务系统共同依赖的核心,具体的业务系统以插件模式的形式存在,这样就可提供可扩展的、灵活的、天然隔离的功能特性,即微内核架构。
不过,微内核架构也有局限性,它假设系统中各个插件模块之间互不认识,且不可预知系统将安装哪些模块,因此这些插件可以访问内核中一些公共的资源,但不会直接交互。
事件驱动架构
为了让子系统互相通信,一种可行的方案是在子系统之间建立一套事件队列管道(Event Queue),来自系统外部的消息将以事件的形式发送至管道中,各个子系统可以从管道里获取自己感兴趣、能够处理的事件消息,也可以为世间新增或者修改其中的附加信息,甚至可以自己发布一些新的事件到管道队列中去。
1.4 微服务时代
微服务是一种软件开发技术,是SOA的一种变体。
微服务是一种通过小型服务组合来构建单个应用的架构风格,这些服务围绕业务能力而非特定的技术标准来构建。各个服务可以采用不同的编程语言、不同的数据存储技术,运行在不同的进程之中。服务采取轻量级的通信机制和自动化的部署机制来实现通信与运维。下面列举了微服务的九个核心业务与技术特征。
- 围绕业务能力结构。 有怎样结构、规模、能力的团队,就会产生对应结构、规模、能力的产品。
- 分散治理。 服务对应的开发团队有直接对服务运行质量负责的责任,也有不受外界干预地掌控服务各个方面的权力,譬如选择与其他服务异构的技术来实现自己的服务。
- 通过服务来实现自治的组件。 服务是进程外的组件,通过远程调用来提供功能。
- 产品化思维。 避免把软件研发视作要去完成某种功能,而是视作一种持续改进、提升的过程。
- 数据去中心化。 微服务明确提倡数据应该按领域分散管理、更新、维护、存储。
- 强终端弱管道。 服务需要额外通信能力,就应该在服务自己的EndPoint上解决,而不是在通信管道上一揽子处理。
- 容错性设计。 不再虚幻地追求服务永久稳定,而是接受服务总会出错的现实,要求在微服务设计中,能够有自动的机制对其以来的服务进行快速故障检测。
- 演进式设计。 容错性设计承认服务会出错,演进式设计则承认服务会被报废淘汰。
- 基础设施自动化。 基础设施自动化,如CI/CD的长足发展,显著减少了构建、发布、运维工作的复杂性。
1.5 后微服务时代
微服务的流行,微服务架构的缺点也慢慢的暴露了出来,比如:
- 侵入式太强。 需要在业务代码里面加入非业务代码的逻辑(如限流、降级等)
- 多语言支持。 需要维护不同语言和非业务代码的成本。
- 学习框架成本高。 组件较多,需要学习的成本比较高。
服务网格(Service Mesh)将“选择什么通信协议” “怎样调度流量” “如何认证授权”之类的技术问题隔离于程序代码之外。使得微服务只需要考虑业务本身的逻辑,这也是最理想的智能终端解决方案。
1.6 无服务时代
人们最开始研究分布式框架,是因为单台机器的性能无法满足系统的运行需求,尽管在后来架构演进过程中,容错能力、技术异构、职责划分等各方面因素都称为架构需要考虑的问题,但获得更好的性能在架构设计需求中依然占很大的比重。对软件研发而言,不去做分布式无疑是最简单的,如果单台服务器的性能可以是无限的,那架构演进的结果肯定会与今天有很大差别。
可以将无服务架构类比于软件开发从汇编语言踏进高级语言的发展过程。无服务主要设计两块内容,后端设备和函数。
- 后端设备。 是指数据库、消息队列、日志、存储等这类用于支撑业务逻辑运行,但本身无业务含义的技术组建。
- 函数。 业务逻辑代码,无服务的函数运行在云端不必考虑算力,也不必考虑容量规划,再无服务中将其称为“函数即服务”。