上一节咱们了解了基于 XML 的 SOAP 协议,SOAP 的 S 是啥意思来着?是 Simple,可是好像一点儿都不简单啊!html
传输协议问题
对于 SOAP 来说,好比我建立一个订单,用 POST,在 XML 里面写明动做是 CreateOrder;删除一个订单,仍是用 POST,在 XML 里面写明了动做是 DeleteOrder。其实建立订单彻底可使用 POST 动做,而后在 XML 里面放一个订单的信息就能够了,而删除用 DELETE 动做,而后在 XML 里面放一个订单的 ID 就能够了。设计模式
因而上面的那个 SOAP 就变成下面这个简单的模样。缓存
POST /purchaseOrder HTTP/1.1 Host: www.cnblog.com Content-Type: application/xml; charset=utf-8 Content-Length: nnn <?xml version="1.0"?> <order> <date>2018-07-01</date> <className> 板栗焖鸡 </className> <price>58</price> </order>
并且 XML 的格式也能够改为另一种简单的文本化的对象表示格式 JSON。服务器
常常写 Web 应用的应该已经发现,这就是 RESTful 格式的 API 的样子。网络
协议约定问题
然而 RESTful 可不只仅是指 API,而是一种架构风格,全称 Representational State Transfer,表述性状态转移,来自一篇重要的论文《架构风格与基于网络的软件架构设计》(Architectural Styles and the Design of Network-based Software Architectures)。架构
这篇文章从深层次,更加抽象地论证了一个互联网应用应该有的设计要点,而这些设计要点,成为后来咱们能看到的全部高并发应用设计都必需要考虑的问题,再加上 REST API 比较简单直接,因此后来几乎成为互联网应用的标准接口。并发
所以,和 SOAP 不同,REST 不是一种严格规定的标准,它实际上是一种设计风格。若是按这种风格进行设计,RESTful 接口和 SOAP 接口都能作到,只不事后面的架构是 REST 倡导的,而 SOAP 相对比较关注前面的接口。app
并且因为可以经过 WSDL 生成客户端的 Stub,于是 SOAP 经常被用于相似传统的 RPC 方式,也即调用远端和调用本地是同样的。负载均衡
然而本地调用和远程跨网络调用毕竟不同,这里的不同还不只仅是由于有网络而致使的客户端和服务端的分离,从而带来的网络性能问题。更重要的问题是,客户端和服务端谁来维护状态。所谓的状态就是对某个数据当前处理到什么程度了。框架
这里举几个例子,例如,我浏览到哪一个目录了,我看到第几页了,我要买个东西,须要扣减一下库存,这些都是状态。本地调用其实没有人纠结这个问题,由于数据都在本地,谁处理都同样,并且一边处理了,另外一边立刻就能看到。
当有了 RPC 以后,咱们原本指望对上层透明,就像上一节说的“远在天边,尽在眼前”。因而使用 RPC 的时候,对于状态的问题也没有太多的考虑。
就像 NFS 同样,客户端会告诉服务端,我要进入哪一个目录,服务端必需要为某个客户端维护一个状态,就是当前这个客户端浏览到哪一个目录了。例如,客户端输入 cd hello,服务端要在某个地方记住,上次浏览到 /root/liuchao 了,于是客户的此次输入,应该给它显示 /root/liuchao/hello 下面的文件列表。而若是有另外一个客户端,一样输入 cd hello,服务端也在某个地方记住,上次浏览到 /var/lib,于是要给客户显示的是 /var/lib/hello。
不光 NFS,若是浏览翻页,咱们常常要实现函数 next(),在一个列表中取下一页,可是这就须要服务端记住,客户端 A 上次浏览到 20~30 页了,那它调用 next(),应该显示 30~40 页,而客户端 B 上次浏览到 100~110 页了,调用 next() 应该显示 110~120 页。
上面的例子都是在 RPC 场景下,由服务端来维护状态,不少 SOAP 接口设计的时候,也经常按这种模式。这种模式原来没有问题,是由于客户端和服务端之间的比例没有失衡。由于通常不会同时有太多的客户端同时连上来,因此 NFS 还能把每一个客户端的状态都记住。
公司内部使用的 ERP 系统,若是使用 SOAP 的方式实现,而且服务端为每一个登陆的用户维护浏览到报表那一页的状态,因为一个公司内部的人也不会太多,把 ERP 放在一个强大的物理机上,也能记得过来。
可是互联网场景下,客户端和服务端就完全失衡了。你能够想象“双十一”,多少人同时来购物,做为服务端,它能记得过来吗?固然不可能,只好多个服务端同时提供服务,你们分担一下。可是这就存在一个问题,服务端怎么把本身记住的客户端状态告诉另外一个服务端呢?或者说,你让我给你分担工做,你也要把工做的来龙去脉给我说清楚啊!
那服务端索性就要想了,既然这么多客户端,那你们就分分工吧。服务端就只记录资源的状态,例如文件的状态,报表的状态,库存的状态,而客户端本身维护本身的状态。好比,你访问到哪一个目录了啊,报表的哪一页了啊,等等。
这样对于 API 也有影响,也就是说,当客户端维护了本身的状态,就不能这样调用服务端了。例如客户端说,我想访问当前目录下的 hello 路径。服务端说,我怎么知道你的当前路径。因此客户端要先看看本身当前路径是 /root/liuchao,而后告诉服务端说,我想访问 /root/liuchao/hello 路径。
再好比,客户端说我想访问下一页,服务端说,我怎么知道你当前访问到哪一页了。因此客户端要先看看本身访问到了 100~110 页,而后告诉服务器说,我想访问 110~120 页。
这就是服务端的无状态化。这样服务端就能够横向扩展了,一百我的一块儿服务,不用交接,每一个人都能处理。
所谓的无状态,实际上是服务端维护资源的状态,客户端维护会话的状态。对于服务端来说,只有资源的状态改变了,客户端才调用 POST、PUT、DELETE 方法来找我;若是资源的状态没变,只是客户端的状态变了,就不用告诉我了,对于我来讲都是统一的 GET。
虽然这只改进了 GET,可是已经带来了很大的进步。由于对于互联网应用,大多数是读多写少的。并且只要服务端的资源状态不变,就给了咱们缓存的可能。例如能够将状态缓存到接入层,甚至缓存到 CDN 的边缘节点,这都是资源状态不变的好处。
按照这种思路,对于 API 的设计,就慢慢变成了以资源为核心,而非以过程为核心。也就是说,客户端只要告诉服务端你想让资源状态最终变成什么样就能够了,而不用告诉我过程,不用告诉我动做。
仍是文件目录的例子。客户端应该访问哪一个绝对路径,而非一个动做,我就要进入某个路径。再如,库存的调用,应该查看当前的库存数目,而后减去购买的数量,获得结果的库存数。这个时候应该设置为目标库存数(可是当前库存数要匹配),而非告知减去多少库存。
这种 API 的设计须要实现幂等,由于网络不稳定,就会常常出错,于是须要重试,可是一旦重试,就会存在幂等的问题,也就是同一个调用,屡次调用的结果应该同样,不能一次支付调用,由于调用三次变成了支付三次。不能进入 cd a,作了三次,就变成了 cd a/a/a。也不能扣减库存,调用了三次,就扣减三次库存。
固然按照这种设计模式,不管 RESTful API 仍是 SOAP API 均可以将架构实现成无状态的,面向资源的、幂等的、横向扩展的、可缓存的。
可是 SOAP 的 XML 正文中,是能够听任何动做的。例如 XML 里面能够写 < ADD >,< MINUS > 等。这就方便使用 SOAP 的人,将大量的动做放在 API 里面。
RESTful 没这么复杂,也没给客户提供这么多的可能性,正文里的 JSON 基本描述的就是资源的状态,没办法描述动做,并且可以出发的动做只有 CRUD,也即 POST、GET、PUT、DELETE,也就是对于状态的改变。
因此,从接口角度,就让你死了这条心。固然也有不少技巧的方法,在使用 RESTful API 的状况下,依然提供基于动做的有状态请求,这属于反模式了。
服务发现问题
对于 RESTful API 来说,咱们已经解决了传输协议的问题——基于 HTTP,协议约定问题——基于 JSON,最后要解决的是服务发现问题。
有个著名的基于 RESTful API 的跨系统调用框架叫 Spring Cloud。在 Spring Cloud 中有一个组件叫 Eureka。传说,阿基米德在洗澡时发现浮力原理,高兴得来不及穿上裤子,跑到街上大喊:“Eureka(我找到了)!”因此 Eureka 是用来实现注册中心的,负责维护注册的服务列表。
服务分服务提供方,它向 Eureka 作服务注册、续约和下线等操做,注册的主要数据包括服务名、机器 IP、端口号、域名等等。
另一方是服务消费方,向 Eureka 获取服务提供方的注册信息。为了实现负载均衡和容错,服务提供方能够注册多个。
当消费方要调用服务的时候,会从注册中心读出多个服务来,那怎么调用呢?固然是 RESTful 方式了。
Spring Cloud 提供一个 RestTemplate 工具,用于将请求对象转换为 JSON,并发起 Rest 调用,RestTemplate 的调用也是分 POST、PUT、GET、 DELETE 的,当结果返回的时候,根据返回的 JSON 解析成对象。
经过这样封装,调用起来也很方便。
小结
- SOAP 过于复杂,并且设计是面向动做的,于是每每由于架构问题致使并发量上不去;
- RESTful 不只仅是一个 API,并且是一种架构模式,主要面向资源,提供无状态服务,有利于横向扩展应对高并发。
原文出处:https://www.cnblogs.com/BeiGuo-FengGuang/p/10265404.html