微服务:如何遵守合同

向微服务架构的过渡要求对开发,测试,维护,设计的方法进行修订,换句话说,对软件组件生命周期的所有方面进行修订。 在本文中,我们将讨论Acronis架构师团队朝着最佳组件API迈进的实践。 这个故事将包括对问题的陈述和对解决方案的分析。 也许对于某些人来说,这篇帖子似乎是“队长”,但对于某人来说,为什么他们错过了超级解决方案X尚不清楚,但我们希望它对您有帮助。 我们邀请微服务构建者阅读并留下您的评论。

图片

如果您订阅了我们的博客,那么您已经阅读了有关微服务合同的信息。 我们在有关选择Swagger或RAML的帖子中讨论了它们,以及可以在先前创建的注释的基础上进行的静态检查 。 今天发表这篇文章的原因是在HighLoad会议上一份报告 。 我们通常需要讨论使微服务之间的关系正式化的途径。 今天,我想与Habr分享我们的结论,并检查其他建筑师是否同意我们的观点。

微服务是开发人员从中创建现代应用程序的“砖块”。 每个此类服务都通过API与外界互动。 通常,微服务是由独立的团队开发的,有时在地理位置上分散,因此为了有效开展工作,有必要保持其公共接口的一致性和完整性。 在提供数百项服务的大型公司中,有必要对每个组件进行注释:形式化输入数据并详细描述其工作结果。 如果使用HTTP REST,则有两种常见的注释格式:RAML和Open API Specification(又名Swagger)。 但是,我们今天关注的问题并不局限于任何特定协议。 因此,以下内容即使对于gRPC也将是相关的。

背景知识


Acronis已经存在了15年以上。 在这段时间里,产品和代码库有了很大的发展。 从复杂的桌面应用程序开始,我们进入了具有集中式管理控制台,权限定界和审核日志的企业模型。 下一步是将企业应用程序转换为开放平台,在该平台上,积累的经验可用于与外部服务集成。

如果说在API之前很重要,那么现在它已经成为产品的重要组成部分。 并且该API提供的流程已经成熟。

主要问题


每个人都对围绕API构建的问题感到熟悉。 我们将以夸张的形式描述它们:作为折磨假设的程序员Vasya和他同样假设的经理Kolya的痛苦。 所有名称都是虚构的,任何匹配都不是偶然的:)

1.说明已过时

让程序员Vasya开发组件A,该组件使用组件B的API。后者具有注释,但无效。 Vasya必须抓取他人的代码,寻找人,提出问题。 截止日期已经过去,他的经理Kolya必须处理截止日期的转移。

2. API不一致

程序员Vasya完成了任务,并切换到与组件B的操作有关的下一个任务。但是开发人员B和开发人员C的美感不同,因此相同的事情在API中的处理方式也有所不同。 Vasya再次处理该代码,而Kolya再次因未能按时完成而遭受痛苦。

3. API未记录

Kolya的经理决定发布组件A的API,以便集成商可以进行出色的集成。 集成商面临问题,支持服务超负荷,经理Kolya忙着一切,Vasya感到轮到他了。

4. API与旧版本不兼容。

实施了一体化,扑灭了所有大火。 但是Vasya突然认为他组件的API远非完美,并且沉浸在修订中。 当然,在这种情况下会破坏向后兼容性,并且所有集成都将崩溃。 这种情况导致集成商的成本增加,开发公司损失资金。

治疗方法


当程序员不了解良好的REST API或此视图分散时,就会出现所有这些问题。 实际上,并非所有开发人员都具有REST经验。 因此,“治疗”的主要方法是针对教育的。 当正确的API的愿景与其他开发人员,架构师和纪录片的愿景协调一致,开始在每个开发人员的头脑中绕时,API便成为理想选择。 形成这一愿景的过程需要努力和专门的工具,我们现在将讨论这些工具。

痛苦1.注释与实现不对应


注释可能与服务的当前状态有所不同,不仅因为它是“黑暗的过去”的API,无法访问。 这可能是一个尚未到来的光明的未来API。

这些情况的原因是缺乏对为什么需要注释的理解。 没有建筑师的恐怖,开发人员倾向于将注释视为内部辅助工具,并不意味着外部有人会使用它。

