大家如果跟着我一直读下来,我们已经走过了很长的一段路。在第五章,总算到了我们对于这篇论文最感兴趣的部分——满足Web需求的技术架构,即REST架构风格。很多人读Fielding的论文喜欢直接跳到第五章,但是这是一种糟糕的阅读方式。前面所有的章节对于推导出REST这种新型的架构风格来说都是必须的。前面的章节和第五章是因和果的关系,如果只读第五章,就只知道果而不知道因,知其然而不知其所以然。要xx理解REST,就必须xx理解Fielding所确立的这一套研究软件架构的方法,这一套方法论才是这篇论文{zd0}的贡献。 如果理解了前面4章的内容,这一章的内容其实非常容易理解,那就是根据上一章所识别出的Web需求,推导出一种xx适合Web需求的架构风格。 一般来说,推导出一种架构风格有两种方法:做加法和做减法。做加法就是先从一个最简单的架构风格开始,逐个添加识别出的架构约束;做减法就是先从一个非常复杂的架构风格开始,逐个去除不需要的架构约束。{dy}种方法强调创造性和无限的想象力,而第二种方法则强调限制和对系统环境的理解。这两种方法都可以得到希望的架构风格,区别是实践的难度。我们都知道,为一个简单的设计添加新的设计元素,通常都要比为一个复杂的设计减少设计元素更加容易。因此推导REST架构风格采用了做加法。 架构风格的推导从一个“空”风格开始。“空”风格就是没有任何约束的风格。这种推导方法我非常欣赏,体现出老子的“无中生有”、“一生二,二生三,三生万物”的思想。让我们清晰地看到了Roy Fielding和Tim Berners Lee等先贤的设计思路,看到了Web的架构如何在保持相对最简化的设计的同时xx地符合Web的需求。 为“空风格”添加的{dy}个架构约束就是客户-服务器。添加这个约束是为了分离xx点。因为Web交互所使用的分布式超媒体的存储地和使用地大多数时候都是不同的,它们的分工和角色有明显的不同,有必要将它们区分为客户端和服务器。服务器主要负责数据存储,而客户端主要负责提供用户界面。对于Web来说,最重要的是这种xx点的分离允许组件独立地进化,从而支持多个组织领域的Internet规模的需求。 添加的第二个架构约束是无状态。 “从客户到服务器的每个请求都必须包含理解该请求所必需的所有信息,不能利用任何存储在服务器上的上下文,会话状态因此要全部保存在客户端” 这个架构约束对于设计高可伸缩的服务器来说是非常重要的,我们几乎可以将此看作一个铁律。只要你希望服务器具有{zd0}的可伸缩性,都应该将服务器设计为无状态的。对于Web服务器是这样,对于数据库服务器也是这样。无状态的服务器设计做负载均衡、做集群都非常容易,很容易通过水平添加新的服务器来支持更大的负载。 很多人不喜欢xx无状态的服务器设计,他们很喜欢通过应用服务器内建的session将大量的状态保存在服务器端,因为这使得编程更加容易。此外,对于无状态的服务器,由于每次请求都需要发送很多会话状态信息,降低了网络性能。 架构的设计其实是一种权衡,设计师要有能力在多种因素之中判断出哪些更为重要。对于面向Internet的Web应用来说,由于设计者无法控制服务器并发访问量,因此应该优先考虑能够使得服务器具有{zd0}可伸缩性的设计。无状态的服务器设计对于保证服务器在高并发访问量时的可靠性是必须的。然而,对于面向局域网的B/S架构企业应用来说,服务器的并发访问量是能够预测并且加以控制的,因此xx无状态的服务器设计就不是必须的了。我们回顾一下Fielding在{dy}章中一再强调的,软件架构是软件在运行时的特性,设计软件架构之前一定要先考虑清楚应用具体的运行环境。面向Internet的Web应用和面向局域网的B/S架构企业应用是两种不同的运行环境,其需求有很大的不同,因此也需要不同的架构设计。很多人简单地将适合企业应用运行环境的架构拿来做Web应用,仅仅是因为它们都使用浏览器作为客户端,都使用HTTP协议。这样的Web应用在小并发访问量的情况下貌似运行地非常好,但是一旦遇到高并发访问,很快就会出现问题。 添加的第三个架构约束是缓存。 添加这个架构约束也是为了满足Internet规模的高可伸缩性需求。HTTP作为Web架构基础协议内建有很多对于缓存的支持。Web缓存一般可以出现在三个地方:客户端、代理、服务器端。使用最多的是客户端缓存,所有主流的Web浏览器都内建有对于客户端缓存的支持。
按照Fielding的描述,REST的统一接口由4个部分组成:资源的标识、通过表述对资源执行的操作、自描述的消息、以及作为应用状态引擎的超媒体 更加具体地说,在通常情况下,资源的标识就是资源的URI;资源的表述携带了资源的状态,可以对资源进行操作;自描述的消息由一些标准的HTTP方法和HTTP头信息字段组成;超媒体就是HTML/XHTML。 添加的第五个架构约束是分层系统。 通信链中最常见的中间组件包括代理、网关、防火墙等等,每个组件还可以内建自己的缓存实现。缓存根据它所在的位置又可以分为客户端缓存、代理服务器缓存、服务器端缓存,代理服务器缓存和服务器缓存是由多个客户端共享的,客户端缓存则是属于单个客户端私有的。 “分层系统约束和统一接口约束相结合,导致了与统一管道和过滤器风格类似的架构属性。”如果大家对于操作系统中的管道概念很熟悉的话,理解REST的分层架构约束是比较容易的。 为REST添加的第六个,也是{zh1}一个架构约束是按需代码。 读到这里,我们看到构成REST架构风格的架构约束其实非常少,5个必需的架构约束加上一个可选的架构约束,不多也不少,xx地满足了Web的需求。这很符合我所欣赏的设计哲学:好的设计并不是无法再添加新的部分,而是任何部分都无法再减少。得到满足系统需求的最简化设计应该是一个好的系统架构师所追求的目标。 识别出了满足Web需求的架构风格所应该具有的架构约束之后,Fielding接下来定义了REST风格的架构有哪些组成元素。一个REST架构的组成元素包括数据、连接器、组件三大类。 每一类架构元素都包括了多个成员, 资源标识符即我们都非常熟悉的URI。 用户代理一般即客户端的浏览器,它和来源服务器在一起构成了通信链的两端,中间还可以插入代理和网关等多个中间组件。前面我们说过,组件之间的交互通过连接器完成。连接器根据它在通信链中所在的位置可以分为客户端连接器和服务器端连接器。此外,缓存也是一种最常见的连接器。解析器和隧道使用的比较少。 Fielding还定义了关于REST的三种视图。每种视图从不同的角度和观点来展示REST的设计原则。这三种视图是: 架构元素的定义描述定义了REST的组成部分,三种架构视图则描述了这些架构元素之间如何协作以形成一个架构。 连接器视图集中于组件之间的通信机制。统一接口这个REST的主要的架构约束就是由连接器来实现的,连接器之间的交互必需通过统一的接口来完成。这个统一接口通常使用HTTP协议来实现,但是并不局限于HTTP协议。在REST的三大类架构元素中,连接器是直接与HTTP协议(或其他通信协议)打交道的部分。 数据视图的一个主要的侧重点是通信格式的定义: 同时,如果对数据进行有效地缓存,也能够非常有效地改善应用的性能。 对于通信协议的设计,Fielding举了一个微妙的“先响应后思考”的例子。尽管服务器不能确定客户端到底需要什么格式的内容,它还是在收到{dy}次请求之后就将最有可能的内容发给客户端。这样做要比先进行一轮内容协商再发送客户端需要格式的内容性能更好。 Fielding在对于数据视图的描述中写道: 这一段话对于理解REST架构的本质,REST为何称作“表述性状态转移”是非常重要的。 {zh1},Fielding回顾了对于Web架构的一些相关的研究工作,指出了这些研究工作中的局限,以及REST与它们的区别。 到了这一章,REST架构风格的面貌已经xx确定,下面就是将REST付诸实践。Fielding和他的协议设计团队正是使用REST作为设计Web架构基础协议HTTP和URI的指导,REST正是HTTP和URI协议背后的设计意图,HTTP和URI正是用来实现REST这样一种风格的架构的。 |