架构风格:你真的懂REST吗?

REST架构精解
本文深入解析REST架构风格,包括其核心约束与RESTful概念,探讨REST成熟度模型及HATEOAS实现难点。

本文探讨如下几个问题:

  • 什么是REST
  • REST包含哪些约束
  • 什么是RESTful
  • 纯RESTful API的难点在哪里

如果你去搜索「什么是REST」的话,大部分情况下,你看到的基本都是RESTful!

这类内容主要说的是:

  • 资源URL应该怎么写
  • 要用GET来获取资源
  • 要用POST来新建资源
  • 要用PUT来更新资源
  • 要用DELETE来删除资源

而实际上REST并不是这些,或者说并不完全是这些!

什么是REST

REST全称Representational State Transfer,出自Roy Thomas Fielding博士的博士论文《Architectural Styles and
the Design of Network-based Software Architectures》第五章(Fielding博士的这篇论文会在后面单独讨论),一般翻译为「表述性状态转移」。

在论文的第6章第一节提到了为什么会取REST这么一个名字:

The name 「Representational State Transfer」 is intended to evoke an image of how a well-designed Web application behaves: a network of web pages (a virtual state-machine), where the user progresses through the application by selecting links (state transitions), resulting in the next page (representing the next state of the application) being transferred to the user and rendered for their use.
「表述性状态转移」这个名称是为了唤起人们对于一个良好设计的 Web 应用如何运转的印象:一个由网页组成的网络(一个虚拟状态机),用户通过选择链接在应用中前进(状态迁移),导致下一个页面(应用的下一个状态的表述)被转移给用户,并且呈现给他们,以便他们来使用。

在「什么是架构模式和架构风格」一文中,提到过:

  • 架构风格是一组架构约束
  • REST是一种架构风格

所以,REST是一组架构约束

REST约束

REST是一个复合架构风格,即它包含了其它的架构风格!

REST约束包括:CS,无状态,分层,缓存,统一接口以及按需代码。其中「统一接口」是REST与其它架构风格的主要区别所在!「统一接口」包括了四个子约束:资源的识别,通过表述操作资源,自描述的消息,超媒体作为应用状态引擎!

《Architectural Styles and
the Design of Network-based Software Architectures》第五章给出了REST的完整推导过程,这里简单列出!

从一个没有约束的架构(NullStyle)开始,不断的添加约束,使此架构进化为需要的架构

Null Style:组件之间没有显著边界的系统,一个没有约束的架构

Client-Server

  • 约束:分离关注点(客户端接口和服务端数据存储)
  • 优势:客户端和服务端可以独立的进化。客户端可以与多个服务端通信,服务端可以方便的伸缩
  • 劣势:降低了性能

Stateless

  • 约束:通信必须在本质上是无状态的。从客户到服务器的每个请求都必须包含理解该请求所必需的所有信息,不能利用任何存储在服务器上的上下文,会话状态因此要全部保存在客户端
  • 优势:改善可见性,监视系统不必为了确定一个请求的全部性质而去查看该请求之外的多个请求。改善可靠性,减轻了从局部故障中恢复的任务量。改善可伸缩性,不必在多个请求之间保存状态,从而允许服务器组件迅速释放资源,并进一步简化其实现,因为服务器不必跨多个请求管理资源的使用。
  • 劣势:降低网络性能,由于不能将状态数据保存在服务器上的共享上下文中,因此增加了在一系列请求中发送的重复数据(每次交互的开销)。将应用状态放在客户端,降低了服务器对于一致的应用行为的控制

Cache

  • 约束:一个请求的响应中的数据被隐式地或显式地标记为可缓存的或不可缓存的
  • 优势:改善网络性能。如果响应是可缓存的,那么客户端缓存就可以为以后的相同请求重用这个响应的数据。可部分或全部消除一些交互,从而通过减少一系列交互的平均延迟时间,来提高效率、可伸缩性和用户可觉察的性能。
  • 劣势:可能降低可靠性,缓存中陈旧的数据与将请求直接发送到服务器得到的数据可能差别很大。

