周志明论架构之道:后微服务时代与无服务时代

后微服务时代(Cloud Native)


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


上节提到的分布式架构中出现的问题,如注册发现、跟踪治理、负载均衡、传输通信等,其实在 SOA 时代甚至可以说从原始分布式时代起就已经存在了,只要是分布式架构的系统,就无法完全避免,但我们不妨换个思路来想一下,这些问题一定要由软件系统自己来解决吗?


如果不局限于采用软件的方式,这些问题几乎都有对应的硬件解决方案。譬如,某个系统需要伸缩扩容,通常会购买新的服务器,部署若干副本实例来分担压力;如果某个系统需要解决负载均衡问题,通常会布置负载均衡器,选择恰当的均衡算法来分流;如果需要解决传输安全问题,通常会布置 TLS 传输链路,配置好 CA 证书以保证通信不被窃听篡改;如果需要解决服务发现问题,通常会设置 DNS 服务器,让服务访问依赖稳定的记录名而不是易变的 IP 地址,等等。经过计算机科学多年的发展,这些问题大多有了专职化的基础设施去解决,而之所以微服务时代,人们选择在软件的代码层面而不是硬件的基础设施层面去解决这些分布式问题,很大程度上是因为由硬件构成的基础设施,跟不上由软件构成的应用服务的灵活性的无奈之举。


软件可以只使用键盘命令就能拆分出不同的服务,只通过拷贝、启动就能够伸缩扩容服务,硬件难道就不可以通过敲键盘就变出相应的应用服务器、负载均衡器、DNS 服务器、网络链路这些设施吗?


行文至此,估计大家已经听出下面要说的是虚拟化技术和容器化技术了。微服务时代所取得的成就,本身就离不开以 Docker 为代表的早期容器化技术的巨大贡献。在此之前,笔者从来没有提起过“容器”二字,这并不是刻意冷落,而是早期的容器只被简单地视为一种可快速启动的服务运行环境,目的是方便程序的分发部署,这个阶段针对单个应用进行封装的容器并未真正参与到分布式问题的解决之中。尽管 2014 年微服务开始崛起的时候,Docker Swarm(2013 年)和 Apache Mesos(2012 年)就已经存在,更早之前也出现了软件定义网络(Software-Defined Networking,SDN)、软件定义存储(Software-Defined Storage,SDS)等技术,但是,被业界广泛认可、普遍采用的通过虚拟化基础设施去解决分布式架构问题的开端,应该要从 2017 年 Kubernetes 赢得容器战争的胜利开始算起。


2017 年是容器生态发展历史中具有里程碑意义的一年。在这一年,长期作为 Docker 竞争对手的RKT 容器一派的领导者 CoreOS 宣布放弃自己的容器管理系统 Fleet,未来将会把所有容器管理的功能移至 Kubernetes 之上去实现。在这一年,容器管理领域的独角兽 Rancher Labs 宣布放弃其内置了数年的容器管理系统 Cattle,提出了“All-in-Kubernetes”战略,把 1.x 版本时就能够支持多种容器编排系统的管理工具 Rancher,从 2.0 版本开始“反向升级”为完全绑定于 Kubernetes 这单一种系统。在这一年,Kubernetes 的主要竞争者 Apache Mesos 在 9 月正式宣布了“Kubernetes on Mesos”集成计划,由竞争关系转为对 Kubernetes 提供支持,使其能够与 Mesos 的其他一级框架(如HDFSSpark 和Chronos等)进行集群资源动态共享、分配与隔离。在这一年,Kubernetes 的最大竞争者 Docker Swarm 的母公司 Docker,终于在 10 月*宣布 Docker 要同时支持 Swarm 与 Kubernetes 两套容器管理系统,也即在事实上承认了 Kubernetes 的统治地位。


