我们可以发现在之前的 Sentinel 资源名都是请求路径,我们可以使用 @SentinelResource 注解的 value 属性来自定义资源名称。第二个我们也发现我们没有写兜底方法,但是在违反 Sentinel 配置规则时,依然会有兜底方法,这个是 Sentinel 默认的。我们可以使用 @SentinelResource 注解的 blockHandler 属性来指定配置规则的兜底方法。第三个就是方法在抛出异常且未违反配置规则要求时,是不会熔断降级而是直接抛出异常,我们可以使用 @SentinelResource 注解的 fallback 属性来给异常加一个兜底方法。
属性 | 描述 |
---|---|
value | 资源名称,必需项(不能为空) |
blockHandler / blockHandlerClass | blockHandler 对应处理 BlockException 的函数名称,可选项。 ♞ blockHandler 函数访问范围需要是 public; ♞ 返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。 ♞ blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。 |
fallback / fallbackClass | fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求: ♞ 返回值类型必须与原函数返回值类型一致; ♞ 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。 ♞ fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。 |
defaultFallback(1.6.0 开始) | 默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback 函数签名要求: ♞ 返回值类型必须与原函数返回值类型一致; ♞ 方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。 ♞ defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。 |
exceptionsToIgnore(1.6.0 开始) | 用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。 |
entryType | entry 类型,可选项(默认为 EntryType.OUT) |
1.8.0 版本开始,defaultFallback 支持在类级别进行配置。
注:1.6.0 之前的版本 fallback 函数只针对降级异常(DegradeException)进行处理,不能针对业务异常进行处理。
/**
* Created with IntelliJ IDEA.
*
* @author Demo_Null
* @date 2020/11/18
* @description
*/
@RestController
@RequestMapping("/provider")
public class ProviderController {
@GetMapping("/find")
// 此种方式只会处理配置降级不会处理业务异常
@SentinelResource(value = "providerFind", blockHandler = "blockHandler")
public Object find() {
return "provider";
}
public Object blockHandler() {
return "配置规则降级";
}
}
/**
* Created with IntelliJ IDEA.
*
* @author Demo_Null
* @date 2020/11/18
* @description
*/
@RestController
@RequestMapping("/provider")
public class ProviderController {
@GetMapping("/find")
// 此种方式配置降级使用默认降级,业务异常使用 fallback
@SentinelResource(value = "providerFind", fallback = "fallback")
public Object find() {
return "provider";
}
public Object fallback() {
return "有异常";
}
}
/**
* Created with IntelliJ IDEA.
*
* @author Demo_Null
* @date 2020/11/18
* @description
*/
@RestController
@RequestMapping("/provider")
public class ProviderController {
@GetMapping("/find")
// 此种配置若二者同时满足,只会进入 blockHandler 处理逻辑。
@SentinelResource(value = "providerFind", blockHandler = "blockHandler", fallback = "fallback")
public Object find() {
return "provider";
}
public Object blockHandler() {
return "违反配置规则";
}
public Object fallback() {
return "有异常";
}
}
/**
* Created with IntelliJ IDEA.
*
* @author Demo_Null
* @date 2020/12/1
* @description 以 blockHandler 为例,fallback 同理
*/
public class MyBlockHandler {
// 注意对应的函数必需为 static 函数,否则无法解析。
public static Object blockHandler(BlockException e) {
e.printStackTrace();
return "违反配置规则";
}
}
/**
* Created with IntelliJ IDEA.
*
* @author Demo_Null
* @date 2020/11/18
* @description
*/
@RestController
@RequestMapping("/provider")
public class ProviderController {
@GetMapping("/find")
@SentinelResource(value="providerFind",blockHandlerClass=MyBlockHandler.class, blockHandler="blockHandler")
public Object find() {
return "provider";
}
}
# 激活 sentinel 对 feign 支持
feign:
sentinel:
enabled: true
/**
* Created with IntelliJ IDEA.
*
* @author Demo_Null
* @date 2020/11/5
* @description
*/
@Component
@FeignClient(value = "ProviderServer", fallback = FeignFallBack.class)
public interface ProviderFeign {
// 业务类直接调用该接口即可
@GetMapping("/provider/get/{id}")
public String get(@PathVariable("id") Integer id);
}
/**
* Created with IntelliJ IDEA.
*
* @author Demo_Null
* @date 2020/11/6
* @description
*/
@Component
public class FeignFallBack implements ProviderFeign {
@Override
public String get(Integer id) {
return "降级返回";
}
}
/**
* Created with IntelliJ IDEA.
*
* @author Demo_Null
* @date 2020/10/29
* @description 消费者启动类
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
我们发现,重启服务之后 Sentinel 配置规则消失了,在生产环境中每次都要重新配置那么将是一个灾难,所以我们需要将配置持久化。这里我们选择将配置持久化到 Nacos 中,当然也可以选择持久化到其他地方。推荐持久化到 Nacos 毕竟 Sentinel 与 Nacos 是一家子。
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-datasource-nacosartifactId>
dependency>
[
{
// 资源名称
"resource": "/hello",
// 来源应用
"limitApp": "default",
// 阈值类型,0 表示线程数,1 表示QPS
"grade": 1,
// 单机阀值
"count": 5,
// 流控模式,0 表示直接,1 表示关联,2 表示链路
"strategy": 0,
// 流控效果,0 表示快速失败,1 表示 Warm Up,2 表示排队等待
"controlBehavior": 0,
// 是否集群
"clusterMode": false
}
]
重新启动服务,请求服务让 Sentinel 发现服务之后可以看到,在流控规则中多了一个资源名为 /hello
的规则,这个是从 Nacos 中读取过来的额配置。