前言
对之前Protocol服务依赖的换电基础数据服务Data服务发布时,单节点故障导致部分电柜ID转换请求调用报错的思考。
故障背景:
相关服务及接口介绍
- Protocol服务
对电柜硬件通过TCP协议上报的数据进行解码成json对象,发送到MQ供业务系统消费;并对业务系统提供SOA接口,将业务系统对柜体的操作参数,编码成TCP字节 Data服务
提供两个SOA接口,接口1将【柜体号】转换成【主板号】,接口2将【主板号】转换成【柜体号】Protocol服务依赖Data服务的接口功能简述
- 每次对电柜下发指令,都要根据【柜体号】调用Data服务,将【柜体号】转换为【主板号】
- 每次电柜上报数据,都要根据【主板号】调用Data服务,将【主板号】转换为【柜体号】
过程
2020-03-27 20:43:45 发布Data服务,共3台服务器,其中一个台由于jar包版本的问题,小概率出现SOA启动异常,导致电柜上报数据时,根据电柜【主板号】查询【柜体号】的部分请求发生异常。
由于电柜定时上报数据较多,虽然是单节点故障还有两台服务正常提供,但依然在短时间内出现大量ERROR请求。
问题解决
由于这个查询是主流程服务,开发相对紧张,在没有分清是单节点故障还是全节点故障时,通过立即回滚,排除冲突jar后重新发布止血,后续重新发布解决问题。
后经基础架构部协助排查,是新引入的 soa-starter-spring-boot
与
历史的 spring-boot-starter-parent
默认的 netty
版本冲突,会小概率的出现 SOA 启动失败
影响范围
本次异常共影响运维端8次扫码换电失败,用户端无影响。
问题总结
之后对此次故障一直耿耿于怀,思考对于核心流程,虽然还有上游还有2/3的服务在正常运行,但难道调到有问题机器时只能任其报错?之前考虑增加本地缓存,但使用缓存有一个问题,即缓存何时过期的处理比较麻烦。
今天再次翻到公司文档中【SOA高级用法-容错和异步调用】,调用方式中有
1. 【failfast:默认的调用方式。快速失败,只发起一次调用,失败立即抛异常。】
那次故障就是使用的此方式,也是默认所有接口的失败方式。看到有”只发起一次调用“失败就抛异常,那想必还有”调用多次失败“时才抛异常的吧,所以吸引我继续往下看
2. 【failover:失败自动切换,当出现失败,重试其它服务节点,所有节点都失败时抛异常。通常用于读操作,但重试会带来更长延迟。】
看到这个,眼前一亮,这个不正是我需要的吗?那次故障就是依赖的Data服务共有3台,其中1台偶发性启发性启动失败,还剩下两台可用,不正可以用这个容错机制进行尝试其他服务吗?
到此,相信那次问题终于有了比较完美和可靠的方案,决定下周开始配起来。
思考
对于发生的问题,一定要多思考,肯定能找到比较完美的解决办法。之前很少接触到RPC的容错机制,面试也经常被问到微服务的降级、容错、CAP原理等,今天终于对一个问题的不懈思考,不满足于问题已解决,而是从刨根问底中正式进入微服务架构中高可用的领域。近两个月自己独自的耿耿于怀终于有了收获。
这次事情也给我另一个教训,如果这个问题能及时和擅长这方面解决方案的同事进行交流,相信也不至于自己这么晚才独自找到近似完美的解决方案,以后遇到类似问题,还是要和有经验的同事多交流,多请教,避免陷于自己的死胡同不能自拔。