这场已经持续了三、四年时间,以 Docker Swarm、Apache Mesos 与 Kubernetes 为主要竞争者的“容器编排战争”终于有了明确的结果,Kubernetes 登基加冕是容器发展中一个时代的终章,也将是软件架构发展下一个纪元的开端。笔者在表 1-1 列出了在同一个分布式服务的问题在传统 Spring Cloud 中提供的应用层面的解决方案与在 Kubernetes 中提供的基础设施层面的解决方案,尽管因为各自出发点不同,解决问题的方法和效果都有所差异,但这无疑是提供了一条全新的、前途更加广阔的解题思路。


表 1-1 传统 Spring Cloud 与 Kubernetes 提供的解决方案对比


Kubernetes Spring Cloud
弹性伸缩 Autoscaling N/A
服务发现 KubeDNS / CoreDNS Spring Cloud Eureka
配置中心 ConfigMap / Secret Spring Cloud Config
服务网关 Ingress Controller Spring Cloud Zuul
负载均衡 Load Balancer Spring Cloud Ribbon
服务安全 RBAC API Spring Cloud Security
跟踪监控 Metrics API / Dashboard Spring Cloud Turbine
降级熔断 N/A Spring Cloud Hystrix


“前途广阔”不仅仅是一句恭维赞赏的客气话,当虚拟化的基础设施从单个服务的容器扩展至由多个容器构成的服务集群、通信网络和存储设施时,软件与硬件的界限便已经模糊。一旦虚拟化的硬件能够跟上软件的灵活性,那些与业务无关的技术性问题便有可能从软件层面剥离,悄无声息地解决于硬件基础设施之内,让软件得以只专注业务,真正“围绕业务能力构建”团队与产品。如此,DCE 中未能实现的“透明的分布式应用”成为可能,Martin Flower 设想的“凤凰服务器“成为可能,Chad Fowler 提出的“不可变基础设施”也成为可能,从软件层面独力应对分布式架构所带来的各种问题,发展到应用代码与基础设施软、硬一体,合力应对架构问题的时代,现在常被媒体冠以“云原生”这个颇为抽象的名字加以宣传。云原生时代与此前微服务时代中追求的目标并没有本质改变,在服务架构演进的历史进程中,笔者更愿意称其为“后微服务时代”。


Kubernetes 成为容器战争胜利者标志着后微服务时代的开端,但 Kubernetes 仍然没有能够完美解决全部的分布式问题——“不完美”的意思是,仅从功能上看,单纯的 Kubernetes 反而不如之前的 Spring Cloud 方案。这是因为有一些问题处于应用系统与基础设施的边缘,使得完全在基础设施层面中确实很难精细化地处理。举个例子,微服务 A 调用了微服务 B 的两个服务,称为 B1和 B2,假设 B1表现正常但 B2出现了持续的 500 错,那在达到一定阈值之后就应该对 B2进行熔断,以避免产生雪崩效应。如果仅在基础设施层面来处理,这会遇到一个两难问题,切断 A 到 B 的网络通路则会影响到 B1的正常调用,不切断的话则持续受 B2的错误影响。


周志明论架构之道:后微服务时代与无服务时代


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


为了解决这一类问题,虚拟化的基础设施很快完成了第二次进化,引入了今天被称为“服务网格”(Service Mesh)的“边车代理模式”(Sidecar Proxy),如图 1-5 所示。所谓的“边车”是一种带垮斗的三轮摩托,我小时候还算常见,现在基本就只在影视剧中才会看到了。这个场景里指的具体含义是由系统自动在服务容器(通常是指 Kubernetes 的 Pod)中注入一个通信代理服务器,相当于那个挎斗,以类似网络安全里中间人攻击的方式进行流量劫持,在应用毫无感知的情况下,悄然接管应用所有对外通信。这个代理除了实现正常的服务间通信外(称为数据平面通信),还接收来自控制器的指令(称为控制平面通信),根据控制平面中的配置,对数据平面通信的内容进行分析处理,以实现熔断、认证、度量、监控、负载均衡等各种附加功能。这样便实现了既不需要在应用层面加入额外的处理代码,也提供了几乎不亚于程序代码的精细管理能力。


周志明论架构之道:后微服务时代与无服务时代


