阿里云作为国内乃至亚洲领先的IaaS云厂商,提供了丰富的算力产品服务,以算力商品在线化的方式进行出售。当前阶段算力商品的载体形态主要是实例规格。那么,购买实例规格的OpenAPI (如RunInstances)也就最具IaaS云的代表性。那么,分析RunInstances接口(编程协议)也就最具典型性。
下面以阿里云OpenAPI RunInstances参数定义,进行‘语言’特性分析。
https://help.aliyun.com/document_detail/63440.html
语言的基本特性来解读OpenAPI
OpenAPI指向性
指向性通知表示明确地表达、描述一个概念、实体、行动等。对于API指向性,意味着API的含义或者功能应首先避免二义性。
我们选择RunInstances作为分析案例,那么它指向什么? 开启实例(Run),也就是云上购买一批实例(Instance等价一定规模的算力)。从实例概念来说,RunInstance指向很明确:购买并启动实例。
进一步分析实例之所以成为实例,且能区分其他实例,那么实例应该具备更具体的‘区分性’的指向性。实例提供算力服务,由此实例的具体指向就是算力相关的具体指向。我们知道实例的算力体现:计算、存储、网络三大件,以及安全等核心要素。所以,RunInstances 里面预期应该有这些算力相关的具体指向。那么RunInstances 当前实际参数在这些具体指向性是怎么体现的呢?
OpenAPI计算指向性
参照RunInstances API 定义,其中有如下参数,这些参数对计算进行了‘指向’。
参数名称 |
数据类型 |
取值样例 |
InstanceType |
String |
ecs.g6.large |
InstanceName |
String |
k8s-node-[1,4]-alibabacloud |
CpuOptions.Core |
Integer |
2 |
CpuOptions.ThreadsPerCore |
Integer |
2 |
CpuOptions.Numa |
String |
1 |
OpenAPI存储指向性
参照RunInstances API 定义,其中有如下参数,这些参数体现了对存储‘指向’性。
参数名称 |
数据类型 |
取值样例 |
SystemDisk.Size |
String |
40 |
SystemDisk.Category |
String |
cloud_ssd |
SystemDisk.DiskName |
String |
cloud_ssdSystem |
SystemDisk.Description |
String |
SystemDisk_Description |
SystemDisk.PerformanceLevel |
String |
PL0 |
SystemDisk.AutoSnapshotPolicyId |
String |
sp-bp67acfmxazb4p**** |
IoOptimized |
String |
optimized |
StorageSetId |
String |
ss-bp67acfmxazb4p**** |
StorageSetPartitionNumber |
Integer |
2 |
DataDisk.N.PerformanceLevel |
String |
PL1 |
DataDisk.N.AutoSnapshotPolicyId |
String |
sp-bp67acfmxazb4p**** |
DataDisk.N.Encrypted |
String |
false |
DataDisk.N.Description |
String |
DataDisk_Description |
DataDisk.N.SnapshotId |
String |
s-bp17441ohwka0yuh**** |
DataDisk.N.Device |
String |
null |
DataDisk.N.Size |
Integer |
2000 |
DataDisk.N.DiskName |
String |
cloud_ssdData |
DataDisk.N.Category |
String |
cloud_ssd |
DataDisk.N.DeleteWithInstance |
Boolean |
true |
DataDisk.N.KMSKeyId |
String |
0e478b7a-4262-4802-b8cb-00d3fb40**** |
OpenAPI网络指向性
参照RunInstances API 定义,其中有如下参数,这些参数体现了对网络‘指向’性。
参数名称 |
数据类型 |
取值样例 |
VSwitchId |
String |
vsw-bp1s5fnvk4gn2tws0**** |
InternetMaxBandwidthIn |
Integer |
10 |
InternetMaxBandwidthOut |
Integer |
10 |
Ipv6AddressCount |
Integer |
1 |
NetworkInterfaceQueueNumber |
Integer |
8 |
NetworkInterface.N.VSwitchId |
String |
vsw-bp67acfmxazb4p**** |
NetworkInterface.N.NetworkInterfaceName |
String |
Network_Name |
NetworkInterface.N.Description |
String |
Network_Description |
NetworkInterface.N.SecurityGroupId |
String |
sg-bp67acfmxazb4p**** |
NetworkInterface.N.PrimaryIpAddress |
String |
172.16.**.** |
NetworkInterface.N.QueueNumber |
Integer |
8 |
NetworkInterface.N.SecurityGroupIds.N |
RepeatList |
sg-bp15ed6xe1yxeycg7**** |
PrivateIpAddress |
String |
10.1.**.** |
Ipv6Address.N |
RepeatList |
Ipv6Address.1=2001:db8:1234:1a00::*** |
OpenAPI安全指向性
参照RunInstances API 定义,其中有如下参数,这些参数体现了对网络‘指向’性。
参数名称 |
数据类型 |
取值样例 |
SecurityGroupId |
String |
sg-bp15ed6xe1yxeycg7**** |
Password |
String |
EcsV587! |
PasswordInherit |
Boolean |
false |
RamRoleName |
String |
RAM_Name |
SecurityGroupIds.N |
RepeatList |
sg-bp15ed6xe1yxeycg7**** |
SecurityOptions.TrustedSystemMode |
String |
vTPM |
SecurityOptions.ConfidentialComputingMode |
String |
Enclave |
小结
- 分析RunInstances 不难发现,里面还有其他的指向性属性参数,这里就不一一解说。
- 计算、存储、网络、安全等这些参数有的是必须,有的非必需。非必需的都有默认值。例如InstanceType必须的,InstanceName非必须的。
- 这些参数有的是基本属性,有的是高级属性。例如CpuOptions.Numa计算的高级特性,SecurityGroupIds.N基本安全组,SecurityOptions.TrustedSystemMode安全增强。
- 计算、存储、网络、安全等构成具体的指向,并且这些具体指向因为各种组合关系,使得这种指向丰富度大大增强,也导致真正理解具体商品对应的明细指向,有一定的成本。也间接反应了面向实例规格这种商品购买,具有一定的学习门槛。
- 如果继续存在InstanceType 这周云产品售卖形态,意味着满足指向型的RunInstances的各具体指向只会更加复杂、更加多元。目前通过启动模版、授权购买的方式可以简化一些操作,本质并没有‘单纯面向概念’,例如实例规格进行交互。
- 未来超越当前的指向有哪些可能。
- 一种可能的超越方式:例如安全是默认配置项,安全的相关配置按默认处理,那么请求参数里面可以省去这部分。
- 一种可能是新的实例规格出售,面向一个算力场景,例如云桌面,其背后具体什么样的资源交付形态,用户不感知,用户只需感知云桌面本身的特性。
- 新的产品规格实例在某个产品代上就终止了,改为‘属性、品牌’。老旧代实例被新的替代。这意味着:新的实例规格价格完全碾压旧代实例,新的实例规格各方面性能都具备很强的能力,完全可以适应各种场景需求
- 面向算力或者服务的交付,屏蔽硬件、软件的差异
OpenAPI 描述性
描述性意味着:对象具有灵活性,支持多种场景的需求,描述性用于更好理解。
描述性这里狭义地理解对当前实例规格的描述说明,算一个辅助的介绍。
参照RunInstances API 定义, 可以将以下参数理解为描述性的内容。
RegionId |
String |
是 |
cn-hangzhou |
ZoneId |
String |
否 |
cn-hangzhou-g |
InstanceName |
String |
否 |
k8s-node-[1,4]-alibabacloud |
Description |
String |
否 |
Instance_Description |
这些参数就是典型的针对具体指向的描述性参数。
整个RunInstances本身就是在描述云上购买算力商品这么一种‘编程协议行为’。
OpenAPI 逻辑性
逻辑性本质是按一定规则、条理来表达一种含义。参照RunInstances API 定义,下面的这几个参数可以说是逻辑性的典型代表。
参数名称 |
数据类型 |
必填性 |
取值样例 |
LaunchTemplateId |
String |
否 |
lt-bp1apo0bbbkuy0rj**** |
LaunchTemplateName |
String |
否 |
LaunchTemplate_Name |
LaunchTemplateVersion |
Long |
否 |
3 |
1.
当前云上商品形态主流的还是‘服务器’这个具体实物形态,对应RunInstances的逻辑就是实现这一形态,支持购买生产一台服务器的需要的各个逻辑参数、支持可编程化。几乎任意一个API本身就是一种逻辑的表现。
OpenAPI 交际性
交际性通常是互动的方式进行,要求互动的双方相互听的懂、相互有响应。
对应RunInstances的交际性,意味着:RunInstance输入参数应该支持
- 服务端应该及时有响应
- 交际如果只是单向的,这个互动是没有‘灵魂’的。对于云的API交际性的典型体现:接口响应要及时,否则就阻碍了高效互动。
- 相应应该和请求是关联的,要求输出相关结果。
- 互动的响应,有积极的、消极的
- 接口反馈有正确的、不正确的。对应接口结果,有成功的反馈,失败的反馈,并且失败有具体的原因、错误表达,便于下一轮的互动,这种结果应该符合互动的上下文、互动双方能够理解。
- 可以反复进行
阿里云的RunInstances的服务响应、结果输出都有相关明确的定义,很好地体现了语言的’交际性‘
OpenAPI 传播性
一种语言的传播性意味着:语言交流的人群规模、人群使用的频率。我们知道中文和英文在形成上是有很大的不同的,例如:语言文字的结构、语法、文法、句法的差异。追根溯源,本质是文化的差异。
那么OpenAPI的传播性,同样意味着有多少人使用,使用频率如何。前面说到RunInstance是阿里云当前商品售卖形态的主要代表,自然RunInstances是高频使用的。而人群规模也就是云的用户规模。对比AWS、AliYun的接口,
OpenAPI 名族性
在这里对应云平台自身的特性。例如阿里云的RunInstances、华为的RunInstance、腾讯的RunInstance、AWS的RunInstance 具有各自平台的特性。没有好坏之分,只有合适与否的选择。
语言的创新和实践
OpenAPI作为云的语言,作为一种用户与云,端与云的交互、互动的程序协议。那么创新性、实践性尤为关键。
OpenAPI 创造性
对于接口协议,从使用方来说,一经定义,就不期望随意修改。越简单越好,越是见名知意的表述越友好。从定义方来说,要能够支持明确的语意,要能在一套接口协议上支持各种场景的需求,要能提供易用性同时支持灵活性。
参照RunInstances API 定义,不能发现其中 Tag的定义,就很好的‘创造性’体现。通过Tag用户自定义自己的名词的Key、Value,这些Key、Value可以实现财务、资源、管理的自定义处理,打开了‘On Cloud’的各种可能的‘二次处理’的大门。例如基于Tag的分账,例如基于Tag的资源和应用分组关心管理,例如给予Tag的私有池匹配调度等。
Tag.N.Key |
String |
否 |
TestKey |
Tag.N.Value |
String |
否 |
TestValue |
OpenAPI 结构性
任何语言都有其相关的基本词汇、词法、句法等结构性信息。OpenAPI作为云的语言,顺着这个思路来看,那么云的所有OpenAPI构成了云的语言,所有OpenAPI遵循一个统一的词汇、词法、句法规则。
对应RunInstances(看作一个句子),它的句法结构性,例如计算、存储、网络、安全、基本描述等。它的词法结构性,单一概念指向的共同前缀结构性。例如SystemDisk SecurityOptions等。
云应该具备很强的实践性,否则云很难实现普惠。我们说云提供的是‘可编程基础设施‘,这个基础实施对外的沟通语言是OpenAPI,OpenAPI是提供算力服务的,被集成到业务的代码中。哪些因素会影响这种实践性的‘质量’或者‘生命力’?回到词汇、词法、句法,对应具体接口,也就是接口的数据结构、接口的功能边界、接口之间的链接。
目前看,OpenAPI的结构性AWS做的非常好,阿里云还有欠缺,为什么这么说。
- 形式上,AWS 明确的列举了它的平台上它提供的OpenAPI Data types,并且各接口严格遵守和使用这些Data types。看起来很简单的形式,其实意味着:各个新的产品推出、服务接口的定义,首先要在整体云的data types里面进行比较,是否已有相关data types,新的data types 是否合乎规范。纵观阿里云,并没有这样的data types 的目录,这也就不难发现,为何阿里云的一些接口定义里面出现了相同概念的多种参数命名。例如RunInstances的RegionId,DescribeSavingsPlansCoverageDetailhttps://help.aliyun.com/document_detail/298067.html 中的返回对象是Region
例如
PurchaseReservedInstancesOffering
https://help.aliyun.com/document_detail/100032.html
参数名 |
参数类型 |
默认值 |
取值说明 |
OfferingType |
String |
All Upfront |
预留实例券的付款类型。取值范围:
|
QuerySavingsPlansInstance
https://help.aliyun.com/document_detail/198100.html
参数名 |
参数类型 |
默认值 |
取值说明 |
PayMode |
String |
total |
付款类型:
|
- 我们说AWS的产品之间的互通性很强,阿里云的产品之间很难一步到位。这什么意思呢。例如你在阿里云购买了ECS、然后购买阿里云的RDS,然后期望ECS和RDS很easy的打通一起服务。在AWS上这块的相对简便些。https://zhuanlan.zhihu.com/p/24721353
https://docs.aws.amazon.com/codecommit/latest/userguide/integrations.html
当然从另外一个“狡辩”角度可以说,阿里云的发展规模还没有达到aws的规模,所以服务还不够成熟,或者说API还不够成熟。从设计视角看,阿里云在API当前的设计上存在的结构性缺陷。
OpenAPI 具体
具体性本质是原子性的另外一种说法。这里其实有一个很模糊的边界,究竟什么概念或者实体范围算一个原子呢,到底切多谢比较合适呢?
例如存储接口的定义,从read、 write 的参数,哪一个粒度最合适,是byte、byte[]、string、object?
例如tags.Key、value 这里是普通string,还是jsong string、还是其他自定义string 甚至加密string,那种合适?
具体性作者的经验是:定义OpenAPI的时候,尽量从属性原子开始定义、到接口功能原子定义结束,从‘概念实体‘具体化设计,到不同角色同学评审一致结束。
OpenAPI 准确
准确性一种是本接口内部的准确性,一种是接口体系内的准确性。准确性第一直观体现在接口命名上。例如create、delete、query,get、put、post、move等关键动词的定义,以及instance、vpc、securityGroup等名词的定义。
例如取消、释放、删除,究竟是delete、cancel、release这样的动词,还是统一delete呢?
准确性作者的经验是:应该首先遵循整体API的上下文环境(可能之前采取了某种风格,这种风格存在缺陷,不建议引入新的风格。因为新的又增加了用户的学习成本),在这个环境下,努力做到准确(很难说有绝对的准确,可能在这个场景下很准确,在另外一个环境下,可能就存在歧义了)。单个接口的准确性应该努力做到极致的‘合理’。多个接口之间的准确性,依赖工具的统一检测和管理、参照业界通用的做法
OpenAPI 简练
简练首先要做到一个接口只做一件事情。如果一个接口做多个事情,那么这个接口相比一件事就不够简练了。
小结
不论以什么方式来看云的OpenAPI,不论以什么设计准则来设计和实施云的OpenAPI,本质的不会变:做到简单、易用、可靠。回到接口设计本身的技术经验,业界有很多成熟的经验可以拿来学习(不一定能直接照搬到工作中,可能有一些技术债务不允许做优化----优化可能又引入新的 不一致)
下面列举Google、Aws、Azure的接口设计实践文档,这些文档还是满值得反复学习、借鉴的。
https://docs.microsoft.com/en-us/azure/architecture/best-practices/api-design
https://docs.microsoft.com/en-us/azure/architecture/microservices/design/api-design
https://aws.amazon.com/startups/start-building/how-to-build-a-public-facing-API/
https://aws.amazon.com/api-gateway/api-management/
https://cloud.google.com/blog/products/api-management/google-cloud-api-design-tips
https://developers.google.com/google-ads/api/rest/design/overview
https://cloud.google.com/apis/design/
总结
如何学习API设计,特别是云的API设计,从购买创建实例RunInstances开始吧。
实施好单个API、以及和生态整体API的协调一致,可以借鉴语言的基本特性来反问自己,是否可以进一步优化下?
最终总有一些坑,一些前人的经验教训可以提前学习,提前规避掉,那么业务的API设计文档,值得反复学习