网站首页 日常浏览正文

高可用、高性能? 接口设计的 16 个原则

接口设计需要考虑哪些方面

  1. 接口的命名。

  2. 请求参数。

  3. 支持的协议。

  4. TPS、并发数、响应时长。

  5. 数据存储。DB选型、缓存选型。

  6. 是否需要依赖于第三方。

  7. 接口是否拆分。

  8. 接口是否需要幂等。

  9. 防刷。

  10. 接口限流、降级。

  11. 负载均衡器支持。

  12. 如何部署。

  13. 是否需要服务治理。

  14. 是否存在单点。

  15. 接口是否资源包、预加载还是内置。

  16. 是否需要本地缓存。

  17. 是否需要分布式缓存、缓存穿透怎么办。

  18. 是否需要白名单。

当我们设计接口,我们或多或少都会有上面列举的一些考虑,我们只有想的更多才能让让我们的接口更加完善,我个人觉得100%完美的接口是不存在,只有适合才是最重要。

接口设计原则

原则一:必须符合Restful,统一返回格式,约定业务层错误编码,每个编码可以携带可选的错误信息。

原则二: 命名必须规范、优雅。

原则三:单一性。

单一性是指接口要做的事情应该是一个比较单一的事情,比如登陆接口,登陆完成应该只是返回登陆成功以后一些用户信息即可,但很多人为了减少接口交互,返回一大堆额外的数据。

比如有人设计一个用户列表接口,接口他返回每一条数据都是包含用户了一大堆跟另外无关的数据,结果一问,原来其他无关的数据是他下一步想要获取的,想达成数据的懒加

原则四:可扩展。

接口扩展性,是指设计接口的时候多想想多种情况,多考虑各个方面,其实我觉得单独将扩展性放在这里也是不妥的,感觉说的跟单一性有点相反的意思,其实这个不是这个意思。

这边的扩展性是指我们的接口充分考虑客户端,想想他们是如何调用的,他要怎样使用我的代码,他会如何扩展我的代码,不要把过多的工作写在你的接口里面,而应该把更多的主动权交给客户程序员。

如获取不同的列表数据接口,我们不可能将每个列表都写成一个接口。 还有一点,我这里特别想指出来的是很多开发人员为了省事(姑且只能这么理解),将接口设计当成只是 app 页面展示。

这些人将一个页面展示就用一个接口实现,而不考虑这些数据是不是属于不同的模块、是不是属于不同的展示范畴、结果下次视觉一改,整个接口又得重写,不能复用。

原则五:必须有文档。

良好的接口设计,离不开清晰的接口文档表述。文档表述一定要足够详细

原则六:产品心。

为什么我说要有产品心?因为我觉得很多人忽略了这一点。我来说一下假如开发一个app,如果一开始连个交互文档给你都没有的话,你怎么设计接口?

所以我觉得作为一个服务端后台开发人员应该要有产品心,特别是对于交互文档应该好好理解,因为这些都会对我们的接口设计有很大的影响。

我在设计接口的时候就很常发现很多交互文档根本就走不通,产品没有考虑到位,交互文档缺失,这时候作为一个开发要主动推动,完善。

原则七:第三方服务接口数据能缓存就缓存。

原则八:第三方服务需要做降级。

原则九:建议消除单点。

原则十:接口粒度要小。

原则十一:客户端能处理的逻辑就不要给服务端处理,减少服务端压力。

原则十二:资源预加载。

原则十三:不要过度设计。

原则十四:缓存尽量不要穿透。

原则十五:接口能缓存就缓存。

原则十六:思辨大于执行

个人小分享

1)接口Restful,统一返回格式,约定业务层错误编码,每个编码可以携带可选的错误信息

在前司,客户端和服务之间是有统一的数据返回格式,约定各层的编码,可以通过编码位数以及编码就可以看出是那一层出问题。

我觉得这对我们定位问题以及维护来说具有莫大的意义,并对异常也进行捕捉,封装成对应的 code,我之前阅读一些人的代码发现其项目根本没有做这一层,因为简单而不做我觉得有失所望。

2)采用 hybird 模式

