3.1.3 OpenAPI
OpenAPI是基于HTTP REST通信的接口规范,我们可以先了解其详细的规范定义(参考地址为https://swagger.io/specification/),当前规范为3.0(截至2020年10月)。下面介绍一下Kubernetes 1.16.0对应的OpenAPI规范,详细的定义可以访问https://editor.swagger.io/。图3-1所示为Kubernetes 1.16.0对应的OpenAPI规范截屏。
众所周知,HTTP是标准的通信协议,与具体的编程语言无关。任何编程语言都可以基于OpenAPI规范发布和调用服务。OpenAPI只是标准的规范,落实到具体编程语言的整合,还是会涉及具体编程语言的OpenAPI SDK开发。SDK主要作用是简化具体编程语言对OpenAPI的服务调用。如OpenAPI与Java整合,借助SpringFox(https://github.com/springfox/springfox)和springdoc-openapi(https://github.com/springdoc/springdoc-openapi)自动生成OpenAPI对应的JSON或者YAML文件,而无须人工编写。随着HTTP的普及,OpenAPI的应用范围越来越广泛。尤其是在前端和后端配合开发、不同合作方之间的API集成等方面,OpenAPI可以起到很好的协调作用。其定义的标椎规范,减少了理解上可能出现的歧义,同时避免了大量技术文档的编写。OpenAPI提供的工具非常多,参考地址为https://openapi.tools/。
图3-1 Kubernetes 1.16.0对应的OpenAPI规范
当然,服务化架构设计的技术方案并不只有上述三种,还包括WSDL、SOAP、xml rpc、json-rpc、Java RMI等。只不过这些技术目前可能已不再流行,或者只是某一编程语言的具体实现,有特定的使用场景,没有被广泛接受,但是这并不代表使用了这些技术就不是服务化架构,这点需要澄清。
下面就来看看实际的服务运维和服务调用,这里可能还需要考虑服务分组、服务版本和服务元信息等。那么,有人可能会提出这样的疑问:既然有了服务名,为何还需要服务相关的其他信息?解释如下。
1.服务分组
服务分组的目的主要是满足不同的地理空间和服务等级需求,例如在不同的数据中心,即便是相同的服务,也要通过不同的集群部署方式来区分。另外,考虑到服务等级要求,如针对给VIP客户提供更可靠的服务,也会涉及同样的服务在不同分组中的不同要求。当然,实际情况复杂多样,可能还会通过其他维度来对服务分组。
2.服务版本
服务发布后,随着需求的变更,我们需要在原有的服务规约上提供更多服务接口,其中一些可能还会涉及具体的逻辑变更。虽然我们竭力想要做到服务的接口兼容,但可能无法总是满足实际的需求。此时,我们需要推出服务的新版本,用于区分之前服务的接口规约。这也是为什么一些HTTP REST服务的URL路径中经常会看到v1、v2这样的版本信息。
3.服务元信息
如果我们的服务并不多(如在10个以内),那么通过一个文档就可以管理这些服务。但是如果是成百上千个服务接口,那么服务查找的成本就会非常高。在这种情况下,我们需要为服务添加一些元信息,如服务描述、服务提供者信息、服务的标签等,以便于管理服务。
在实际开发中,我们经常会听到两个术语,服务注册和服务发现。它们分别是指什么?应该如何管理上面提到的服务分组、版本和元信息以方便消费者调用服务呢?这里,我们需要一个服务注册(Service Registry)中心,首先由服务提供者负责向服务注册中心提供服务的名称、分组、版本和元信息等,然后服务的消费者根据自己的需求(如指定的分组和版本等)查找并调用指定的服务,整体结构如图3-2所示。
图3-2 服务调用的整体结构流程
在实际的业务场景中,我们所要考虑的内容远比图3-2所示的多,如服务的健康度检查、服务优雅上下线、服务调用的负载均衡、服务接口隔离(Interface Segregation)等。感兴趣的读者可以自行参阅相关资料。