Uniform InterfaceREST核心特征):

  • 约束:组件之间要有一个统一的接口,包括四个子约束:
    • 资源的识别(identification of resources):每个资源都有各自的标识符。客户端在请求时需要指定该标识符。客户端所获取的是资源的表述,如HTML,XML 或 JSON 格式等。
    • 通过表述操作资源(manipulation of resources through representations):客户端操作的是资源的表述,而不是资源本身。
    • 自描述的消息(self-descriptive messages):每条消息都包含足够的信息来描述如何处理该消息。
    • 超媒体作为应用状态引擎(HATEOAS)(hypermedia as the engine of application state):客户端通过服务器提供的超媒体内容来了解如何操作表述,通过将对表述的操作提交到服务端,服务端来操作资源,继而改变服务端的状态。
  • 优势:简化整体架构,改善可见性,促进独立的可进化性
  • 劣势:降低了效率。信息都使用标准化的形式来转移,而不能使用特定于应用的需求的形式。

** Layered System**:

  • 约束:通过限制组件的行为,将架构分解为若干等级的层。
  • 优势:通过将组件对系统的知识限制在单一层内,为整个系统的复杂性设置了边界,并且提高了底层独立性。使用层来封装遗留的服务,使新的服务免受遗留客户端的影响;通过将不常用的功能转移到一个共享的中间组件中,从而简化组件的实现。中间组件还能够通过支持跨多个网络和处理器的负载均衡,来改善系统的可伸缩性
  • 劣势:增加了数据处理的开销和延迟,因此降低了用户可觉察的性能。可以通过在中间层使用共享缓存来弥补这一缺点。

Code-On-Demand(可选):

  • 约束:一个客户端组件知道如何访问一组资源,但不知道如何处理它们。它向一个远程服务器发送对于如何处理资源的代码的请求,接收这些代码,然后在本地执行这些代码
  • 优势:能够为一个已部署的客户端添加功能,改善了可扩展性和可配置性;当代码能够使它的动作适应于客户端的环境,并在本地与用户交互而不是通过远程交互时,能够得到更好的用户可觉察性能和效率。由于服务器将工作交给了客户端(否则将消耗服务器的资源),从而改善了服务器的可伸缩性
  • 劣势:由于需要管理求值环境,降低了简单性,在一些情况下可以通过简化静态的客户端功能得到补偿。最大的限制是由于服务器发送代码而不是简单的数据,因此缺乏可见性。如果客户端无法信任服务器,缺乏可见性会导致明显的部署问题。

总结

可能看完了推导,你还是不知道REST是什么!下面我通过一个列子来解释什么是「REST」!

举个例子

我们先看看Fielding博士为什么要设计REST?Fielding博士在论文里提到了,他设计REST是为了指导现代Web架构的设计与开发!基于REST,Fielding博士设计了HTTP1.1!也就是说,HTTP1.1是符合REST的!所以要搞懂REST,只要理解HTTP1.1就可以了!

如果你做过Web应用,那么CS,分层,无状态,缓存应该都很好理解,这里就不赘述了!按需代码就是类似Flash,Applet这类Web端应用,用以扩展Web功能的!

这里只说一下「统一接口」这个约束!

我们就以一个简单的HTTP请求来解释REST!

比如你输入www.abc.com时:

  • 你通过标示符来定位到www.abc.com网站的首页,abc站点将首页资源组装成Response信息返回到你的浏览器(资源的识别)
  • 返回的内容头里(HTTP header),告诉了浏览器该如何处理返回的信息(自描述的消息)
  • 返回的信息体(HTTP body),一般是HTML格式,它是你访问的首页资源的表述,里面包含了你能对这个表述进行的操作,比如能访问哪些链接,能提交哪些数据(超媒体作为应用状态引擎)
  • 你点击链接后,这是对表述的操作,你根本没有接触到真实的资源(通过表述操作资源)
  • 服务端接收到你的请求后,将对应链接的资源组装成Response信息返回(此时应用的状态就改变了)。
  • 浏览器接到返回后,将页面渲染出来,你可以进行下一步的操作。

什么是RESTful

上面解释了什么是「REST」!现在来解释一下什么是RESTful!

前面说了,REST是一组架构约束!那么,如果一个应用满足了REST约束,那么我们就可以称这个应用是RESTful的

虽然,很多系统自称是RESTful的,但是,实际上,绝大部分系统都不是RESTful的,或者不是完全RESTful的!Fielding博士对这个问题,发表了一篇博文,明确什么系统才能称为是符合我REST的!文中明确说明,系统必须满足HATEOAS约束才能称为是符合REST的!而HATEOAS很难实现!因为有人的参与!