采用 hybird 模式涉及到资源预加载的问题,在很多项目里面都大量使用,譬如前司的生活服务,就采用了 hybird 模式,先将资源文件(包含图片、前端页面)打包放到服务器并通过版本号进行管理,并通过一个总的配置文件来管理,如果是H5页面可以进行模板预先设计,down到本地。

配置文件格式:


  *文件1*        name:xxx        url:http:xxxx        md5:xxxx   *文件2*        name:zzz        url:http:zzzz        md5:zzz

客户端每次启动应用或者定时请求总的配置文件,通过http code是否是304判断是否需要下载这个总的配置文件,如果code是200,那么下载这个配置,比较那个文件发生变化,并将其下载。这样的好处:

  1. 减少接口的交互;

  2. 资源预加载,节省流量,打开页面更加流畅,对于服务端来说字需要返回数据json串就行,而不需要其他,减少服务端压力;

  3. 方便开发人员,资源管理更加简洁,比如做活动需要的h5页面,只需要前端上传对应的h5资源包到服务端,不需要通过后端开发人员就可以搞定。

虽然这个原理很简单,但是现在很多app还是没有做这个,都是通过填写一个url,加载网页的方式去打开,体验性太不友好。

3)客户端

客户端跟服务端就是接口请求的关系,很多时候需要要求客户端做一些数据缓存的工作以及一些检验工作。在前司已经好几次给客户端的同学坑过了,客户端同学接口乱调用,死循环调用。

一次是做一个关于事件提醒的功能,需要每天定时调用调用服务端一个接口,结果客户端的同学写了一个 bug 导致请求每隔一两秒就调用一次,导致服务器这边此接口 pv 翻了N倍,而且这个 bug 通过测试同学很难测试出来;

还有一次发现服务端一段时间以后 UV 不见涨,但是PV却涨的很猛,定位发现是客户端同学A图省事在一个方法里面调用了N个接口,也就是模板方法。

因为版本更新,同学B需要做一个新的功能,然后也调用了A同学的接口导致,从而导致PV上升,其实B同学完全不需要调用这么多接口。这些都是真实案例,所以这里需要有一个监控接口异常的机制。

4)思辨大于执行

写到这里觉得这个非常重要,思辨大于执行,意味着我们不是一股脑就去干,也不是不去干,我们做事情需要思考、辨别;从而让事情更高效、更好、更有力的执行。接口设计也一样,需要我们去思辨。

5)本地缓存、分布式缓存以及异步

缓存在前司主要分为客户端缓存、CDN缓存、本地缓存(guava)、Redis缓存。

在MZ早期是接口是采用 DB+本地缓存的方式提供数据,但这种模式DB压力大,接口吞吐量小,本地缓存多机难一致性、更新不及时问题。

为了解决这些问题,引入分布式缓存,并通过 Task 将业务数据刷到 Redis,接口只访问 redis,不会访问 DB,及时 DB 故障也不会影响功能。

不同的业务系统系统通过 MQ 来解耦,多机房不是通过 MQ 来实现数据的一直。

比如,评论,先通过写 Redis,写 MQ 来实现数据在多机房同步,再通过 task 将 Redis 中评论同步到 DB 中。

接口设计涉及方方面面,这边也只谈到一个大概,虽然有点泛泛而谈,希望此拙文对你有所启示。

6)数据库

数据库分库分表,一般都是通过 userId 或者 imei 或者 mac 地址来分表,单表数据量控制在500w以内,这需要我们提前估算好数据量,尽量避免数据的迁移。

在前司,数据库一般都是采用 mysql+MongoDB 两种,MySQL存储用户的用户数据,MongoDB 存储业务数据,就像阅读和生活服务里面的业务数据就存储在 MongoDB 里面。

在数据库这层,我们主要也是通过主从模式、读写分离、分库、分表来实现数据的可用性。

7)业务

业务尽可能拆分、独立部署、将项目按业务划分、按功能划分等。譬如生活服务,我们当时主要拆分成管理后台 admin、任务 task、活动、web、数据展示模块。

8)数据中心

每个大一点的公司都有数据部门,我们这边可以通过数据中心的数据分析来达到我们需要的数据。

比如黑名单,推广效果、活动数据。我们可以通过这些完善我们的接口功能。之前在前司做了个数据处理后异步加载到 Redis 来实现数据利用的项目。


还没有人评论?赶快抢个沙发~

发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。