记提高服务接口可用性、稳定性注意事项总结
一、背景
到新公司有一段时间了发现公司的服务接口设计的过于复杂、易用性方面也不太方便,结合以前的经验做些调整优化,以此记录遇到的注意事项。
我们知道服务接口API使用方式:1、被使用方使用 2、依赖于别的服务接口 3、既被使用方使用又依赖于别的服务接口。要提高服务的可用性、稳定性,会涉及到业务应用系统的分布式架构缓存、数据库等多方面,本文只从服务接口api层面讨论。在实际的操作过程中发现和《如何避免故障?》很多处理方式不谋而合。那么从上面三种使用场景讨论具体的处理策略。
二、被使用方使用场景
1、服务接口api参数易用性
参数定义:定义具有明确含义的参数名称,实际情况中发现竟然还有o、p的参数。
参数的类型:每一个参数明确的数据类型,不要清一色的String而尽量给每一个参数定义不同合适的数据类型,避免api方法的误用和减少了数据类型的转换。
参数的数量:服务接口api中参数个数不宜太多,如果个数太多那就建议使用参数类吧。在实际情况中有七八个参数,使用参数类是不是清爽的很多。
2、服务接口api良好的使用说明
参数的使用说明就不再赘述了。着重说下下面情况:
参数有传参中文:某些情况下我们的接口会传参中文,中文参数就会有编码要求UTF-8,GBK,如果不约束具体的编码,可能接口就会有乱码甚至保存异常。如ERROR 1366 (HY000)
无分页:某些业务逻辑中无分页,但默认情况下要返回前N条数据,如果没有说明就会造成使用方的困惑。实际中我们的一个接口默认提供前12条数据,而使用方知道数据不止12条,徒增沟通时间成本。
有分页:定义好默认一页记录数,还是允许使用方自行定义返回记录数。根据业务场景还是要约束一页记录数,避免数量过大而影响性能。
因此我们要对接口api制定详细的良好的使用说明。
3、服务接口api异常信息
明确详细的异常信息在调试api快速定位解决问题的利器了,因此我们必须设计良好的异常信息,以便自己记录和提供给使用方参考。
- 参数检验异常
为了服务接口的安全,我们都会把参数做校验及转换。如参数id是整型类型的 id=81 我们就会做整型类型的校验,如果不是整型的就会返回参数id必须是整型的提示信息及自定义的错误代码。
- 业务逻辑异常
在内部处理业务逻辑时,如果出现异常我们也要将记录相应的异常信息及自定义的错误代码,而不能只给使用方提示服务器发生错误这样信息。估计看到这样的信息会抓狂,我们的目的是当使用方拿到错误代码对照接口api使用说明就会很快定位到问题所在。
我们可以定义异常信息格式:
{
"requestId" : 1001, "code" : 1024, "message" : "Paramters Validation Failed", "errors" : [ { "code" : 5432, "field" : "tkey", "message" : "Required argument tkey: expect [type: java.lang.String]" }, { "code" : 5622, "field" : "token", "message" : "token cannot be blank" } ] }
4、服务接口api粒度
在设计接口api时,api粒度不宜过细也不宜过粗,根据具体的业务逻辑进行设计。过细的话不仅api性能差也会徒增服务器压力。如获取某个专辑信息及其中的视频信息,我们实际中只有获取某个专辑信息的接口和专辑中的视频信息的接口。和同事讨论才得知当时按照“单一职责”原则进行设计的。能够按照“单一职责”原则进行设计固然是好,但是也不能太死板应该在原则下灵活变通。现在我们在增加一个接口api(同时返回某个专辑信息及其中的视频信息)性能是不是会优于上述两种接口组合使用哪?
5、服务接口api版本演进或版本控制
随着业务的发展,老的接口api已不能满足新的业务逻辑,此时是改造老的接口还是增加新的接口?如果在老的接口中进行改造来支持新的业务逻辑,但是不得不维护老的业务逻辑,无形中增加工作量和难度。实际中我们可以新增加接口api,老的api和新的api同时提供服务,然后将老的api平滑过度到新的api。
我们可以定义api版本格式
/ms/api/v2/...
6、服务接口api业务功能降级
我们先来看下视频网站一部影片都会有那些相关数据?
一部影片都会有影片正片信息和影片相关的视频片段(预告片、花絮等)
我们就可以有以下的处理思路:
- 设置降级开关
- 当合法的请求量瞬间爆满,服务接口api的性能严重下降时,自动或手动打开降级开关至返回影片的正片信息,而相关片段(周边视频)就可以暂时不返回数据
- 当服务器压力减弱时,关闭降级开关在返回相关片段(周边视频)数据。
7、服务接口api限流
服务接口api的降级和限流都是流量控制的处理策略,同时也是系统的自我保护策略。虽然牺牲了一部分业务功能和高并发量,但换来的系统的可用性。
限流请参看之前的文章《服务接口API限流 Rate Limit》。
三、依赖于第三方服务接口场景
1、设置合理的超时时间
如果超时就应该断掉请求连接,把业务处理的线程让给别的请求,加快处理同时也减轻了所依赖服务的压力。
2、合理使用重试机制
根据所依赖服务接口返回的信息合理的使用重试机制,如果所依赖的服务返回业务处理异常在使用重试机制也毫无意义,只会徒增所依赖服务器的压力。
3、异步调用服务接口
我们的服务接口中都会穿插着业务逻辑,如果使用httpsyncclient异步调用服务接口数据,此时处理自己的业务逻辑在结合异步返回的数据组织最终的业务数据。从而提高了服务接口处理能力。
4、依赖服务接口
如果所依赖的服务接口crash,那么自己的服务接口也无法正常提供数据。
根据依赖的服务接口数据的时效性,做出相应的处理策略:
a、数据时效性不高,可以对依赖接口返回的数据做缓存处理。通过定时任务刷新缓存数据或者定义缓存数据失效时间等方式。
b、数据时效性非常高,对于这种情况 --- 痛点。 如果您有好的处理策略请指点。
四、接口调用过程异常处理
1、接口调用过程异常原因
- 通讯框架异常
a、网络通讯错误
系统错误会导致无法预测的异常产生,还的具体取决于RPC服务的实现方式。对于这种错误,唯一的处理方式只有:另外找时间或机会重试
- 业务系统异常
a、系统错误
服务应用在处理内部逻辑时出现了无法控制的错误,常见场景:
-
- 网络访问失败
- 数据库访问失败
- 文件写入失
一般这种错误,采用重试机制就能很好得到解决。
b、业务错误
调用方传递了违背业务规则的参数从而导致了业务处理失败。
2、接口调用过程异常处理
- 定义自定义异常
这个异常主要用于收缩和屏蔽服务层的具体错误信息,当服务端遇到无法处理的错误情况时,需要继续向客户端外抛,让客户端来择机进行重试。客户端亦可通过SelfException快速判断当前业务中断的原因来自于SelfService的失败。
我们可以在返回的结果中增加isReTry,来告诉调用方服务接口是否需要重试机制。
五、总结
合理的服务接口设计和良好的服务接口使用,都会提高服务接口可用性和稳定性、易用性、健壮性。
服务接口异常处理解决方案:
调用情况 | isSuccess | errorCode | isReTry | throw SelfException | throw Exception | 调用方处理 |
框架异常 | / | / | / | true | 重试 | |
系统异常 | / | / | true | / | 重试 | |
业务异常 | false | true | true | true | / | 重试 |
业务异常 | false | true | false | true | / | / |
成功返回 | true | false | / | / | / | / |
参考延伸阅读:http://www.cnblogs.com/LBSer/p/4753112.html
由于本人经验有限,文章中难免会有错误,请浏览文章的您指正或有不同的观点共同探讨!
作者:三石雨
出处:http://www.cnblogs.com/exceptioneye
再烦,也别忘微笑;再急,也要注意语气。
再苦,也别忘坚持;再累,也要爱自己。
低调做人,你会一次比一次稳健;高调做事,你会一次比一次优秀。