为了缓解这个尴尬,Richardson 提出了「REST成熟度模型」。该模型把 REST 服务按照成熟度划分成 4 个层次:

  • **第一个层次(Level 0)**的 Web 服务只是使用 HTTP 作为传输方式,实际上只是远程方法调用(RPC)的一种具体形式。SOAP 和 XML-RPC 都属于此类。
  • **第二个层次(Level 1)**的 Web 服务引入了资源的概念。每个资源有对应的标识符和表述。
  • **第三个层次(Level 2)**的 Web 服务使用不同的 HTTP 方法来进行不同的操作,并且使用 HTTP 状态码来表示不同的结果。如 HTTP GET 方法来获取资源,HTTP DELETE 方法来删除资源。
  • **第四个层次(Level 3)**的 Web 服务使用 HATEOAS。在资源的表述中包含了链接信息。客户端可以根据链接来发现可以执行的动作。

从上述 REST 成熟度模型中可以看到,使用 HATEOAS 的 REST 服务是成熟度最高的,也是推荐的做法。

  • 对于不使用 HATEOAS 的 REST 服务,客户端和服务器的实现之间是紧密耦合的。客户端需要根据服务器提供的相关文档来了解所暴露的资源和对应的操作。当服务器发生了变化时,如修改了资源的 URI,客户端也需要进行相应的修改。
  • 而使用 HATEOAS 的 REST 服务中,客户端可以通过服务器提供的资源的表达来智能地发现可以执行的操作。当服务器发生了变化时,客户端并不需要做出修改,因为资源的 URI 和其他信息都是动态发现的。

现在大部分的自称是RESTful的系统,一般只能达到第三个层次!

HATEOAS的难点

HATEOAS为什么难以实现?是因为客户端无法决策!HTTP能实现RESTful,是因为浏览器只是将表述以及对资源的操作选项展示了出来,至于具体该如何操作,是由使用浏览器的人来决定的!也就是说,虽然服务端告诉了客户端操作的可选项,但是客户端没办法知道该选择什么!
网页浏览是有人的参与的,但是RESTful API是没有人参与的,这就导致RESTful API的客户端难以做出决定,该做什么!

可行的解决办法是:

  • 语义分析:客户端具有语义分析能力,能够自动的分析出后面需要执行哪个操作,目前这个很难实现
  • 客户端领域设计:客户端引入领域设计,在一个领域内,客户端和服务端达成共识,在特定领域内,目前有哪些操作。不过这个还是做不到只修改服务端就可以实现系统的进化。服务端进化后,客户端需要做对应的调整才可以完成整个系统的进化。

参考资料

