《凤凰架构》读书笔记

按照作者分的章节名称来区分重点,进行总结和提炼。

什么是凤凰架构

1、提出重编程能力还是重架构的问题

问:做一个高质量的软件,应该把精力集中在提升其中每一个人员、过程、产出物的能力和质量上,还是该把更多精力放在整体流程和架构上?

答:这两者都重要。前者重术,后者重道;前者更多与编码能力相关,后者更多与软件架构相关;前者主要由开发者个体水平决定,后者主要由技术决策者水平决定。

2、提出构建一个大规模但依然可靠的软件系统是否是可行的

通过冯诺依曼研发自复制自动机的例子举例我们一直是在用不可靠部件构造可靠的系统。比如我们开发的每个环节都是有可能出错的,但最终设计出的软件必然是不可靠的,但事实并非如此。用冯诺依曼的自动机这个例子来讲就是说这些零部件可能会出错,某个具体的零部件可能会崩溃消亡,但在存续生命的微生态系统中一定会有其后代的出现,重新代替该零部件的作用,以维持系统的整体稳定。在这个微生态里,每一个部件都可以看作一只不死鸟,它会老去然后又能涅槃重生。

3、强调架构演变最终都是为了使我们的服务更好地死去和重生

软件架构风格演变顺序:大型机 -> 原始分布式 -> 大型单体 -> 面向服务 -> 微服务 -> 服务网格 -> 无服务

技术架构上呈现出从大到小的发展趋势。作者提出了:相比于易于伸缩拓展应对更高的性能等新架构的优点,架构演变最重要的驱动力始终都是为了方便某个服务能够顺利地“死去”与“重生”而设计的,个体服务的生死更迭,是关系到整个系统能否可靠续存的关键因素。

服务架构演进史

原始分布式时代

UNIX 的设计原则提出了:保持接口与实现的简单性,比系统的任何其他属性,包括准确性、一致性和完整性,都来得更加重要。

负责制定 UNIX 系统技术标准的开放软件基金会(也叫OSF) 邀请了各大计算机厂商一起参与共同制订了名为“分布式运算环境”(也叫DCE)的分布式技术体系。DCE 包含一套相对完整的分布式服务组件规范与参考实现。

OSF 严格遵循 UNIX 设计风格,有一个预设的重要原则是使分布式环境中的服务调用、资源访问、数据存储等操作尽可能透明化、简单化,使开发人员不必过于关注他们访问的方法或其他资源是位于本地还是远程。这样的主旨非常符合一贯的UNIX 设计哲学。但是实现的目标背后包含着当时根本不可能完美解决的技术困难。 因为DCE一旦要考虑性能上的差异就不太行了。为了让程序在运行效率上可被用户接受,开发者只能在方法本身运行时间很长,可以相对忽略远程调用成本时的情况下才能考虑分布式,如果方法本身运行时间不够长,就要人为用各种方式刻意地构造出这样的场景,譬如将几个原本毫无关系的方法打包到一个方法体内,一块进行远程调用。这种构造长耗时方法本身就与期望用分布式来突破硬件算力限制、提升性能的初衷相互矛盾。并且此时的开发人员实际上仍然必须每时每刻都意识到自己是在编写分布式程序,不可轻易踏过本地与远程的界限。这和简单透明的原则相违背。

通过这个原始分布式开发得出了一个教训:某个功能能够进行分布式,并不意味着它就应该进行分布式,强行追求透明的分布式操作,只会自寻苦果。

基于当时的情况摆在计算机科学面前有两条通往更大规模软件系统的道路,一条是尽快提升单机的处理能力,以避免分布式带来的种种问题;另一条路是找到更完美的解决如何构筑分布式系统的解决方案

单体系统时代

单体架构中“单体”只是表明系统中主要的过程调用都是进程内调用,不会发生进程间通信。

单体架构的系统又叫巨石系统。单体架构本身具有简单的特性,简单到在相当长的时间内,大家都已经习惯了软件架构就应该是单体这种样子,所以并没有多少人将“单体”视作一种架构来看待。

和很多书中的内容不同的是,单体其实并不是一个“反派角色”,单体并没有大家口中的那么不堪。实际上,它时运行效率最高的一种架构风格。基于软件的性能需求超过了单机,软件开发人员规模扩大这样的情况,才体现了单体系统的不足之处。

单体架构由于所有代码都运行在同一个进程空间之内,所有模块、方法的调用都无须考虑网络分区、对象复制这些麻烦的事和性能损失。一方面获得了进程内调用的简单、高效等好处的同时,另一方面也意味着如果任何一部分代码出现了缺陷,过度消耗了进程空间内的资源,所造成的影响也是全局性的、难以隔离的。比如内存泄漏、线程爆炸、阻塞、死循环等问题,都会影响整个程序,而不仅仅是影响某一个功能、模块本身的正常运作。

