本文是后端微服务架构系列的第二篇文章。在微服务架构中服务之间的通讯方式常见的有两种:RPC
和 REST
。java
文章每周持续更新,各位的「三连」是对我最大的确定。能够微信搜索公众号「 后端技术学堂 」第一时间阅读(通常比博客早更新一到两篇)
关于微服务和 RPC
的更多细节,能够参考我上一篇文章 面试都在问的微服务、服务治理、RPC、下一代微服务框架... 一文带你完全搞懂!c++
这篇文章主要介绍什么是 REST
风格设计以及 RESTful
接口。阅读完本文你将收获如下知识点:程序员
REST
和 RESTful
REST
接口设计规范是什么REST
为何要设计成无状态RPC
和 REST
适用场景REST(Representational State Transfer,表述性状态转移)
是一种软件架构风格。REST提出了一组架构约束条件和原则,任何知足 REST
约束条件和原则的架构,都称为 RESTful
架构。web
微服务之间须要相互通讯以完成特定的业务处理,在典型的客户端-服务端设计模型中,客户端和服务端统统过消息请求-响应的方式交互协做,REST
就是这样一套微服务之间交互接口的设计约束和原则规范。面试
乍一看 REST
「表述性状态转移」每一个字都认得,连起来不知道什么意思。也难怪,这是做者 Roy Thomas Fielding
在他的博士论文里提出的概念,论文天然都是学术用语,不过感兴趣的同窗能够去看看做者论文原文,地址我贴出来:https://www.ics.uci.edu/~fiel...redis
今天 lemon 用大白话帮你透彻理解这个概念,咱们把「表述性状态转移」掰开来看,先搞明白什么是「表述性」,什么是「状态转移」。编程
「表述性」实际上是缺乏了主语的,主语是「资源」。完整的描述是「资源表述性」,也就是「资源的描述」。在网络通讯中用什么描述资源呢?没错就是 URI(Uniform Resource Identifier,统一资源标识符)
。json
这里有几个近义词先给你们先科普一下:后端
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
自己并无提到底层应该使用什么协议,平常实践案例中最经常使用的是基于 HTTP
的 RESTful
实现。
这是由于 HTTP
协议自带的动词 GET/POST/PUT/DELETE
能够做为推进状态转移的方法,另外HTTP
的制定了规范的状态码。还有其余的一些 HTTP
特性,这些特性使得在HTTP
之上实现 REST
要简单得多,而若是使用其余协议的话,就须要本身实现这些特性。
RESTful
架构中,发生状态转换的是「资源」,因此URI
中通常只能包含表明「资源」的名词,而且推荐是复数,而不该该在 URI
中包对资源进行操做的动词。
对资源执行的CURD「增删改查」
动做应该在HTTP
请求方法的GET/POST/PUT/DELETE
中体现。
符合REST规范的写法:
POST http://www.test.com/lemon // 建立 Get http://www.test.com/lemon // 查询 PUT http://www.test.com/lemon // 修改 DELETE http://www.test.com/lemon //删除
不符合REST规范的写法:
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 状态码
表示请求处理结果,下降了微服务间互操做成本。
状态码 | 状态码含义 |
---|---|
2xx | 成功,操做被成功接收并处理 |
3xx | 重定向,须要进一步的操做以完成请求 |
4xx | 客户端错误,请求包含语法错误或没法完成请求 |
5xx | 服务器错误,服务器在处理请求的过程当中发生了错误 |
下面是常见的HTTP
状态码:
RESTful
接口要求是「无状态」。无状态指的是任意一个Web请求必须彻底与其余请求隔离,当客户端发起请求时,消息自己包含了服务端识别这一请求上下文所需的所有信息。
接口「无状态」更确切的说是服务端无状态,整个会话仍是须要状态维持的。要完成一个业务流程,通常客户端与服务端须要屡次的消息交互,咱们知道HTTP
协议是「无状态协议」,这就须要服务端可以识别几个独立 HTTP
请求的「状态信息」,从而将他们关联到一个业务流程中。
仍是举例子银行系统取款的例子:
这里有个问题,服务端在不一样时间点收到登陆请求和取款请求,这两个请求都是用户 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
具体化为一种基于HTTP
并按照 REST
约束设计的通讯协议,两个通讯协议之间仍是能够比较一下的。
RPC (Remote Procedure Call)
远程过程调用是一个计算机通讯协议。咱们通常的程序调用是本地程序内部的调用,RPC
容许你像调用本地函数同样去调用另外一个程序的函数,这中间会涉及网络通讯和进程间通讯,但你无需知道实现细节,RPC
框架为你屏蔽了底层实现。RPC
是一种服务器-客户端Client/Serv er
模式,经典实现是一个经过发送请求-接受回应进行信息交互的系统。
不少 RPC
框架提供的消息传输都是基于二进制的,好比Thrift
、Protocol buffers
。这样作的好处是消息结构比较紧凑,对于频繁调用或者大流量、低时延要求的应用场景,可以显著减小网络开销;另外一个约束是某些 RPC
框架有很强的技术耦合性,好比 Dubbo
只能用于 java
技术栈。综上,RPC
更加适用于系统内部微服务之间的高效通讯。
RESTful
接口因为提供了统一的基于 HTTP
的 REST
设计标准,只需 web
框架支持 HTTP
协议,并设计RESTful
风格的接口便可,极大的方便了第三方服务接入调用,适合用于微服务系统对外暴露的接口设计标准。
本文是微服务架构设计中接口选型的一个小方面,不少人会以为如今工做面试,无论是大厂仍是小公司,都是面试造飞机,工做拧螺丝。我的认为即便你在入职以后接触不到架构方面的工做,也要有一颗架构的心,高度决定认知,若是只盯着手上的那颗螺丝那和咸鱼有什么区别?
老规矩。感谢各位的阅读,文章的目的是分享对知识的理解,技术类文章我都会反复求证以求最大程度保证准确性,若文中出现明显纰漏也欢迎指出,咱们一块儿在探讨中学习。
好了,今天的技术分享就到这里,本文是后端开发微服务设计系列的第二篇,这个系列应该还会继续更新,咱们下期再见。
很是详细的 Linux C/C++ 学习路线总结!已拿腾讯offer
Linux下「进程」出问题不要慌,资深程序员教你6招搞定!
面试官:你说对MySQL事务很熟?那我问你10个问题
我用大数据分析了一线城市1000多份岗位招聘需求,告诉你如何科学找工做
腾讯后台开发面试笔试C++知识点参考笔记
还能这么玩?我用VsCode画类图、流程图、时序图、状态图不要太爽!
面试官:你会几种redis分布式锁?我会三种!
最详细的我的博客教程搭建教程GithubPages+Jekyll 简约风格博客
能够微信搜索公众号「 后端技术学堂 」回复「资料」有我给你准备的各类编程学习资料。文章每周持续更新,咱们下期见!