<think>好的,我现在需要帮助用户理解微服务架构的定义和应用实例。用户要求用通俗易的语言解释,并且参考之前提供的引用内容。首先,我需要回顾之前的对话和用户提供的引用,确保信息准确且符合用户的需求。 用户在上一次的问题中已经详细解释了微服务架构的定义、特点、工作原理以及案例,现在他们可能希望得到一个更简洁、更易的版本,特别是实际应用例子。根据用户提供的引用,特别是引用[1]、[2]、[3]和[5],微服务的核心是将大型应用拆分为独立的服务,每个服务专注于单一业务功能,并且可以独立部署。 首先,定义部分需要简单明了,避免技术术语。引用[3]提到微服务是架构风格,由多个独立部署的微服务组成,每个服务完成一件任务。所以可以这样表述:微服务架构是把一个大型软件拆分成多个独立的小服务,每个服务专注做好一件事,比如用户管理或支付处理,各自独立运行和更新。 接下来是应用实例。用户可能对电商系统比较熟悉,引用[2]中提到电商的例子,比如搜索、推荐、客户服务等拆分成微服务。这里可以举一个具体的电商下单流程,分解成用户服务、订单服务、支付服务和库存服务,每个服务各司其职,通过API或消息队列通信。比如用户下单时,订单服务调用支付服务处理付款,成功后通知库存服务减少库存,物流服务安排发货,这样每个环节独立,一个环节出问题不影响整体。 同时,需要提到实际应用中的好处,如独立扩展(根据流量增减服务实例)、技术多样性(不同服务用不同语言开发)以及故障隔离。引用[4]提到微服务解决复杂性问题,分解成可管理的块,所以可以强调这点,比如系统更易维护和扩展。 用户可能还想知道实际公司如何应用,比如引用[2]提到的Netflix案例,但用户提供的引用中没有直接提到,不过之前的回答里有Netflix的例子,可能需要确认是否要包含。根据当前提供的引用,引用[5]提到了聚合器模式,可以简单说明聚合器如何组合多个服务的数据,比如电商首页需要用户信息、推荐商品和促销活动,聚合器分别调用各自服务获取数据,整合后展示给用户。 需要注意避免使用过多技术术语,用日常例子说明。比如将微服务比作餐厅的不同部门,厨房、收银、配送各自独立,协同工作,这样用户更容易理解。 最后,确保引用正确的来源,引用[1]对比了单体架构和微服务,引用[3]强调独立部署,引用[5]说明聚合器模式。需要将这些引用自然地融入到回答中,比如在解释独立部署时引用[3],在举例电商时引用[2]和[5]。 总结回答结构:定义、通俗解释、应用实例(电商下单流程)、实际应用方法(独立部署、通信方式、聚合器)、好处,最后相关问题。保持段落简短,使用粗体突出重点,代码块和公式按之前的要求处理。</think>### 微服务架构的定义与实际应用(通俗版) #### 一、一句话定义 **微服务架构**就像把一台巨型机器拆成多个独立小机器人,每个小机器人专注做好一件事(比如管用户、管支付),它们通过无线对讲机(API/消息队列)协作,最终完成整个系统任务[^3][^4]。 --- #### 二、通俗解释 想象一家餐厅: - **传统单体架构**:所有工作由一个大厨完成(炒菜+收银+洗碗) - **微服务架构**: - 厨房机器人 → 只负责做菜(**商品服务**) - 收银机器人 → 只管算账(**支付服务**) - 配送机器人 → 专注送餐(**物流服务**) **优势**:某个机器人故障(如收银机坏了)不会导致整个餐厅停摆[^1] --- #### 三、典型应用实例:电商下单 假设你在网购一双鞋,背后流程这样运行: 1. **用户服务** → 检查你的登录状态(“是本人吗?”) 2. **订单服务** → 创建订单(“买鞋1双,总价399”) ```python # 伪代码示例:订单服务调用支付服务 payment_result = call_payment_service(order_amount=399) ``` 3. **支付服务** → 连接支付宝扣款(“钱已到账”) 4. **库存服务** → 自动减少库存(“鞋子-1”) 5. **物流服务** → 生成快递单(“准备发货”) **关键点**: - 每个环节都是独立服务,用不同颜色框表示 - 支付失败不会影响商品库存数据[^2][^5] --- #### 、实际应用方法 1. **拆服务原则** - 按业务能力拆:比如把“用户评论功能”从商品服务里独立出来 - 参考案例:某外卖平台将“骑手调度算法”单独作为微服务,每小时可优化百万次路线[^4] 2. **通信方式选择** | 场景 | 方案 | 例子 | |---|---|---| | 需要实时反馈 | 直接打电话(REST API) | 下单时立即查库存 | | 允许延迟处理 | 发短信留言(消息队列) | 支付成功后通知发优惠券 | 3. **基础设施工具** - **服务管家**(服务注册中心):记录所有机器人的位置 - **故障保险丝**(熔断器):当支付服务崩溃时,自动切换备用方案 - **监控摄像头**(分布式追踪):追踪一个订单经过的所有服务[^3] --- #### 五、这样做的好处 - **灵活升级**:更新支付系统无需关闭整个网站 - **精准扩容**:双11期间给支付服务加10台服务器,其他服务维持原样 - **技术自由**:用Java写支付系统,用Python写推荐算法(就像餐厅里中餐和西餐厨房用不同厨具)[^2][^5] --- #### 六、你可能会遇到的问题 比如: - **过度拆分**:给“修改用户头像”功能单独建服务 → 维护成本暴增 - **数据不一致**:订单显示支付成功,但库存没扣减 → 需要最终一致性方案 --相关问题-- 1. 如果微服务之间频繁通信,如何避免系统变慢? 2. 如何用最简单的方式监控微服务的健康状态? 3. 微服务架构下数据库该怎么设计? 4. 小公司适合用微服务吗?什么情况下该考虑转型?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值