同样的,由于所有代码都共享着同一个进程空间,不能隔离,也就无法做到单独停止、更新、升级某一部分代码,所以从可维护性来说,单体系统也是不占优势的。程序升级、修改缺陷往往需要制定专门的停机更新计划,做灰度发布、A/B 测试也相对更复杂。

除了以上问题是单体架构的缺陷外,作者提出,最重要的还是:单体系统很难兼容“Phoenix”的特性

单体架构这种风格潜在的观念是希望系统的每一个部件,每一处代码都尽量可靠,靠不出或少出缺陷来构建可靠系统。但是单体靠高质量来保证高可靠性的思路,在小规模软件上还能运作良好,但系统规模越大,交付一个可靠的单体系统就变得越来越具有挑战性。

为了允许程序出错,为了获得隔离、自治的能力,为了可以技术异构等目标,是继为了性能与算力之后,让程序再次选择分布式的理由。在单体架构后,有一段时间是在尝试将一个大的单体系统拆分为若干个更小的、不运行在同一个进程的独立服务,这些服务拆分方法后来导致了面向服务架构(Service-Oriented Architecture)的一段兴盛期,这就是SOA 时代。

SOA时代

SOA是一次具体地、系统性地成功解决分布式服务主要问题的架构模式。

三种有代表性的SOA

  • 烟囱式架构

信息烟囱又叫信息孤岛。使用这种架构的系统也被称为孤岛式信息系统或者烟囱式信息系统。它指的是一种完全不与其他相关信息系统进行互操作或者协调工作的设计模式。

这样的系统其实并没有什么“架构设计”可言。这样完全不进行交互的模式不符合真实业务情况。

  • 微内核架构

微内核架构也被称为插件式架构。微内核将主数据,连同其他可能被各子系统使用到的公共服务、数据、资源集中到一块,成为一个被所有业务系统共同依赖的核心(Kernel,也称为 Core System),具体的业务系统以插件模块(Plug-in Modules)的形式存在,这样也可提供可扩展的、灵活的、天然隔离的功能特性。

这种模式适合桌面应用程序和Web 应用程序。对于平台型应用来说,经常会加入新的功能,就很像时不时加一个新的插件模块进来所以微内核架构比较适合。微内核架构也可以嵌入到其他的架构模式之中,通过插件的方式来提供新功能的定制开发能。

微内核架构也有它的局限和使用前提,架构中这些插件可以访问内核中一些公共的资源,但不会直接交互。但是无论是企业信息系统还是互联网应用必须既能拆分出独立的系统,也能让拆分后的子系统之间顺畅地互相调用通信。

image-20210804212830472

事件驱动架构

为了能让子系统互相通信,事件驱动架构的方案是在子系统之间建立一套事件队列管道,来自系统外部的消息将以事件的形式发送至管道中,各个子系统从管道里获取能够处理的事件消息,可以自己发布一些新的事件到管道队列中去,如此,每一个消息的处理者都是独立的,高度解耦的,但又能与其他处理者通过事件管道进行互动。

image-20210804212849753

演化至事件驱动架构时远程服务调用迎来了 SOAP 协议的诞生

微服务时代

微服务是一种通过多个小型服务组合来构建单个应用的架构风格,这些服务围绕业务能力而非特定的技术标准来构建。各个服务可以采用不同的编程语言,不同的数据存储技术,运行在不同的进程之中。服务采取轻量级的通信机制和自动化的部署机制实现通信与运维。

“微服务”这个技术名词是由 Peter Rodgers 博士在 2005 年度的云计算博览会提出的。“Micro-Web-Service”,指的是一种专注于单一职责的、语言无关的、细粒度 Web 服务。最初的微服务可以说是 SOA 发展时催生的产物。随着时间的推进,技术的发展,微服务已经不再是维基百科定义的那样,“仅仅只是一种 SOA 的变种形式”了。

微服务真正的崛起是在 2014 年,Martin Fowler 与 James Lewis 合写的文章《Microservices: A Definition of This New Architectural Term》中 给出了现代微服务的概念: “微服务是一种通过多个小型服务组合来构建单个应用的架构风格,这些服务围绕业务能力而非特定的技术标准来构建。各个服务可以采用不同的编程语言,不同的数据存储技术,运行在不同的进程之中。服务采取轻量级的通信机制和自动化的部署机制实现通信与运维。”

文中列举了微服务的九个核心的业务与技术特征:

  • 围绕业务能力构建
  • 分散治理
  • 通过服务来实现独立自治的组件
  • 产品化思维
  • 数据去中心化
  • 强终端弱管道
  • 容错性设计
  • 演进式设计
  • 基础设施自动化

