当前位置: 首页 > 科技观察

微服务API设计实践与思考总结

时间:2023-03-15 17:02:58 科技观察

APIFirstAPI设计FAQ越来越多的公司开始实现微服务架构。与单体应用架构相比,微服务将复杂性拆分、分散到更细粒度的应用中,大大降低了单个服务在开发中的复杂度,开发者只需要专注于单一业务场景的编程。从技术发展的角度来看,大大减少了单个服务的代码量。从业务的角度来看,业务复杂度的降低降低了需求的沟通成本。但是整体的业务复杂度还是存在的,当我们需要接入或依赖其他服务时,通常作为接入方,并不需要对服务提供方的业务有深入的了解。这时候,API就成为了开发者之间的交流语言。好的API设计可以大大降低沟通成本,有时甚至可以代替文档,尤其是基础服务。服务的可扩展性有时会反映在API的可扩展性上。曾经参与过一个基础业务微服务的业务升级,由于老版本的API没有明确划分,部分API重复,后面大部分API都要重构(换成新版本的API)),这只会在服务消费者升级阶段持续1-2个月的时间,在这个过程中,我不断思考API设计中的一些问题,应该遵循哪些原则。API是敏捷开发大浪潮中的先行者。产品通常需要快速迭代。面对一个新的需求,如果需要开发一个新的接口,通常在表结构设计好之后,开发者需要完成API的设计并交付给消费者。(即服务的调用方或依赖方,其余文字表示此意),在技术联调前,消费者可以通过Mock接口完成调试。所以一般来说,API是先随服务一起交付,然后再完成编码、测试、调试等。当然,由于需求和技术实现的细节,在实现过程中可能会发现需要调整需求,或者API接口的调整。API的初始版本可能不成熟,这导致我们在API调整或演化过程中维护API。方面有很多疏漏,所以API在初次交付后的维护是一个持续的工作。API设计中的常见问题在设计API的过程中,由于缺乏经验,或者由于多次交接,或者由于需求的多次变更,服务的API被慢慢破坏,导致以下常见问题。忘记评论。注释通常描述API函数和参数说明,以及如何访问它们,甚至给出简单的例子。过于详细的注解会带来一定的副作用,比如因为新的需求需要调整内部逻辑,但是由于没有及时更新API注解,会给新接入的调用者带来潜在的风险。因此,不仅需要为API提供完整清晰的注释,而且当内部逻辑发生变化时,开发者通常需要在API层面评估变化,包括注释。接口数量不断扩大。接口数量扩大的原因有很多。可能是界面升级,但是老界面不能直接下线,所以会提供一个功能类似的新界面;面对新需求,直接开发新接口;可能是接口分类不合理,也可能是数据模型混乱导致API划分混乱,API功能重复,最终导致一个场景出现多个API接口。这显然是应该避免的事情。.解决这些问题需要对业务有充分的了解,下面的设计原则将提供解决此类问题的方法。在缺乏有效测试的情况下,很多开发者往往忽略了接口的测试。无论是内部逻辑细节的单元测试,还是接口层面的测试,都是服务健壮性的有效保障。如果不能对接口进行有效的测试,不仅是失败,而且经常会被线上BUG困扰。API设计原则简单、重点突出:在面向对象的设计原则中,首先是单一职责原则,这一原则同样适用于API设计。我们的主要对象是业务模型,API是封装了内部逻辑后对外开放的功能。保持API简单,职责单一,可以避免解决上述接口扩展的问题。如何实现API的单一职责,需要我们在定义接口的时候能够准确的识别出接口之间的关联和边界。可以从以下几个角度来划分API:根据业务实体的划分,不同的业务实体采用不同的方法。接口类查询类和修改类的接口分离;一般来说,我们的数据查询场景远大于修改场景,查询的业务场景多种多样。修改,此时的业务逻辑通常比较特殊(比如有很多额外的数据校验),所以建议尽量把修改类和查询API分开,甚至把业务配置后台也分开从正常的业务查询中类查询,使其能够适应相应的业务变化。focus:单一接口场景基于业务抽象,专注于某个场景,相互之间不重叠,从而保证接口的粒度足够小,尤其是对于基础业务,接口粒度的划分可以保证接口纯净且相互独立,让需求的变更不涉及过多的接口变更(除非业务模型有较大调整)。另外需要注意的是,内部逻辑业务数据模型(POJO类)和API数据模型(DTO)有时会有差异,否则消费者可能需要了解服务的业务模型才能正确使用接口。这就需要开发者在API设计中明确规定应该向消费者提供哪些数据模型。在这个前提下,更有助于我们保持对单一界面的关注。好的注释应该包括什么:接口的使用场景,参数的描述,接口文档的链接地址可以在接口类描述中给出,方便调用者查看参数的描述;包含参数的含义,参数的类型按照Javadoc链接规范,参数是否为空,特殊值说明过期说明;如果接口已经过期,则需要给出过期说明。对于Java,是@Deprecated注解,给出了切换接口的说明。如果条件允许,可以推动调用方迁移接口,老接口后续的离线扩展唯一不变的就是变化,接口会不断演进。我们不提倡提前过度设计,但在演进过程中必须始终保持接口的可扩展性。多参数结构和单参数类结构一般来说,如果一个接口的参数少于三个,建议使用多参数接口,直观简洁。如果一个接口的参数比较多,以后可能会经常变化,为了方便扩展和兼容,参数会被封装成一个类结构,记得还要给每个字段一个完整的注释说明。类重用噩梦单参数类结构下,经常看到多个功能差异明显的接口频繁重用一个结构,甚至接口参数和返回值重用一个DTO。为了保证兼容性,他们必须在同一个DTO中不断增加字段,随着时间的推移会增加维护成本。这是一个不合理的类设计。如果遵循专注的原则,在很多情况下是可以避免这个问题的。兼容性当接口逻辑或参数发生变化时,需要保持与旧接口的兼容性。这是更改API时必须遵循的原则之一,必须通过接口测试来验证兼容性。您要添加新界面吗?当面对新的需求时,为了避免直接修改旧接口,一些开发者会统一提供一个新接口。如果逻辑上没有重大变化,这将改进API。维修费用。如果后期不重构API,新增加的维护成本将远远大于初期节省的开发成本。比如我们需要对某个参数添加有效验证,那么我们需要修改两个接口的API实现,而且是重复的代码,我们的影响范围变成了两个接口,所以扩大范围影响也带来了更多的潜在风险。当然,在接口逻辑大调整、API重构等场景下,更好的做法是提供新的接口,推动服务消费者使用新的API,最后让老的API慢慢下线。为了遵循简单和重点的原则。完善的测试单元测试,完善的单元测试可以保证代码的健壮性,在编码阶段提前发现并解决潜在的bug,单元测试是一个开发者必备的能力。界面和场景测试。接口测试包括内部逻辑验证、异常输入、并发场景下单个接口的验证。开发者要对API进行完整的逻辑验证,需要构建完整的测试数据(通常包括scheme.sql和data.sql文件),尤其是基础业务,在一些复杂的业务场景下需要组合多个接口来完成一个场景测试,并对中间数据和输出进行Assert和确认,这也会编写一定的测试代码维护成本需要开发人员权衡利弊。注意文档。好的注释和文档可以减少大部分与服务消费者的沟通工作,也可以避免一些错误的接口调用。没有人愿意每次都在IM工具上浪费大量口水或者需要面对面询问如何正确使用API,也没有开发人员愿意每天重复回答如何调用提供的接口。对于接口文档,可以简单的像Javadoc,也可以通过wiki集中管理,可以是markdown文档,还有很多开源系统,比如Swagger、yapi、eolinker等;微服务架构大大加强了通信成本也是微服务架构的劣势,但合理使用工具可以减少不必要的通信。总结作为微服务之间的桥梁,API的设计和维护是微服务架构中非常重要的环节。每个开发者不仅需要良好的代码规范,更需要建立并遵守API设计规范。API设计能力作为微服务架构中软实力的一部分,需要开发者有一定的设计经验积累。同时,只有不断的思考和总结,才能达到更深层次的认识。