其他
面试造飞机系列:看架构师如何设计微服务接口
RPC
和 REST
,关于微服务和 RPC
的更多细节,可以参考我上一篇文章 面试都在问的微服务,一文带你彻底搞懂!REST
风格设计以及 RESTful
接口。阅读完本文你将收获以下知识点:什么是 REST
和RESTful
REST
接口设计规范是什么REST
为什么要设计成无状态接口无状态真的是没有状态吗 RPC
和REST
适用场景
REST 和 RESTful
REST(Representational State Transfer,表述性状态转移)
是一种软件架构风格。REST提出了一组架构约束条件和原则,任何满足 REST
约束条件和原则的架构,都称为 RESTful
架构。REST
就是这样一套微服务之间交互接口的设计约束和原则规范。REST
「表述性状态转移」每个字都认得,连起来不知道什么意思。Roy Thomas Fielding
在他的博士论文里提出的概念,论文自然都是学术用语,不过感兴趣的同学可以去看看作者论文原文,地址我贴出来:https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm表述性
URI(Uniform Resource Identifier,统一资源标识符)
。URI
是统一资源标识符,用来唯一的标识一个资源。URL
是统一资源定位器,它是一种具体的 URI
,即 URL
可以用来标识一个资源,而且还指明了如何定位这个资源,URL
是 URI
的子集。URN
统一资源命名,是通过名字来标识资源。URN
也是 URI
的子集。HTTP
协议中用 URL
标识资源,也就是浏览器地址栏你看到的那一串网址。资源表述性
传统的接口设计
lemon
这个人物对象,在服务端的存储形式是一个c++
的class
类型存储。lemon
对象的过程。服务端定义存储结构头文件 lemon.h
class lemon{
string name;
string address;
uint64 phone;
}
客户端代码引用服务端定义的
lemon.h
,「互相引用头文件,增加了服务耦合性!」客户端初始化一个
lemon
实例并序列化后通过网络接口发送给服务端。
class lemon lm;
lm.name = "lemon";
lm.address = "Shenzhen";
lm.phone = 18666666666;
服务端接收消息,反序列化,存储传输过来的 lemon
对象
资源表述性接口设计
lemon
这个服务内部的对象,对外表现可以用一张图片来表示,也可以用包含lemon
的姓名、地址、电话等信息的 xml
或 json
格式的数据表示。{
name : "lemon",
address: "ShenZhen",
phone : 18666666666
}
<?xml version="1.0" encoding="UTF-8" ?>
<name>lemon</name>
<address>ShenZhen</address>
<phone>18666666666</phone>
lemon
这个「资源」在服务内部的存放形式对外不可见,外界客户端发起请求可以用不同的资源表述格式来获取服务端的资源。os
大概是这样的: 客户端你不用管我是如何保存这个对象的,只要你说的清楚想要什么对象,只管发来请求便是!)。状态转移
REST的约束条件
协议选择
REST
本身并没有提到底层应该使用什么协议,日常实践案例中最常用的是基于 HTTP
的 RESTful
实现。HTTP
协议自带的动词 GET/POST/PUT/DELETE
可以作为推动状态转移的方法,另外HTTP
的制定了规范的状态码。还有其他的一些 HTTP
特性,这些特性使得在HTTP
之上实现 REST
要简单得多,而如果使用其他协议的话,就需要自己实现这些特性。请求规范
RESTful
架构中,发生状态转换的是「资源」,所以URI
中一般只能包含代表「资源」的名词,并且推荐是复数,而不应该在 URI
中包对资源进行操作的动词。CURD「增删改查」
动作应该在HTTP
请求方法的GET/POST/PUT/DELETE
中体现。POST http://www.test.com/lemon // 创建
Get http://www.test.com/lemon // 查询
PUT http://www.test.com/lemon // 修改
DELETE http://www.test.com/lemon //删除
POST http://www.test.com/Createlemon // 创建
POST http://www.test.com/Querylemon // 查询
POST http://www.test.com/Modifylemon // 修改
POST http://www.test.com/Deletelemon //删除
状态码
RESTful
规范的接口返回状态码都是通用的,不需要额外约定,利用HTTP Status Code 状态码
表示请求处理结果,降低了微服务间互操作成本。HTTP
状态码:200 - 请求成功 301 - 资源(网页等)被永久转移到其它URL 404 - 请求的资源(网页等)不存在 500 - 内部服务器错误
无状态
RESTful
接口要求是「无状态」。无状态指的是任意一个Web请求必须完全与其他请求隔离,当客户端发起请求时,消息本身包含了服务端识别这一请求上下文所需的全部信息。无状态不是真的没有状态
HTTP
协议是「无状态协议」,这就需要服务端能够识别几个独立 HTTP
请求的「状态信息」,从而将他们关联到一个业务流程中。用户lemon要登录银行系统,首先需要在登录页面输入用户名和密码,这时候产生一个登录请求 服务端收到登录请求,执行登录逻辑并返回操作结果 lemon登录之后点击取款100万,产生一个取款请求 服务端收到取款请求,执行取款逻辑并返回操作结果
lemon
产生的,如果不在技术层面做对独立的 HTTP
请求做关联的话,服务端就无法知道这两个请求其实是都是用户lemon
「取款业务」的组成部分。技术方案
Session
方式。服务端保存会话状态,客户端每次请求携带session-id
。服务端维护一个会话状态信息列表,用
session-id
唯一标识一个状态信息,session-id
一般包含在HTTP
响应的Set-Cookie
头部返回给客户端,后续客户端请求携带包含session-id
信息的cookie
头部,服务端解析cookie
取出session-id
,去维护的状态列表中取回该消息对应的状态信息,这样就把无状态的HTTP
变成有状态的了。
Token
方式。服务端不保存会话状态,客户端每次请求都携带完整的会话状态信息(一般是加密的)给服务端。Token
也称作是「令牌」或临时证书签名,状态信息都被加密到token
中,这样每当服务器收到请求后解密token
就能获取该请求对应的状态信息,也就能把不同的请求消息关联到同一个业务流程中来,和session
方式有类似的效果,只不过这次的状态信息不保存在服务端。
Session
方式是有状态的,第二种 Token
方式是无状态的。RESTful
接口最好按第二种技术方案实现,当然要实现无状态也还有其他方式,思路都是「服务端不保持会话状态」就对了。为什么要无状态
RESTful
接口要求是无状态的,是为了更好的适应分布式业务场景,发挥微服务集群优势。REST 和 RPC
REST
是一种软件架构接口设计风格,RPC
是一种计算机通信协议,看起来是两个不同的概念,没法比较。REST
具体化为一种基于HTTP
并按照 REST
约束设计的通信协议,这样两个通信协议才有比较性。回顾下RPC
RPC (Remote Procedure Call)
远程过程调用是一个计算机通信协议。我们一般的程序调用是本地程序内部的调用,RPC
允许你像调用本地函数一样去调用另一个程序的函数,这中间会涉及网络通信和进程间通信,但你无需知道实现细节,RPC
框架为你屏蔽了底层实现。RPC
是一种服务器-客户端Client/Server
模式,经典实现是一个通过发送请求-接受回应进行信息交互的系统。RPC
框架提供的消息传输都是基于二进制的,比如Thrift
、Protocol buffers
。这样做的好处是消息结构比较紧凑,对于频繁调用或者大流量、低时延要求的应用场景,能够显著减少网络开销;另一个约束是某些 RPC
框架有很强的技术耦合性,比如 Dubbo
只能用于 java
技术栈。综上,RPC
「更加适用于系统内部微服务之间的高效通信」RESTful
接口由于提供了统一的基于 HTTP
的 REST
设计标准,只需 web
框架支持 HTTP
协议,并设计RESTful
风格的接口即可,极大的方便了第三方服务接入调用,「适合用于微服务系统对外暴露的接口设计标准」写在最后
你知道吗?其实 Oracle 直方图自动统计算法存在这些缺陷!(附验证步骤) 你公司的虚拟机还闲着?基于 Jenkins 和 Kubernetes 的持续集成测试实践了解一下! 一站式杀手级 AI 开发平台来袭!告别切换零散建模工具 那些神一样的程序员 比特币当赎金,WannaRen 勒索病毒二度来袭! 通过 Python 代码实现时间序列数据的统计学预测模型
真香,朕在看了!