《Microservices》文中除了定义微服务是什么,还专门申明了微服务不是什么——微服务不是 SOA 的变体或衍生品,应该明确地与 SOA 划清了界线,不再贴上任何 SOA 的标签。

微服务追求的是更加自由的架构风格,摒弃了几乎所有 SOA 里可以抛弃的约束和规定,提倡以“实践标准”代替“规范标准”。没有了统一的规范和约束,服务的注册发现、跟踪治理、负载均衡、故障隔离、认证授权、伸缩扩展、传输通信、事务处理,等等这些问题,在微服务中不再会有统一的解决方案,即使只讨论 Java 范围内会使用到的微服务,光一个服务间远程调用问题,可以列入解决方案的候选清单的就有:RMI(Sun/Oracle)、Thrift(Facebook)、Dubbo(阿里巴巴)、gRPC(Google)、Motan2(新浪)、Finagle(Twitter)、brpc(百度)、Arvo(Hadoop)、JSON-RPC、REST,等等;光一个服务发现问题,可以选择的就有:Eureka(Netflix)、Consul(HashiCorp)、Nacos(阿里巴巴)、ZooKeeper(Apache)、Etcd(CoreOS)、CoreDNS(CNCF),等等。其他领域的情况也是与此类似,总之,完全是八仙过海,各显神通的局面。

作为一个普通的服务开发者,“螺丝钉”式的程序员,微服务架构是友善的。可是,微服务对架构者是满满的恶意,因为对架构能力要求已提升到史无前例的程度

后微服务时代

定义:从软件层面独力应对微服务架构问题,发展到软、硬一体,合力应对架构问题的时代,此即为“后微服务时代”。

当虚拟化的基础设施从单个服务的容器扩展至由多个容器构成的服务集群、通信网络和存储设施时,软件与硬件的界限便已经模糊。一旦虚拟化的硬件能够跟上软件的灵活性,那些与业务无关的技术性问题便有可能从软件层面剥离,悄无声息地解决于硬件基础设施之内,让软件得以只专注业务,真正“围绕业务能力构建”团队与产品。

Kubernetes 成为容器战争胜利者标志着后微服务时代的开端,但 Kubernetes 仍然没有能够完美解决全部的分布式问题——“不完美”的意思是,仅从功能上看,单纯的 Kubernetes 反而不如之前的 Spring Cloud 方案。这是因为有一些问题处于应用系统与基础设施的边缘,使得完全在基础设施层面中确实很难精细化地处理。

举个例子,微服务 A 调用了微服务 B 的两个服务,称为 B1和 B2,假设 B1表现正常但 B2出现了持续的 500 错,那在达到一定阈值之后就应该对 B2进行熔断,以避免产生雪崩效应。如果仅在基础设施层面来处理,这会遇到一个两难问题,切断 A 到 B 的网络通路则会影响到 B1的正常调用,不切断的话则持续受 B2的错误影响。

image-20210804212912692

以上问题在通过 Spring Cloud 这类应用代码实现的微服务是可以处理和解决的,只受限于开发人员的想象力与技术能力,但基础设施是针对整个容器来管理的,粒度相对粗旷,只能到容器层面,对单个远程服务就很难有效管控。类似的情况不仅仅在断路器上出现,服务的监控、认证、授权、安全、负载均衡等都有可能面临细化管理的需求,譬如服务调用时的负载均衡,往往需要根据流量特征,调整负载均衡的层次、算法,等等,而 DNS 尽管能实现一定程度的负载均衡,但通常并不能满足这些额外的需求。

为了解决这一类问题,虚拟化的基础设施很快完成了第二次进化,引入了“服务网格”(Service Mesh)的“边车代理模式”(Sidecar Proxy),所谓的“边车”是由系统自动在服务容器(通常是指 Kubernetes 的 Pod)中注入一个通信代理服务器,以类似网络安全里中间人攻击的方式进行流量劫持,在应用毫无感知的情况下,悄然接管应用所有对外通信。这个代理除了实现正常的服务间通信外(称为数据平面通信),还接收来自控制器的指令(称为控制平面通信),根据控制平面中的配置,对数据平面通信的内容进行分析处理,以实现熔断、认证、度量、监控、负载均衡等各种附加功能。这样便实现了既不需要在应用层面加入额外的处理代码,也提供了几乎不亚于程序代码的精细管理能力。