您可以通过以下方法治愈这种疼痛:

  • 建筑审查。 对于各种规模的公司来说,这是一件非常有用的事情,在该公司中至少有一个程序员“知道如何正确地做”。 更改服务时,架构师或负责人应监视批注的状态,并提醒程序员不仅必须更新服务,而且还必须更新其描述。 副作用-面对建筑师的瓶颈
  • 从注释生成代码。 这就是所谓的API优先方法。 这意味着您首先要进行注释,然后生成主代码(为此有足够的工具,例如[go-swagger](https://github.com/go-swagger/go-swagger)),然后填写业务服务逻辑。 这种安排避免了不一致。 当服务确定的任务区域清晰划定时,它可以很好地工作。
  • 测试注释与实现 。 为此,我们从注释(RAML /招摇)中生成用请求轰炸服务的客户端。 如果答案与注解相对应,并且服务本身没有失败,那么一切都很好。

测试注释与实施
让我们专注于测试。 这样的全自动查询生成是一项复杂的任务。 从API批注中获取数据后,您可以创建单独的请求。 但是,任何API都隐含依赖关系,例如,在调用GET / clients / {cliend_id}之前,您需要先创建此对象,然后获取其ID。 有时依赖性不太明显-创建对象X需要传递关联对象Y的标识符,这不是子集合。 RAML和Swagger都不允许描述明确的依赖关系。 因此,这里有几种方法可能:

  1. 期望开发人员在表示依赖性的批注中给出正式评论。
  2. 向开发人员请求描述期望的序列(有很多方法可以使用YAML ,专用DSL或通过精美的GUI描述请求,就像现在废弃的apigee一样
  3. 获取真实数据(例如,使用OpenResty记录所有服务器请求和响应)
  4. 使用(几乎)人工智能(例如RESTler )从注释中提取依赖

无论如何,测试任务非常耗时。

图片

就个人而言,我们到了手动准备测试序列的地步。 无论如何,开发人员都需要编写测试,以便我们为他们提供方便的工具,该工具可能会发现几个其他错误。

我们的实用程序使用以下yaml描述请求的顺序:

图片

圆括号声明在测试期间替换的变量。 地址变量作为CLI参数传递,并且random生成任意字符串。 这里最感兴趣的是response-to-var字段:它包含一个变量,将在其中将json与服务器响应一起写入。 因此,在最后一行,您可以使用task.id获取创建的对象的ID。

疼痛2。API不一致


什么是一致性? 我们不会引入任何正式的定义,但是,为了简化,这是内部一致性。 例如,在最初的项目中,Vasya需要在HighLoad上汇总报告中的数据,并且API按年份提供数据过滤。 在该项目几乎完成之后,经理Kolya来到Vasya,要求将发言人的统计信息添加到分析中,并制定一种新方法“ GET Speakers”,并按年份进行过滤。 结果,Vasya在几个小时内完成了代码,但是在测试过程中发现该方法不起作用。 原因是在一种情况下,“ year”是数字,在另一种情况下是字符串。 但这当然乍一看并不明显,并且在使用API​​时需要经常注意。 API持久性是不需要这种过度护理的时候。

有许多不一致的例子:

  1. 使用相同数据的不同格式。 例如,时间格式,标识符类型(数字或字符串UUID),
  2. 应用不同的语法进行过滤或分页,
  3. 不同的服务授权方案。 这些差异不仅会擦伤程序员的大脑,而且还会反思需要支持不同方案的测试。


治疗方法

  • 建筑审查。 如果有暴君建筑师,他(在没有精神分裂症的情况下)将确保一致性。 副作用:公共汽车因素和暴政:)
  • 创建指南API。 这是一个需要开发(或准备就绪)的单一标准,但是最重要的是实现它。 这需要宣传,一根棍子和一根胡萝卜。
  • 实施静态检查以确保符合注释API指南( 在此处了解有关内容)。

图片
示例-静态测试项目

每个公司对使用哪种准则都有自己的选择。 而且,大概没有通用的方法,应该是什么,不应该什么。 毕竟,标准中的规定越多,您要控制的严格程度就越高,而对创造自由的限制也就越大。 最重要的是,很少有人读到“只有100页”的文件。

在我们公司中,我们在指南中包括以下几点:

图片
可以在MicrosoftPayPalGoogle上找到准则的其他良好示例。

疼痛3。未记录API


注释的存在是简化使用API​​的必要条件,但不是充分条件。 您可以编写注释,以使其无法充分发挥其潜力。 在以下情况下会发生这种情况:

  1. 没有足够的描述(用于参数,标题,错误等);
  2. 没有足够的使用示例,因为示例不仅可以用于改进文档(为开发人员提供更多上下文以及直接从门户直接使用API​​的能力),还可以用于测试(作为模糊测试的起点));
  3. 有未记录的功能。

通常,这种情况发生在以下情况:开发人员对需要​​注释的原因没有一个清晰的了解;技术作家与程序员之间没有沟通;以及如果没有人弄清楚该公司因文档质量差而要付出多少成本。 并且,如果他们来到程序员那里,并且在每次请求支持后撤消,所有注解将很快被填写。

治疗方法:

  • 可供程序员使用的API参考生成工具。 如果开发人员看到同事和用户对他的API的描述是什么样的,他将尝试使注释更好。 副作用:配置这些工具将需要其他手动操作。
  • 在所有相关人员之间建立互动 :程序员,传播者,支持人员。 副作用:与所有人见面,使流程复杂化。
  • 使用基于API注释的测试 。 在带有注释的CI存储库中实现上述静态检查。

在Acronis中,基于带有SDK客户端和Try-It部分的注释生成注释API。 与代码示例和用例描述一起,它们构成了程序员所需的各种必要且方便的附件。 请访问我们的门户,网址为developer.acronis.com

图片

我必须说,有一整套工具可用于生成API参考。 一些公司自己开发满足自己需求的工具。 其他人则使用相当简单和免费的工具,例如Swagger编辑器 。 经过长期(非常漫长)的研究,我们在Acronis确定了Apimatic.io,并选择了REST United,Mulesoft AnyPoint等。

痛苦4.向后兼容性问题


向后兼容性可能因任何琐事而受损。 例如,程序员Vasya每次都用一个错字写“兼容性”一词:“兼容性”。 可以在代码,注释和一个查询参数中找到此错字。 注意到错误之后,Vasya在整个项目中都替换了这个单词,并且没有将更改发送到产品中。 当然,向后兼容性将受到损害,服务将下降几个小时。

为什么会发生此类事件? 主要原因是对API生命周期的误解,这可能会导致集成中断,不可预测的EOL(生命周期终止)策略以及晦涩的API版本。

治疗方法:

  • 建筑审查。 与往常一样,架构师的坚定双手可以防止向后兼容。 但是,其主要任务是说明支持多个版本的成本,并在不破坏现有API的情况下寻找进行更改的选项。
  • 向后兼容性检查。 如果API批注包含最新描述,则可以在CI阶段检查向后兼容性违规;
  • 及时更新文档。 必须在服务代码更改的同时更新API参考和API描述。 为此,您至少可以启动标准化清单,至少可以设置更改通知,至少可以训练超能力从一切中生成一切……重要! 文档部门应了解所有计划的更改,以便他们有机会计划用于更新文档和编写升级指南的资源。 经过测试和验证的升级指南是您在API中启动的任何重命名的可悲属性。

变更管理


描述与API生命周期相关的活动的规则称为变更管理策略。

图片

如果您具有“当前”和“新”注释的两个版本,则向后兼容性检查在技术上很简单:只需解析两个注释并检查是否存在必要的字段

图片

我们编写了一个特殊的工具,使您可以比较对CI的向后兼容性至关重要的所有参数。 例如,在GET / healthcheck请求中更改响应正文时,将显示类似于以下内容的消息:

图片

结论


每个架构师都梦想着摆脱API问题。 每个经理都梦想着不了解API问题。 :)。 有很多药物,但是每种药物都有自己的价格和副作用。 我们与API共享了最简单的儿童期疾病的治疗选择,然后出现了更严重的问题。 我们的文章“队长”的结论:API问题始于头脑,向人们传授良好实践是成功的主要保证。 其他一切都只是技术问题。 您遇到了什么问题以及在组织中选择了哪种解决方案?

图片
不良API的药物。

我们将很高兴收到任何想法,评分,评论,意见和问题!

Source: https://habr.com/ru/post/zh-CN483380/


All Articles