- 凤凰架构:构建可靠的大型分布式系统
- 周志明
- 3117字
- 2021-06-24 11:30:49
1.1 原始分布式时代
可能与绝大多数人的认知有些差异,“使用多个独立的分布式服务共同构建一个更大型系统”的设想与实际尝试,其实要比今天大家所了解的大型单体系统出现的时间更早。
在20世纪70年代末期到80年代初,计算机科学刚经历了从以大型机为主向以微型机为主的蜕变,计算机逐渐从一种存在于研究机构、实验室当中的科研设备,转变为存在于商业企业中的生产设备,甚至是面向家庭、个人用户的娱乐设备。此时的微型计算机系统通常具有16位寻址能力、不足5MHz时钟频率的处理器和128KB左右的内存地址空间。譬如著名的英特尔处理器的鼻祖Intel 8086处理器,就是在1978年研制成功,流行于80年代中期,甚至一直持续到90年代初期仍在生产销售。
计算机硬件有限的运算处理能力,已直接影响到了单台计算机上信息系统软件能够达到的最大规模。为突破硬件算力的限制,高校、研究机构、软硬件厂商开始分头探索,寻找使用多台计算机共同协作来支撑同一套软件系统的可行方案。这一阶段是对分布式架构最原始的探索,从结果来看,历史局限决定了它不可能一蹴而就地解决分布式的难题,但从过程来看,这个阶段的探索称得上成绩斐然,研究过程中的很多成果都对今天计算机科学的诸多领域产生了深远影响,并直接推动了后续软件架构的演化进程。譬如,惠普公司(及后来被惠普收购的Apollo)提出的网络运算架构(Network Computing Architecture,NCA)是未来远程服务调用的雏形;卡内基·梅隆大学提出的AFS(Andrew File System,Andrew文件系统)是日后分布式文件系统的最早实现(Andrew意为纪念Andrew Carnegie和Andrew Mellon);麻省理工学院提出的Kerberos协议是服务认证和访问控制的基础性协议,也是分布式服务安全性的重要支撑,目前仍被用于实现包括Windows和Mac OS在内的众多操作系统的登录、认证功能等。
为了避免UNIX系统的版本战争[1]在分布式领域中重演,负责制定UNIX系统技术标准的“开放软件基金会”(Open Software Foundation,OSF,也即后来的“国际开放标准组织”)邀请了当时业界主流的计算机厂商一起参与,共同制订了名为“分布式运算环境[2]”(Distributed Computing Environment,DCE)的分布式技术体系。DCE包含一套相对完整的分布式服务组件规范与参考实现,譬如源自NCA的远程服务调用规范(Remote Procedure Call,RPC),当时被称为DCE/RPC,它与后来Sun公司向互联网工程任务组(Internet Engineering Task Force,IETF)提交的基于通用TCP/IP协议的远程服务标准ONC RPC被认为是现代RPC的共同鼻祖;源自AFS的分布式文件系统(Distributed File System,DFS)规范,当时被称为DCE/DFS;源自Kerberos的服务认证规范;还有时间服务、命名与目录服务,甚至现在程序中很常用的通用唯一识别符(Universally Unique Identifier,UUID)也是在DCE中发明出来的。
额外知识
UNIX的分布式设计哲学
保持接口与实现的简单性,比系统的任何其他属性,包括准确性、一致性和完整性,都来得更加重要。
——Richard P.Gabriel,The Rise of Worse is Better,1991
由于OSF本身的UNIX背景,当时对这些技术的研究都带着浓厚的UNIX设计风格,有一个预设的重要原则是要使分布式环境中的服务调用、资源访问、数据存储等操作尽可能透明化、简单化,从而使开发人员不必过于关注他们访问的方法或其他资源是位于本地还是远程。这样的设计主旨非常符合UNIX一贯的设计哲学,然而这个过于理想化的目标背后其实蕴含着彼时根本不可能完美解决的技术困难。关于UNIX设计哲学,有几个不同的版本,这里指的是Common Lisp的作者Richard P.Gabriel提出的简单优先原则,即“Worse is Better”。
尽管“调用远程方法”与“调用本地方法”只有两字之差,但若要兼顾简单、透明、性能、正确、鲁棒、一致等特点,两者的复杂度就完全不可同日而语了。且不说远程方法不能再依靠本地方法那些以内联为代表的传统编译优化来提升速度,光是“远程”二字带来的网络环境下的新问题,譬如,远程的服务在哪里(服务发现),有多少个(负载均衡),网络出现分区、超时或者服务出错了怎么办(熔断、隔离、降级),方法的参数与返回结果如何表示(序列化协议),信息如何传输(传输协议),服务权限如何管理(认证、授权),如何保证通信安全(网络安全层),如何令调用不同机器的服务返回相同的结果(分布式数据一致性)等一系列问题,全都需要设计者耗费大量精力。
面对重重困难与压力,DCE不仅从零开始、从无到有地回答了其中大部分问题,构建出大量的分布式基础组件与协议,而且真的尽力做到了相对“透明”,譬如在DFS上访问文件,如果不考虑性能差异,很难感受到它与本地磁盘文件系统有什么不同。可是,一旦考虑性能差异,那远程和本地的鸿沟是无比深刻的,两者的速度往往有着数量级上的差距,完全不可调和。尤其是在那个时代的机器硬件条件下,为了让程序在运行效率上可被用户接受,开发者只能在方法本身运行时间很长、可以相对忽略远程调用成本时的情况下考虑分布式。如果方法本身运行时间不够长,就要人为用各种Tricks刻意构造出这样的场景,譬如将几个原本毫无关系的方法打包到一个方法体内,一起进行远程调用。一方面,这种长耗时方法本身就与期望用分布式来突破硬件算力限制、提升性能的初衷相悖;另一方面,此时的开发人员实际上仍然必须每时每刻都意识到自己是在编写分布式程序,不可轻易踏过本地与远程的界限。设计向性能做出的妥协,令DCE“尽量简单透明”的努力几乎全部付诸东流,无论是从编码、设计、部署还是从运行效率上看,远程与本地都有着天壤之别。开发一个能良好运作的分布式应用,需要极高的编程技巧和各方面的专业知识去支撑,这时候反而是人本身对软件规模的约束超过了机器算力上的约束。
对DCE的研究是计算机科学第一次对分布式有组织领导、有标准可循、有巨大投入的尝试,但无论是DCE还是稍后出现的CORBA,从结果来看,都不能称得上成功,因为将一个系统拆分到不同的机器中运行,为解决这样做带来的服务发现、跟踪、通信、容错、隔离、配置、传输、数据一致性和编码复杂度等方面的问题所付出的代价已远远超过了分布式所取得的收益。亲身经历过那个年代的计算机科学家、IBM院士Kyle Brown事后曾评价道,“这次尝试最大的收获就是对RPC、DFS等概念的开创,以及得到了一个价值千金的教训:某个功能能够进行分布式,并不意味着它就应该进行分布式,强行追求透明的分布式操作,只会自寻苦果。”
额外知识
原始分布式时代的教训
某个功能能够进行分布式,并不意味着它就应该进行分布式,强行追求透明的分布式操作,只会自寻苦果。
——Kyle Brown,IBM Fellow,Beyond Buzzwords:A Brief History of Microservices Patterns,2016
以上结论是有违UNIX设计哲学的,却是当时现实情况下不得不做出的让步。摆在计算机科学面前有两条通往更大规模软件系统的道路:一条是尽快提升单机的处理能力,以避免分布式带来的种种问题;另一条是找到更完美的、解决如何构建分布式系统的解决方案。
20世纪80年代正是摩尔定律开始稳定发挥作用的黄金时期,微型计算机的性能以每两年增长一倍的惊人速度提升,硬件算力束缚软件规模的链条很快变得松动,信息系统进入以单台或少量几台计算机即可作为服务器来支撑大型信息系统运作的单体时代,且在很长的一段时间内,单体都将是软件架构的绝对主流。尽管如此,对于另外一条路,即对分布式计算、远程服务调用的探索也从未中断。关于远程服务调用这个关键问题的历史、发展与现状,笔者还会在第2章中以现代RPC和RESTful为主角来进行更详细的讲述。那些在原始分布式时代中遇到的各种分布式问题,也还会在软件架构演进后面几个时代里被人们反复提起。
原始分布式时代提出的构建符合UNIX设计哲学的、如同本地调用一般简单透明的分布式系统的这个目标,是软件开发者对分布式系统最初的美好愿景,但迫于现实,它会在一定时期内被妥协、被舍弃。换句话说,分布式将会经过一段越来越复杂的发展过程。不过,在三十多年后的21世纪10年代[3],随着分布式架构逐渐成熟、完善,并取代单体成为大型软件的主流架构风格以后,这个美好的愿景终将会重新被开发者拾起。
[1] UNIX系统的版本战争:https://en.wikipedia.org/wiki/Unix_wars。
[2] 分布式运算环境:https://en.wikipedia.org/wiki/Distributed_Computing_Environment。
[3] 20世纪80年代的三十多年之后。这里是指服务网格提出后,重新崛起的透明通信。