很难从概念上判定清楚一个与应用系统运行于同一资源容器之内的代理服务到底应该算软件还是算基础设施,但它对应用是透明的,不需要改动任何软件代码就可以实现服务治理,这便足够了。服务网格在 2018 年才火起来,今天它仍然是个新潮的概念,仍然未完全成熟,甚至连 Kubernetes 也还算是个新生事物。但作者提出,未来 Kubernetes 将会成为服务器端标准的运行环境,如同现在 Linux 系统;服务网格将会成为微服务之间通信交互的主流模式,把“选择什么通信协议”、“怎样调度流量”、“如何认证授权”之类的技术问题隔离于程序代码之外,取代今天 Spring Cloud 全家桶中大部分组件的功能,微服务只需要考虑业务本身的逻辑,这才是最理想的解决方案。

无服务时代

如果说微服务架构是分布式系统这条路的极致,那无服务架构,也许就是“不分布式”的云端系统这条路的起点。

虽然发展到了微服务架构解决了单台机器的性能无法满足系统的运行需要的问题,但是获得更好性能的需求在架构设计中依然占很大的比重。对软件研发而言,不去做分布式无疑才是最简单的,如果单台服务器的性能可以是无限的,那架构演进一定不是像今天这个样子。

绝对意义上的无限性能必然是不存在的,但在云计算落地已有十年时间的今日,相对意义的无限性能已经成为了现实。2012 年,Iron.io 公司率先提出了“无服务”的概念,2014 年开始,亚马逊发布了名为 Lambda 的商业化无服务应用,并在后续的几年里逐步得到开发者认可,发展成目前世界上最大的无服务的运行平台;到了 2018 年,中国的阿里云、腾讯云等厂商也开始跟进,发布了旗下的无服务的产品,“无服务”已成了近期技术圈里的“新网红”之一。

无服务现在还没有一个特别权威的“官方”定义,但它的概念并没有前面各种架构那么复杂,本来无服务也是以“简单”为主要卖点的,它只涉及两块内容:后端设施和函数。

  • 后端设施是指数据库、消息队列、日志、存储,等等这一类用于支撑业务逻辑运行,但本身无业务含义的技术组件,这些后端设施都运行在云中,无服务中称其为“后端即服务”(Backend as a Service,BaaS)。
  • 函数是指业务逻辑代码,这里函数的概念与粒度,都已经很接近于程序编码角度的函数了,其区别是无服务中的函数运行在云端,不必考虑算力问题,不必考虑容量规划,无服务中称其为“函数即服务”(Function as a Service,FaaS)。

无服务的愿景是让开发者只需要纯粹地关注业务,不需要考虑技术组件,后端的技术组件是现成的,可以直接取用,没有采购、版权和选型的烦恼;不需要考虑如何部署,部署过程完全是托管到云端的,工作由云端自动完成;不需要考虑算力,有整个数据中心支撑,算力可以认为是无限的;也不需要操心运维,维护系统持续平稳运行是云计算服务商的责任而不再是开发者的责任。

作者认为无服务很难成为一种普适性的架构模式,因为无服务不适配于所有的应用。对于那些信息管理系统、网络游戏等应用,所有具有业务逻辑复杂,依赖服务端状态,响应速度要求较高,需要长链接等这些特征的应用,至少目前是相对并不适合的。因为无服务天生“无限算力”的假设决定了它必须要按使用量计费以控制消耗算力的规模,所以函数不会一直以活动状态常驻服务器,请求到了才会开始运行,这导致了函数不便依赖服务端状态,也导致了函数会有冷启动时间,响应的性能不可能太好

作者认为软件开发的未来不会只存在某一种“最先进的”架构风格,多种具针对性的架构风格同时并存,是软件产业更有生命力的形态。笔者同样相信软件开发的未来,多种架构风格将会融合互补,“分布式”与“不分布式”的边界将逐渐模糊,两条路线在云端的数据中心中交汇。

架构师的视角

访问远程服务

远程服务调用

进程间通信

RPC 出现的最初目的,就是为了让计算机能够跟调用本地方法一样去调用远程方法。

进程间通信的方式有

  • 管道,又叫具名管道

管道类似于两个进程间的桥梁,可通过管道在进程间传递少量的字符流或字节流。普通管道只用于有亲缘关系进程(由一个进程启动的另外一个进程)间的通信,具名管道摆脱了普通管道没有名字的限制,除具有管道所有的功能外,它还允许无亲缘关系进程间的通信。管道典型的应用就是命令行中的|操作符,比如:

ps -ef | grep java

ps与grep都有独立的进程,以上命令就通过管道操作符|将ps命令的标准输出连接到grep命令的标准输入上。

  • 信号

信号用于通知目标进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程自身。信号的典型应用是kill命令,比如:

kill -9 pid

以上就是由 Shell 进程向指定 PID 的进程发送 SIGKILL 信号。

  • 信号量

信号量用于两个进程之间同步协作手段,它相当于操作系统提供的一个特殊变量,程序可以在上面进行wait()和notify()操作。

  • 消息队列

以上三种方式只适合传递传递少量信息,消息队列用于进程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值