Rest架构风格详解

Rest架构风格详解

  • 何为架构风格?
    • 设计模式
    • 架构模式
    • 架构风格
  • Rest架构风格
    • 客户端-服务器(Client-Server, CS)
    • 无状态(Stateless)
    • 缓存(Cache)
    • 统一接口 (HATEOAS)
    • 分层的系统
    • 按需代码(可选)
  • 参考链接

表现层状态转换(英语:Representational State Transfer,缩写:REST)是Roy Thomas Fielding博士于2000年在他的博士论文中提出来的一种万维网软件架构风格,目的是便于不同软件/程序在网络(例如互联网)中互相传递信息。

何为架构风格?

讲架构风格时,需要先讲讲设计模式、架构模式的定义。

设计模式

在《设计模式》这本书的「What is a Design Pattern?」小节,对设计模式下了一个明确的定义:

The design patterns in this book are descriptions of communicating objects and classes that are customized to solve a general design problem in a particular context.

设计模式描述了一组类和对象的关系,用以解决特定上下文内的某个常见的设计问题!

架构模式

那我们可以这么定义架构模式:架构模式描述了一组组件之间的关系,用以解决特定上下文内的某个常见的架构问题!

维基百科上也给架构模式做了类似的定义:

An architectural pattern is a general, reusable solution to a commonly occurring problem in software architecture within a given context

架构模式是一个通用的、可重用的解决方案,用以解决特定上下文内的某个常见的架构问题!

架构风格

Roy Thomas Fielding博士,在他的REST论文中,对架构风格做出了定义:

An architectural style is a coordinated set of architectural constraints that restricts the roles/features of architectural elements and the allowed relationships among those elements within any architecture that conforms to that style.

一种架构风格是一组协作的架构约束,这些约束限制了架构元素的角色和功能,以及在任何一个遵循该风格的架构中允许存在的元素之间的关系。

Martin Flower在微服务文章中的说明,也间接支持了此定义。文中首先明确「微服务」是一种架构风格,然后给出了微服务所具有的特征(就是约束),具有这些约束的系统就可以说是使用了微服务架构风格!

Rest架构风格

REST 是一种架构风格,它包含了一个分布式超文本系统中对于组件、连接器和数据的约束。REST 是作为互联网自身架构的抽象而出现的,其关键在于所定义的架构上的各种约束。只有满足这些约束,才能称之为符合 REST 架构风格。

下面介绍一下Rest架构风格的6种架构约束。

客户端-服务器(Client-Server, CS)

客户端-服务器架构背后的约束原则是分离关注点。通过将用户界面功能(User interface functionality)移入到C端,服务器端只做数据存储, 简化了服务器组件,提高了可伸缩性。只要通信接口不发生变化,C端跟S端都能独立的演进。Rest架构风格详解_第1张图片

无状态(Stateless)

无状态要求通信本质上是无状态的。无状态要求从客户端发到服务器的所有请求都必须包含理解该请求的全部信息,不能利用任何存储在服务器端的上下文,会话状态因此要全部保存在客户端。在不同的客户端请求之间,服务器并不保存客户端相关的上下文状态信息。
无状态给架构带来了三方面的好处:可见性,可靠性,可伸缩性。

  1. 可见性。可见性是指一个组件对于其他两个组件之间的交互进行监视或者调解(monitor or mediate)的能力。拥有了可见性之后,就能够通过多个交互共享的缓存来改善性能(如Nginx缓存页面),通过分层服务来改善可伸缩性、通过反射式监控(reflective monitoring)来改善可靠性、通过中间件(例如,网络防火墙)对交互做检查来改善安全性。请求具有理解改请求的全部信息后,监控系统就不必要为了确定请求本身,查看该请求之外的多个请求。
  2. 可靠性。可靠性描述一个架构中的组件出现部分故障时,系统层面收到影响的程度。是指在给定时间内,特定环境下软件无错运行的概率。CS模式下,无状态减轻了从局部障碍中恢复的任务量,使得Server端可以快速恢复服务,从分布式系统层面看影响很小。
  3. 可伸缩性。一般来说,多个请求才能完成一个完整业务。而服务器不用再多个请求之间保存状态,从而可以允许服务器组件快速释放资源,简化实现,不用跨多个请求管理资源使用情况。

架构设计本身就是一种权衡,无状态虽然带来了上述优点。它也带来了一些不利的影响

  1. 降低网络性能。由于状态数据不能保持在服务器上的共享上下文中,这些数据会重复发送到服务器上,增加每次交互的开销(数据量)。
  2. 降低一致性控制能力。应用状态放在客户端,功能本身就得依赖于跨多个客户端版本的语义(semantics across multiple client versions)的正确实现,降低了服务器对于一致的应用行为的控制能力。比如http的put、push的语义,各个版本要保持一致,服务器才能理解。
    Rest架构风格详解_第2张图片

缓存(Cache)