图来自 Istio 的配置文档,图中的 Mixer 在 Istio 1.5 之后已经取消,这里仅作示意

很难从概念上判定清楚一个与应用系统运行于同一资源容器之内的代理服务到底应该算软件还是算基础设施,但它对应用是透明的,不需要改动任何软件代码就可以实现服务治理,这便足够了。


服务网格在 2018 年才火起来,今天它仍然是个新潮的概念,仍然未完全成熟,甚至连 Kubernetes 也还算是个新生事物。但笔者相信,未来 Kubernetes 将会成为服务器端标准的运行环境,如同现在 Linux 系统;服务网格将会成为微服务之间通信交互的主流模式,把“选择什么通信协议”、“怎样调度流量”、“如何认证授权”之类的技术问题隔离于程序代码之外,取代今天 Spring Cloud 全家桶中大部分组件的功能,微服务只需要考虑业务本身的逻辑,这才是最理想的Smart Endpoints解决方案。


上帝的归上帝,凯撒的归凯撒,业务与技术完全分离,远程与本地完全透明,也许这就是最好的时代了吧?


无服务架构(Serverless)


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


人们研究分布式架构,最初是由于单台机器的性能无法满足系统的运行需要,尽管在后来架构演进过程中,容错能力、技术异构、职责划分等各方面因素都成为架构需要考虑的问题,但其中获得更好性能的需求在架构设计中依然占很大的比重。对软件研发而言,不去做分布式无疑才是最简单的,如果单台服务器的性能可以是无限的,那架构演进的结果肯定会与今天有很大的差别,分布式也好,容器化也好,微服务也好,恐怕都未必会如期出现,最起码不必一定是像今天这个样子。


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


在学术界,2009 年,云计算概念刚提出的早期,UC Berkeley 大学曾发表的论文《Above the Clouds: A Berkeley View of Cloud Computing》,文中预言的云计算的价值、演进和普及在过去的十年里一一得到验证。十年之后的 2019 年,UC Berkeley 的第二篇有着相同命名风格的论文《Cloud Programming Simplified: A Berkeley View on Serverless Computing》发表,再次预言未来“无服务将会发展成为未来云计算的主要形式”,由此来看,“无服务”也同样是被主流学术界所认可的发展方向之一。

We predict that serverless computing will grow to dominate the future of cloud computing

我们预测无服务将会发展成为未来云计算的主要形式

—— Cloud Programming Simplified: A Berkeley View on Serverless Computing, 2019


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

  • 后端设施是指数据库、消息队列、日志、存储,等等这一类用于支撑业务逻辑运行,但本身无业务含义的技术组件,这些后端设施都运行在云中,无服务中称其为“后端即服务”(Backend as a Service,BaaS)。

  • 函数是指业务逻辑代码,这里函数的概念与粒度,都已经很接近于程序编码角度的函数了,其区别是无服务中的函数运行在云端,不必考虑算力问题,不必考虑容量规划(从技术角度可以不考虑,从计费的角度你的钱包够不够用还是要掂量一下的),无服务中称其为“函数即服务”(Function as a Service,FaaS)。


无服务的愿景是让开发者只需要纯粹地关注业务,不需要考虑技术组件,后端的技术组件是现成的,可以直接取用,没有采购、版权和选型的烦恼;不需要考虑如何部署,部署过程完全是托管到云端的,工作由云端自动完成;不需要考虑算力,有整个数据中心支撑,算力可以认为是无限的;也不需要操心运维,维护系统持续平稳运行是云计算服务商的责任而不再是开发者的责任。在 UC Berkeley 的论文中,把无服务架构下开发者不再关心这些技术层面的细节,类比成当年软件开发从汇编语言踏进高级语言的发展过程,开发者可以不去关注寄存器、信号、中断等与机器底层相关的细节,从而令生产力得到极大地解放。


