前两天看了下Sentinel(分布式系统的流量防卫兵)。网上各种吹捧说简单、开箱即用。然后研究一下,嗯......确实开箱即用,而且上手简单。然后话不多说,立马整一套环境,集成Nacos、Feign上来就是干!但是中间还是遇到了一些问题,先说下我的细节场景:
-
我定义了一个服务者(provider)并且提供了Feign客户端调用。
-
在服务熔断的Feign客户端实现类中抛出了异常。如下图:
Feign客户端接口:
Feign实现类(自定义fallback函数):
-
我在消费端(consumer)配置了全局异常处理器,然后调用服务端的Feign接口。可是在出现服务熔断即服务端down机的时候,我的消费端总是捕捉不到我自定义的这个ServiceException异常.
看下我的全局异常处理器
经过冥思苦想,然后跟踪Sentinel源码终于找到了问题原因。并且总结出经验:
- Feign的接口调用端的自定义fallback函数中尽量避免抛出异常。
下面说下为什么我们尽量避免在自定义的fallback中抛出异常
-
当使用Fegin接口远程调用服务者出现异常情况的时候,会走fallback中的逻辑。
-
我们模拟服务端down机。:
-
我们先看下SentinelInvocationHandler 这个类的这段代码。
如果 我们的服务端没响应或者网络延迟或者其他未知情况导致methodHandler.invoker() 方法没有正确返回,则抛出异常。也就是调用FeignClient过程中出现了异常。如果我们自定义了服务熔断的fallback方法,则会执行我们的fallback方法。
下图是模拟服务者down掉的情况,进入到 catch 代码段,校验我们有没有自定义的falback逻辑,有的话则执行
执行到我们自定义的fallback逻辑。然后我写的是依然抛出异常,打算交给全局异常处理器处理:
此时如果在fallback中依然抛出异常的话。SentinelInvocationHandler 这个类会把这个异常当成一个Error抛出。
此时我的全局异常处理器就不能把这个异常当做我们自定义的ServiceException处理,而是把它当成了Throwable处理。这样会导致我们排错的时候找错方向,因为我明明抛出的是ServiceException怎么最后变成Throwable了?。
-
总结:
- Sentinel集成Feign调用的时候,在服务熔断的fallback中尽量避免抛出异常,最后会被Sentinel当做一个Throwable处理。最好正确返回一个我们可识别的一个结果,在返回结果中表明调用异常即可。
- 使用Sentinel写个demo很简单。但是企业中使用Sentinel还是需要自己对源码进行一些调整的。
- 比如集成Nacos实现持久化的时候。这儿也有个坑,可能是Sentinel的bug。简单说下吧就是当在Sentinel控制台添加流控规则并且持久化到Nacos中去的时候,只能添加一个资源,再次添加资源的时候会把上一个覆盖掉。准备在issues上提一下
- 想要在企业中使用Sentinel我感觉必须得把源码拉下来,跑一下。