前言
近年来,微服务架构发展迅速,SparkPost就是早期落地微服务架构公司之一,他们发现落地微服务过程中,不光需要考虑服务发现、服务注册、服务调用跟踪链等等架构问题,也需要重视微服务API的变更管理。微服务的一大特性就是独立发布,快速迭代,但前提是足够稳定,他们在使用微服务构建API的过程中就遇到很多问题:
1. 客户(微服务使用方)经常反馈API 升级变更后不可用,有时影响范围不可控,导致该微服务上线延期,甚至线上故障,违背了微服务初衷
2. API参数变化或返回结果变化而导致客户端行为不一致,依赖客户端需要大量重构,团队不能专注在创新型工作
3. API 易用性差, 使用方技术栈不统一,各自进行API抽象及封装,容易出错
4. 缺少文档及使用引导,需要大量支持工作
5. 闭门造车,产出微服务往往不能满足需求,运行一段时间就会逐渐废弃
SparkPost经过多年的探索与实践,总结了大量最佳实践,指导他们构建持久稳定的微服务API。现如今,它们的API被成千上万的客户使用,包括Pinterest、Zillow和Intercomto,每月发送超过150亿封电子邮件。
在这篇文章中,我将回顾几个选择和最佳实践。
七大原则
一、Restful是最好的,但要实用,不需要学究式
首先,也是最重要的一步,我们采取的步骤是决定使用REST作为API。我们的理念是选择以下三个要素作为我们的API的基础:。
1. HTTP : 这包括响应代码和操作符。操作符包括POST、GET、PUT和DELETE,它们可以映射到基本CRUD(创建、读取、更新、删除)操作。
2. resources : 这些是HTTP操作人员执行的实体。
3. JSON (JavaScript对象表示法) : 这是一种通用的数据交换格式。
这三个元素提供了实用REST API所需的一切,包括简单性、可移植性、互操作性和可修改性。在构建了API之后,用户可以轻松地对其进行集成,而不考虑他们的编程语言,包括C#、PHP和Node。Js, Java,甚至是Shell中的CURL。他们可以不用担心潜在的技术发展,包括多种微服务。
当我们创建SparkPost API时,我们试着不要太过学究式地使用纯粹的REST模型,而是选择易于使用。下面是两个可能不遵循RESTful最佳实践的示例:
1. GET /api/v1/account?include=usage
2. POST/api/v1/sending-domains/example.domain.com/verify
第一个示例使用查询字符串参数来过滤实体中返回的内容。在第二个示例中,我们在终端名称中使用“verify”这个动词,这可能不符合Restful。我们会讨论每个新的用例,并尽力确保它的一致性和易于使用。
二、发展进化并管理变化
我们有许多开发人员和团队在使用我们的API的微服务,并在持续的变更。当工程师确定它已经通过了我们的测试时,我们就会自动将变更部署到生产中。
我们很早就决定让我们的API在使用惯例和如何管理变更方面保持一致。我们建立了一个治理小组,其中包括代表每个团队的工程师、产品管理组的成员和CTO。这个组建立了并强制我们遵守的API约定,并且是完全文档化的。
文档化的约定让我们可以减少不一致,并且更容易定义每个新的端点。以下是我们建立的一些约定:
· 在单词命名时,URL路径是带有连字符的小写字母,并且区分大小写。
· URL查询参数和JSON字段也是小写的下划线,并且是大小写敏感的。
· 请求主体中的非预期查询参数和JSON字段应该被忽略。
治理组还为如何进行更改以及允许哪些类型的更改设置了基本规则。有一些很好的API更改对用户是有益的,并且不会破坏它们的集成,包括:
· 一个新的API资源、端点或现有资源上的操作。
· 一个新的可选参数或JSON字段。
· 在JSON响应主体中返回的新字段。
相反,一个破坏性的变化包括任何可能破坏用户集成的东西,比如:
· 更改字段的数据类型。
· 一个新的必需参数或JSON 字段。
· 删除现有端点或请求方法。
· 现有资源方法的实质性行为差异,例如将选项的默认值改为“true”
三、做任何修改时不要制造破坏
即使它们是修复bug或不一致的结果,也应该避免发生修改。通常在这种特殊的情况下运行比破坏与客户端的集成风险更大。如果变化是多样的,我们会非常谨慎,寻找其他方法来实现我们的目标。有时可以通过简单地允许用户通过帐户设置或API参数更改其行为来实现。
然而,总会有一种情况引入变化对我们用户的利益胜过任何潜在的不利因素,将引入的变化。但是在这些情况下,我们遵循了这些最佳实践:
· 我们分析了API日志,以了解更改可能会影响多少用户。
· 我们给用户至少30到60天的提前警告。
· 我们发了一封邮件或发表了一篇博客文章,里面包含了关于改变的详细信息以及我们为什么要做这些改变。
· 我们在API文档中提供了升级指导。
四、“一个版本”规则
在过去的三年里,我们对API进行了数千次的修改,现在仍然是第一个版本。我们很早就决定不将API的版本超过第一个版本,因为这样做会增加不必要的复杂性,从而减慢用户对我们最新和最强大功能的使用。对API的版本控制也会减缓开发和测试,让监控变得复杂,让用户文档变得混乱。
另外,我们的API没有版本控制,这意味着我们可以避免围绕主题的争论。有三种方法可以实现API的版本,所有这些都有潜在的缺陷:
· 把这个版本放到URL中: 容易做,但是从语义的角度来看是一个不好的选择,因为这个实体在v1和v2之间没有变化。
· 添加一个自定义的标题 : 也很容易做,但是语义不强。
· 在accept标头中放置这个版本: 语义强但是最复杂的方法。
五、使用客户端库来帮助非javascript用户
我们的一些用户更喜欢Python、c#、Java或PHP而不是JavaScript。我们通过维护客户端库(为其代码提供易于使用的函数库)将API集成到应用程序中,使其快速进行集成。
随着时间的推移,我们的客户库已经发生了变化,我们也做了相应的版本。我们已经了解到,在包装一个不断增长的API时,抽象是很困难的,所以我们专注于提供一层薄薄的抽象,并使用一些语法快捷方式来简化我们API的使用。这样做可以让我们的用户快速地访问我们任何API,并且具有许多灵活性
六、“文档优先”的策略
我们将我们的文档视为代码,并在编写或更改一个API代码行之前使用它来记录我们的API更改。这样做可以帮助我们执行我们的约定,使所有事情保持一致,并保持良好的客户体验。它还削减了支持成本。
我们在GitHub中维护我们的文档,这使得技术和非技术用户可以很容易地做出更改。我们还发现,更容易审查变更的方式。我们使用API Blueprint Markdown格式和Jekyll生成HTML文档,以及一个名为Algolia的强大搜索服务。这样做让我们能够提供更好的客户体验,包括移动设备。
对于那些不想“滚动升级自己”文档的人来说,我们推荐OpenAPI(以前称为“Swagger”)、Apiary和API Blueprint。避免使用不适合REST API文档的工具是很重要的。我们建议在文档中包含一个亮橙色的“在Postman中运行”的按钮,这样可以很容易地试用一个API,以及成功和失败场景的例子。
七、听取用户的意见
最后,我们建议所有开发人员注意他们的用户的反馈。SparkPost有一个社区Slack的频道,成千上万的用户可以方便地联系我们的产品、支持、工程和执行管理团队的成员。我们也有一个专门的开发人员关系团队,他们专注于与开发人员社区的合作。所有这些都让我们能更好倾听用户的意见,并将他们的反馈整合到我们的API中。
总结
随着微服务架构的发展,微服务快速增长,有的企业内部运维了超过1000的微服务,且仍在不断增长,每个微服务包含数十API,如何持续管理微服务API 变化将成为企业的关注点,SparkPost 根据这些规则和最佳实践,为他们的业务从提供现场电子邮件基础设施到以完全基于云计算的电子邮件发送服务提供了坚实的基础。
原文链接:
https://devops.com/7-principles-for-using-microservices-to-build-an-api-that-lasts/
更多技术分享请关注公众号:JFrog杰蛙DevOps
2月11日在线课堂:《容器持续交付流水线最佳实践》
课堂收益:
1 .基于 Jenkins Pipeline,搭建 Docker 容器自动化持续交付流水线。
2 . 通过各阶段自动化及手工测试的结果,形成多维度质量关卡,保障发布包质量。
3 . 开发测试镜像和生产镜像分库管理,通过质量关卡的镜像升级到生产库,生产库的镜像权限得到保障,避免镜像被篡改。
4 .为 Docker 镜像构建进行持续的深度漏洞扫描,保证线上应用服务的安全。
5 . 为应用依赖的数据库等有状态服务提供自动化地数据库升级流程,规范自动化 CI/CD 流水线。
报名链接:https://www.bagevent.com/event/6358324