真正对外提供服务的代码需要关心的除了核心业务逻辑之外,就是如何处理错误了。即便是单一服务也存在着不少外部依赖,微服务之后种种依赖项就更多了。只保证核心业务逻辑实现正常是不够的,更需要细致去考虑如何应对各种错误。自己并没有想到有什么一劳永逸的办法,但认识到这一问题具备这样的意识总是没错的。

逃不开的“墨菲定律”,凡是可能出现问题的都会出现问题。如果编码的时候就隐约感觉到某部分可能出问题,那大概率一定会发生,但更多的问题是编码时候没有意识到的。如果可以无脑的按照某种思路步骤一步步去考虑应对,相对来说系统的可用性可能可以得到改善。

主动处理外部依赖异常

首先要解决外部依赖问题,不管是数据库、缓存还是下游RPC,代码调用的这些服务都可能异常或者超时。这些依赖调用地方都要做好异常处理,有网络请求的都需要设置超时时间,避免被拖垮。

外部依赖的破坏性测试

不论是手动触发真正的依赖故障,还是依托故障注入的手段。对于外部依赖处理需要通过破坏性测试去进行验证。如果已经有方便的框架流程可以自动跑当然好,没有的话也需要手动去进行验证。只有实际测试过才能够验证上面异常处理的正确性。

预埋依赖隔离开关

很多时候除了对依赖异常进行处理,还可以考虑预留开关在其出现问题的时候进行手动隔离。依赖隔离肯定是有损的,但有损肯定也比服务不可用强得多。

尽可能多的使用配置下发机制

有时候触发问题是因为一些配置项参数设置不合理,比如不合理的超时时间、不合理的重试次数等,能下发的配置最好都进行下发。这样有问题的时候可能可以通过配置变更救回。

关键路径的单元测试覆盖

单元测试不要去追求全局覆盖率,但是关键路径还是要去完善的。否则功能本身的正确性无从验证,后续代码变更就更提心吊胆了。核心功能要覆盖测试,一些兜底处理策略也要覆盖测试,否则预留的后手可能根本不能生效。

关键路径包含哪些呢?放在可用性层面的话,那就是一些开关控制逻辑,资源初始化与清理逻辑,配置变更下发响应逻辑。

性能测试

性能测试往往也是能够发现问题的。比如线程池参数设置不合理,高并发访问很容易导致线程池资源耗尽。性能测试利于发现此类问题。性能测试最好能自动化、常态化。

灰度上线验证

代码上线最好也是一步步来,时间不紧急的话,小规模灰度看效果,再逐步放开。有的时候过于乐观自信容易导致问题,还是稳妥一点比较好。

总结

写bug虽然免不了,但要把bug的影响范围控制住。在微服务场景中,除了业务功能之外,还要注意保护服务自身、避免拖累其它服务。如上这些手段策略一定程度上可以帮助实现这一目标,当然最为重要的还是编码本身了。如何写出正确的代码,那又是另外的问题了。