无服务架构的远期前景看起来是很美好的,但笔者自己对无服务中短期内的发展并没有那么乐观。与单体架构、微服务架构不同,无服务架构有一些天生的特点决定了它现在不是,以后如果没有重大变革的话,估计也很难成为一种普适性的架构模式。无服务架构对一些适合的应用确实能够降低开发和运维环节的成本,譬如不需要交互的离线大规模计算,又譬如多数 Web 资讯类网站、小程序、公共 API 服务、移动应用服务端等都契合于无服务架构所擅长的短链接、无状态、适合事件驱动的交互形式;但另一方面,对于那些信息管理系统、网络游戏等应用,又或者说所有具有业务逻辑复杂,依赖服务端状态,响应速度要求较高,需要长链接等这些特征的应用,至少目前是相对并不适合的


这是因为无服务天生“无限算力”的假设决定了它必须要按使用量(函数运算的时间和占用的内存)计费以控制消耗算力的规模,因而函数不会一直以活动状态常驻服务器,请求到了才会开始运行,这导致了函数不便依赖服务端状态,也导致了函数会有冷启动时间,响应的性能不可能太好(目前无服务的冷启动过程大概是在数十到百毫秒级别,对于 Java 这类启动性能差的应用,甚至能到接近秒的级别)。


无论如何,云计算毕竟是大势所趋,今天信息系统建设的概念和观念,在(较长尺度的)明天都是会转变成适应云端的,笔者并不怀疑 Serverless+API 的设计方式会成为以后其中一种主流的软件形式,届时无服务还会有更广阔的应用空间。


如果说微服务架构是分布式系统这条路当前所能做到的极致,那无服务架构,也许就是“不分布式”的云端系统这条路的起点。虽然在顺序上笔者将“无服务”安排到了“微服务”和“云原生”时代之后,但它们两者并没有继承替代关系,强调这点是为了避免有读者从两者的名称与安排的顺序中产生“无服务就会比微服务更加先进”的错误想法。


笔者相信软件开发的未来不会只存在某一种“最先进的”架构风格,多种具针对性的架构风格同时并存,是软件产业更有生命力的形态。笔者同样相信软件开发的未来,多种架构风格将会融合互补,“分布式”与“不分布式”的边界将逐渐模糊,两条路线在云端的数据中心中交汇。今天已经能初步看见一些使用无服务的云函数去实现微服务架构的苗头了,将无服务作为技术层面的架构,将微服务视为应用层面的架构,把它们组合起来使用是完全合理可行的。以后,无论是通过物理机、虚拟机、容器,抑或是无服务云函数,都会是微服务实现方案的候选项之一。


本节是架构演进历史的最后一节,如本章引言所说,我们谈历史,重点不在考古,而是借历史之名,理解好每种架构出现的意义与淘汰的原因,为的是更好地解决今天的现实问题,寻找出未来架构演进的发展道路。


对于架构演进的未来发展,2014 年,Martin Fowler 与 James Lewis 在《Microservices》的结束语中曾写到,他们对于微服务日后能否被大范围地推广,最多只能持有谨慎的乐观,在无服务方兴未艾的今天,与那时微服务的情况十分相近,笔者对无服务日后的推广同样持谨慎乐观的态度。软件开发的最大挑战就在于只能在不完备的信息下决定当前要处理的问题。时至今日,依然很难预想在架构演进之路的前方,微服务和无服务之后还会出现何种形式的架构风格,但这也契合了图灵的那句名言:尽管目光所及之处,只是不远的前方,即使如此,依然可以看到那里有许多值得去完成的工作在等待我们。


We can only see a short distance ahead, but we can see plenty there that needs to be done.


尽管目光所及之处,只是不远的前方,即使如此,依然可以看到那里有许多值得去完成的工作在等待我们。


—— Alan Turing,Computing Machinery and Intelligence,1950


本文由机械工业出版社授权发布。


购买周志明博士最新力作《凤凰架构》,可以在下图扫码或者直接通过查看原文跳转,祝阅读愉快!

上一篇:ECS七天训练营进阶班 第一天 基于ECS搭建FTP服务


下一篇:详解网商银行“三地五中心”数据部署架构(5)