缓存可以改变网络的效率。要求一个请求的响应中的数据被隐式的或者显示的标记为可缓存或者不可缓存的。如果是可缓存的,客户端缓存就可以为以后的相同请求重用这个响应的数据。
缓存架构约束的好处在于它有可能部分或者全部消除一些交互,从而减少系列交互的平均延迟时间,来提高效率、可伸缩性和用户感知的性能。这样也有代价,如果缓存中陈旧的数据与请求直接发送到服务器得到的数据差别会很大,那么缓存会降低可靠性。
Rest架构风格详解_第3张图片

统一接口 (HATEOAS)

Rest架构风格详解_第4张图片
统一接口是REST架构风格的核心特征,它强调组件间要有一个统一的接口。
通过在组件接口上应用通用性的软件工程原则,简化了整体的系统架构,也改善了交互的可见性。实现与他们提供的服务是解耦的,这促进了独立的演进性。当然,统一接口也会影响效率,因为信息都使用标准化的形式来提交,而不能使用特定于应用的需求的形式。
REST接口被设计为可以高效的传输大粒度的媒体数据,并针对Web的常见情况作了优化,但这也是导致该接口对于其他形式的架构交互而言不是最优的。
那么怎么样才能有统一的接口呢?REST由四个接口架构约束来定义:

  1. 资源标识(identification of resources)。REST对于信息的核心抽象是资源。任何能够被命名的信息都能够作为一个资源:一份文档、一张图片或者一个苹果等等。资源是到一组实体的概念性映射,而不是与映射相关的实体本身。资源标识符是用来标识组件之间交互所涉及到的特定资源,客户端在请求时需要指定该标识符。在 REST 服务中,该标识符通常是 URI。
  2. 通过表述来操作资源。表述是由一个字节序列和描述这些字节的表述元数据(representation metadata)组成。一个表述可用来表达某个资源的当前状态或者预期状态,或者某个其他资源的值。客户端接收到消息之后,可以通过消息中的控制数据和媒体类型信息来了解如何操纵资源,比如对资源进行修改或删除。
  3. 自描述的消息。每条消息都包含足够的信息来描述如何处理该消息。
  4. 作为应用状态引擎的超媒体(HATEOAS)。在资源的表达中包含了链接信息。客户端可以根据链接来发现可以执行的动作。

统一接口的请求的参数有请求的控制数据、一个(表示请求的目标的)资源标识符、以及一个可选的表述组成。输出参数有响应的控制数据、可选的资源元数据、以及一个可选的表述组成。统一接口这部分东西很多,在后面专门有一节讨论一下。

分层的系统

一个分层系统是按照层次来组织的,没一层为在其之上的层提供服务,并且使用在其之下的层所提供的服务。并且内部层对于相邻外部层之外的所有层而言,是被隐藏起来的。通过这样做,减少了跨越多层的耦合,从而改善了可进化性和可重用性。分层的系统的例子很多,最知名的就是TCP/IP的四层模型和OSI的七层模型。

在分层的系统中,可以有中间件来支持跨多个网络和处理器的负载均衡,处理安全策略和缓存等相关问题,以提高系统的可伸缩性。客户端、服务器并不需要了解中间的这些层次的细节。中间组件还能够主动的转换消息的内容,因为这些消息是自描述的,并且其语义对于中间件是可见的。
Rest架构风格详解_第5张图片
分层系统的主要缺点是:增加了数据处理的开销和延迟,因此降低了用户感知的性能。当然,这个问题可以通过在中间层增加缓存来弥补这个问题。

用户感知的性能,是根据对用户的影响来度量的,主要度量手段是延迟(latency)和完成时间(completion time)。
延迟(latency)是指从最初的触发请求到最早的响应指示之间持续的时间。在网络应用中,主要会出现在这些点上:1)应用对于触发动作的事件的响应时间。2)在组件之间建立交互所需的时间。 3)将交互请求数据传输到每个组件所需要的时间。4)在每个组件上处理每个交互请求所需的时间;5)应用通过移交和处理交互结果,最后呈现结果到用户面前的时间。
完成时间(completion)是完成一个应用动作花费的时间。完成时间与延迟的区别在于,延迟代表一个应用能够增量的处理正在接收的数据的程度。延迟可以认为是请求到响应最短时间,从用户发送请求,到收到第一个交互响应为止。而完成时间应该是用户请求最终完成的时间。这个从下载文件可以比较容易看出来,点击下载,到显示1%的下载进度的时间为100ms,则延时为100ms。而完成时间需要等待整个文件下载完成。
延迟的优化往往延长完成时间,反之亦然。比如通过压缩传输的数据传输,可以减少完成时间,但是延迟可能更高,因为组件处理增加了数据压缩的时间。所以在优化时,需要关注接收者更关注的是延时(例如Web浏览器)还是完成时间(Web爬虫)。

按需代码(可选)

服务器可以通过传输可执行代码的方式来扩展或自定义客户端的行为,对客户端进行扩展。这样可以减少被预先实现的功能的数量,简化客户端开发。而且允许在部署之后下载功能代码,也能改善系统的可扩展性。这是一个可选的约束。

可扩展性就是将功能添加到一个系统中的能力。动态可扩展性就是将功能添加到已经部署的系统中,而不影响系统的其他部分。

参考链接

  • thomas fielding, by Wikipedia
  • Architecture Styles and Design of Network based Software, by roy thomas fielding

你可能感兴趣的:(REST,架构)