1.怀疑第三方
有兜底最好业务降级方案
如果第三方服务挂掉怎么办?我们业务也跟着挂掉?显然这不是我们希望看到的结果,如果能制定好降级方案,那将大大提高服务的可靠性。举几个例子以便大家更好的理解。
遵循快速失败失败原则,一定要设置好超时时间
保护第三方 慎重选择重试机制
2、防备使用方
设计一个好的api,避免误用
a) 遵循接口最少暴露原则
使用方用多少接口我们就提供多少,因为提供的接口越多越容易出现乱用现象,言多必失嘛。此外接口暴露越多自己维护成本就越高。
b) 不要让使用方做接口可以做的事情
如果使用方需要调用我们接口多次才能进行一个完整的操作,那么这个接口设计就可能有问题。比如获取数据的接口,如果仅仅提供getData(int id);接口,那么使用方如果要一次性获取20个数据,它就需要循环遍历调用我们接口20次,不仅使用方性能很差,也无端增加了我们服务的压力,这时提供getDataList(List<Integer> idList);接口显然是必要的。
c) 适用方能从其他第三方获取的数据,不要给他处理
比如 要获取交易订单列表接口,使用方让给返回会员卡名称 票名称字段,最后核心交易,我也要从依赖第三方区获取这些数据,那就让使用方自己去调用拼接这些数据
c)避免长时间执行的接口
还是以获取数据方法为例:getDataList(List<Integer> idList); 假设一个用户一次传1w个id进来,我们的服务估计没个几秒出不来结果,而且往往是超时的结果,用户怎么调用结果都是超时异常,那怎么办?限制长度,比如限制长度为100,即每次最多只能传100个id,这样就能避免长时间执行,如果用户传的id列表长度超过100就报异常。
加了这样限制后,必须要让使用方清晰地知道这个方法有此限制。之前就遇到误用的情况,某用户一个订单买了超过100个商品,该订单服务需要调用商品中心接口获取该订单下所有商品的信息,但是怎么调用都失败,而且异常也没打出什么有价值的信息,后来排查好久才得知是商品中心接口做了长度限制。
怎么才能做到加了限制,又不让用户误用呢?
两种思路:1)接口帮用户做了分割调用操作,比如用户传了1w个id,接口内部分割成100个id列表(每个长度100),然后循环调用,这样对使用方屏蔽了内部机制,对使用方透明;2)让用户自己做分割,自己写循环显示调用,这样需要让用户知道我们方法做了限制,具体方法有:1)改变方法名,比如getDataListWithLimitLength(List<Integer> idList); ;2)增加注释;3)如果长度超过 100,很明确地抛出异常,很直白地进行告知。
d)参数易用原则
避免参数长度太长,一般超过3个后就较难使用,那有人说了我参数就是这么多,那怎么办?写个参数类嘛!
此外避免连续的同类型的参数,不然很容易误用。
能用其它类型如int等的尽量不要用String类型,这也是避免误用的方法。
e)异常
限流
3、做好自己
3.1 单一职责原则
对于工作了两年以上的同学来说,设计模式应该好好看看,我觉得各种具体的设计模式其实并不重要,重要的是背后体现的原则。比如单一职责原则,在我们的需求分析、架构设计、编码等各个阶段都非常有指导意义。
在需求分析阶段,单一职责原则可以界定我们服务的边界,如果服务边界如果没界定清楚,各种合理的不合理的需求都接,最后导致服务出现不可维护、不可扩展、故障不断的悲哀结局。
对于架构来讲,单一职责也非常重要。比如读写模块放置在一起,导致读服务抖动非常厉害,如果读写分离那将大大提高读服务的稳定性(读写分离);比如一个服务上同时包含了订单、搜索、推荐的接口,那么如果推荐出了问题可能影响订单的功能,那这个时候就可以将不同接口拆分为独立服务,并独立部署,这样一个出问题也不会影响其他服务(资源隔离);又比如我们的图片服务使用独立域名、并放置到cdn上,与其它服务独立(动静分离)。
从代码角度上讲,一个类只干一件事情,如果你的类干了多个事情,就要考虑将他分开。这样做的好处是非常清晰,以后修改起来非常方便,对其它代码的影响就很小。再细粒度看类里的方法,一个方法也只干一个事情,即只有一个功能,如果干两件事情,那就把它分开,因为修改一个功能可能会影响到另一个功能。
3.2 避免单点
不要把鸡蛋放在一个篮子里面,要做好服务多机房部署,异地多活,服务应该做到水平的扩展
对于数据来说避免单点就是 通过分片 分层的方式
最近我们公司atop出了一次故障,导致用户中心,联动等都大量超时报警,最后排查到是因为我们的base服务的多语言 缓存存在大value的问题,导致把连接打满,cpu飙升,内存使用率升高,因为其他服务也依赖base服务,但是其他接口大量的超时
解决方案 ,临时加机器,马上最大value的拆分工作,等平稳下来再把机器下掉
将大value拆分小value,mget的方式获取
也有存在缓存热点问题,80%的请求读到20%的资源
将热点数据放到本地缓存
将热点key 随机,避免单个热点key一直打到一台服务上