通用能力抽象选择SDK组件还是API服务?
大型的后端服务,当需要把一部分通用能力抽象出来,通常有两种方式:SDK组件或者API服务。
对于有Java分库分表经验的同学来说,这两种形式的选择类似于Sharding-JDBC和MyCat的选型:前者作为client层方案类似于SDK;后者提供了proxy层类似API的服务。
关于Sharding-JDBC和MyCat的选型感兴趣的同学,可以查看小辉之前的博客《一文了解数据拆分与分库分表》
无论是SDK组件还是API服务,起初可能是一个人或者一个小组使用,随着版本迭代和人力投入,影响力和对接方越来越多,这过程中存在两个角色:提供方和使用方。因为不同的角色对于通用能力的诉求是不完全一样的,本文会分别从这两个角色进行讨论。
简单介绍下概念:
SDK:软件开发工具包(全称:Software Development Kit)。一般是指软件工程师为特定的软件包、软件框架、硬件平台、操作系统等建立应用软件时的开发工具的集合。例如Java工程常用maven或gradle引入的依赖组件,Go工程中go.mod指定的依赖组件。
API:应用程序编程接口(全称:Application Programming Interface)。一般是指一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。API的定义比较宽泛,本文狭义的认为API为后端的微服务,提供远程rpc服务。
两种方式的优缺点区分如下:
- | 优点 | 缺点 |
---|---|---|
SDK组件 | 不用单独部署,运维成本低,不需要作为代理层进行二次转发,性能更优 | 如果需要升级,则需要各个系统都进行部署或者做版本隔离;各个系统耦合SDK的依赖,对于复杂庞大的逻辑不友好。 |
API服务 | 系统升级的时候只需要API服务自己进行兼容升级即可,生效速度快 | 需要部署和运维一套服务,运维成本高。下游依赖需要API服务做路由,多了一次网络跳转。 |
无论是SDK组件还是API服务,对于提供方的原则:
任何代码变动都需要兼容老版本,不可以升级后对相同输入产生了不同的输出,
代码结构最好进行足够的抽象和提供拓展的接口,以便代码变更尽可能的满足开闭原则。
讲述完优缺点和原则,再结合项目中的问题讨论下。
细节讨论
1. SDK运维成本低?API服务运维成本高?
SDK运维成本低这个优点只在SDK使用方和下游是同一个团队的场景才更准确。如果你是SDK的提供方,使用方是其他团队,如果SDK包含有下游依赖。当SDK使用方有大型活动、流量有徒增或扩容的要求时,SDK包含的下游是需要扩容的。这个扩容操作时SDK使用方来负责沟通呢,还是SDK的提供方来沟通呢?这就存在协作边界的模糊性。而且SDK提供方需要维护好调用下游的名单以及频次,成本也是有的。
而对于API服务运维成本高的问题,如果是小团队协作,确实API服务会增加一个微服务和配套的devops,相比SDK组件有更高的成本。但是对于成熟工具链的团队,新增服务会很容易。相对应的好处是,API服务接入可以将流量评估收口到API服务的提供方,更容易控制好风险。
2. SDK的升级成本高?
当SDK使用方越多、迭代越频繁,升级成本越高。举个栗子,SDK对于一个通用函数进行了修改并发布,部分服务升级SDK后发现该版本SDK有隐藏bug,接下来所有使用方团队需要扫描使用该版本SDK的服务然后进行SDK升级。相对来说,API服务只需要提供方静默升级即可。
3. 各个系统耦合SDK的依赖,对于复杂庞大的逻辑不友好?
这句话的前提是SDK随着功能迭代变得越来越臃肿,就会出现这种问题,使得引入SDK就间接引入了很多依赖,增加编译时间也增加依赖管理的问题。
4. 如果要支持第三方定制化的能力,复杂度会如何?
如果你是SDK提供方,你完全可以将一些逻辑通过模板设计模式写出来,将过程中的变量或函数,通过多态以及接口的形式暴露出去。这样的话,作为SDK使用方,需要定制化的话,只需要在自己的服务本地进行定制重写即可。
但如果你是提供API服务,对于定制化的服务,需要让使用方mr到你的服务代码或者你去实现定制化。这其中就涉及到服务保密性的问题,如果是非开源服务、使用方是外部用户的话,那大概率是不能提供mr的权限了。这样新功能的开发负担就转移到了提供方。
无论是提供SDK组件还是API服务,都需要进行合理的逻辑抽象,让使用方尽量可以满足开闭原则的基础上去增删代码。
5. 服务鉴权问题
背景:在一些大型互联网公司,下游服务对于它的上游服务是有白名单限制的。此外,对于API使用方是公司外部的用户,在网关层可能也需要设置流量白名单。
对于服务提供方来说,如果使用方无论是公司内部的还是公司外部的,都需要考虑服务鉴权问题。
如果你是SDK提供方,使用方新接入SDK,他并不清楚下游会有哪些,如果自测阶段不充分,很有可能有部分流量走到了没有申请鉴权的下游服务,这样会造成一定的困扰。你需要提供友好的说明或者承担这部分工作。
如果你是API服务提供方,使用方新接入API,只需要配置一个白名单即可。这方面API服务就要比SDK组件轻松很多。
6. 接入友好问题
对于提供方来说,无论SDK组件还是API服务,完善的使用文档都是必要的。
如果使用方是公司内部的,两种服务的接入友好差不多(前提是API服务不需要token鉴权)。
如果使用方是公司外部的,对于用户来说,SDK的接入方式更友好,只需要从多租户平台设置自己的秘钥,然后SDK就可以开箱即用。相对来说API服务就需要自己按照文档步骤生成token鉴权,管理各种api接口的uri路径以及创建各种请求/结果参数的对象结构。
总结
以下仅为小辉个人使用体验。
作为提供方,对于公司外部的服务接入,更倾向于API接入方式。选择API可以方便系统升级,迭代周期可以更自由。
作为提供方,对于公司内部的服务接入,两种方式需要结合对服务未来的规划、人力的规划等等来决定。
作为使用方,对于公司外部的服务接入,更倾向于SDK接入方式。前提是SDK的依赖不会过于臃肿、SDK功能稳定不会有被经常通知强制升级的情况。
作为使用方,对于公司内的服务接入,两种使用方式均可。哪个形式更省心哪个就更优。
以上讨论的使用方,都是以用户的视角来讨论的。
用户指的是直接使用SDK的开发同学
客户指的是技术选型或预算控制的开发同学或技术经理
这里提一下客户要关注的。
作为要选择三方服务的客户来说,用户的体验当然很重要,会影响兄弟们的工作效率和激情。此外,还要考虑的是不同的三方服务的服务稳定性、功能的完整程度(二次开发的成本)、套餐价格、问题响应速度、口碑等。
三方服务选型要慎重再慎重,因为后续想要更换三方服务的成本可能会很大。