由于AWS并没有像Google一样公开出一份API Design Guide,所以只能根据 API 的模样去逆向工程最初的设计考量。既然上一篇介绍了很多 REST 的缺陷,那么这里也会介绍一下 AWS是如何处理这类问题的。由于 AWS 在公有云领域无可置疑的领导地位,国内很多的公有云也是跟着AWS样子走的,所以如果你看国内一些公有云的API(如果有)是长得和 AWS很像的。
NO REST 上一篇说 Google 的设计是很极限的使用了 REST,而 AWS 作为另一个分支的极限,就一点 REST 的样子都没有了。具体作对比来说:
AWS 这么设计也是有历史原因,毕竟 AWS 诞生的时候 REST 的概念也刚出来,不可能上来就用,而之后为了兼容性和历史统一就一直使用这种风格了。另外听公司里年级大的一些程序员说 AWS 这种风格叫 SOAP,是当年在企业级应用里十分流行的一种设计,然而作为新世纪的程序员半天也没理解什么是 SOAP,就只能照着 AWS API 的模样来猜一下了。
来看一个创建实例的 API,从这里就能明白 AWS 的设计风格了。
https://ec2.amazonaws.com/ ?Action=RunInstances &ImageId=ami-beb0caec &InstanceType=m1.large &MaxCount=1 &MinCount=1 &KeyName=my-key-pair &NetworkInterface.1.DeviceIndex=0 &NetworkInterface.1. PrivateIpAddresses.1.Primary=true &NetworkInterface.1. PrivateIpAddresses.1.PrivateIpAddress=10.0.2.106 &NetworkInterface.1. PrivateIpAddresses.2.Primary=false &NetworkInterface.1. PrivateIpAddresses.2.PrivateIpAddress=10.0.2.107 &NetworkInterface.1. PrivateIpAddresses.3.Primary=false &NetworkInterface.1. PrivateIpAddresses.3.PrivateIpAddress=10.0.2.108 &NetworkInterface.1.SubnetId=subnet-a61dafcf &AUTHPARAMS
域名 域名分为两部分,产品线名称 + 接入点域名。这里的产品线名称基本和控制台里能看到的是对应的,比如 ec2 的 API 里就包含了实例,子网,Volume,EIP 等这些资源的 API 操作。接入点一般就 amazonaws.com 尽管 AWS 在世界范围内有很多 region 但是接入点都是这一个,应该是通过 DNS 来选则离当地最近的服务器,唯二的例外一个是美国国防部另一个是 AWS 北京采用的是独立的域名接入点。可以看出 AWS API 从设计最初就是希望能够一套方法操纵世界范围内的计算资源。
此外通过产品线来划分域名也可以方便的做到流量分离,如果所有产品的 API 接入点都做成同样的,靠程序进行分离显然会比较麻烦,而且域名划分也可以很好的隔离故障域。
URL参数 前面说过了 API 的 HTTP 部分没有路径,没有方法,没有 header 和 body,那么就只能靠 URL 参数来传递信息了。所有的 API 参数第一个部分都是 Action=xxx,可以看出来和 REST 围绕资源构造方法的思路不同,AWS API 的设计原则的中心就只有方法。既然不需要围绕资源来构造方法,那么很多 API 的设计就会直白很多。比如之前所说的在 REST 中给实例绑定 eip 这种涉及多个资源操作不好设计 API 的情况,AWS 这里就会简单很多,给实例绑定 eip 的 API 就是Action=AssociateAddress。同样像删除实例和 List 实例这种 REST 里比较简单的设计,这里也很直白,就是Action=TerminateInstances, Action=DescribeInstances. 由于所有参数都是通过 HTTP URL 参数传递的,习惯 JSON 传递数据的人可能会有疑问如何传递一个数组或者字典这种带嵌套的复杂数据结构。上面的例子也已经给出了,其实是有方法进行转换的比如上面创建实例 API 例子中的 private_ip 部分换成 JSON 就是: { “private_ips”: [ { “primary”: true, “private_ip_address”:”127.0.0.1” }, { “primary”: false, “private_ip_address”:”172.31.1.1” } ]} 如果仔细看 API 提供的 Action,可以发现绝大部分 Action 都是复数形式的批量操作 DescribeInstances, TerminateInstances,RunInstances,只有少部分像绑定 IP 这种是单数形式的操作。这样一来 REST 中比较难支持的批量操作,这里在设计最初就考虑支持了。比较跳出 REST 的框架来看,单资源的操作也只是批量操作的一个特殊形式。
另外这样所有信息都放 URL 参数做法额外的一个好处是程序处理起来会容易一些,不必先看路径,再看方法,再看 header 最后看 body 这样从各个地方拼出完整的信息,只需要统一从参数里找就可以。权限相关的处理在这种模式下也会很方便,方法名字直接就出来了,关联的资源 id 也可以从 URL 中直接找到,不用再去解析 body 来拿一堆信息才可以做鉴权。
Name or ID 作为定位资源的唯一标识符,可以用资源的 name 也可以用 id,AWS 的设计中 API 定位一个资源必须要用 ID。用 Name 定位的好处就是 API 看起来对人类比较友好,但问题也会很多。比如需要保证名字的全局唯一性,或者保证名字在某个 namespace 下是唯一的,这就需要很多额外的成本,API 和权限的设计和实现也需要考虑 namespace 会多加一层复杂度。另外当用 name 作为唯一标示的时候,变更名称的操作也会变得复杂。
在 AWS 的体系中,名字是可以任意重复的,在 API 中 Name 只能作为过滤条件出现,是无法保证定位到唯一资源的,所有定位资源都需要用 ID。这里面也有少量例外,比如 LoadBalancer 由于会生成域名,名字本身就是全局唯一的,就可以直接用名字来定位了,而且这类资源也是没有 ID 的。一般认为 id 的问题是格式太长了对人类不友好,看起来也别扭。但其实 ID 没必要像 UUID 那么长,在AWS 中一般资源的 ID 格式是资源名简称 + 八位十六进制字母,比如 instance 可能是 i-AB098884, volume 是 vol-FF122542, securityGroup 是 sg-AAA223333 这样的话通过资源名先做个隔离,八位十六进制本身能容纳将近 40 亿个名字,对于很多系统来说这个名字空间已经足够了。(然而最近 AWS 新的资源 id 部分已经到 16 位了,天知道他们有多少资源)
特殊字段
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有