Spring Cloud Alibaba一一SentinelResource
SentinelResource
在定义了资源点之后,我们可以通过Dashboard控制台页面来设置限流和降级策略来对资源点进行保护。同时还能通过[**@SentinelResource**](/SentinelResource)****注解来制定出现异常时的处理策略
1、属性说明
- value
资源名称、必须项、因为需要通过resource name找到对应的规则,这个是必须配置的。
- blockHandler
blockHandler对应处理BlockException的函数名称,可选项。blockHandler函数访问范围需要是public,返回的类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为BlockException。
- fallback
fallback函数名称,可选项,用于在抛出异常的时候提供fallback处理逻辑。fallBack函数可以针对所有类型的异常(Throwable)
- blockHandlerClass
blockHandler函数默认需要和原生方法在同一个类中,如果希望使用其他类的函数,则需要指定blockhandlerClass为对应的类的Class对象,注意对应的函数必须为static函数,否则无法解析。
- fallbackClass
fallBackClass的应用和blockHandlerClass类似,fallback函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定fallbackClass为对应的类的Class对象,注意对应的函数必须为static函数,否则无法解析。
2、自定义处理限流和业务异常
@GetMapping("/hello4")
@SentinelResource(value ="hel1o4",blockHandler ="blockHandler",fallback ="fallbackHandler")
public string hello4(Integer age){
int i = 10 / age;
return "hello4";
}
// hel13Handler方法的参数和返回值要和原方法一直,BlockException用来接收原方法的异常
public string blockHandler(Integer age,BlockException e){
return"资源被限流”;
}
//hel13Handler方法的参数和返回值要和原方法一直,Throwable用来接收原方法的异常(这里必须是Throwable用来接收原方法的异常,不能是exception)
public string fallbackHandler(Integer age,Throwable e) {
return"资源出现异常";
}
以上这种方式可以处理资源中的限流和业务异常了,但是发现异常处理类和业务代码耦合了,而且还没办法复用。
3、处理异常类和业务类解耦
@RestController
@slf4j
public class HelloController f
@GetMapping("/hel1o4")
@SentinelResource(value = "hello4",
blockHandlerClass = MyBlockHandlerClass.class,
blockHandler ="blockHandler",
fallbackClass = FallbackHandler.class,
fallback ="fallbackHandler")
public string hello4(Integer age) {
int i = 18 / age;
return "hel1o4";
}
}
public class FallbackHandler {
// 这里的方法必须是静态的,方法参数和返回值要和原方法一致
public static string fallbackHandler(Integer age,Throwable e) {
return"资源出现异常"
}
}
public class MyBlockHandlerClass f
// 这里的方法必须是静态的,方法参数和返回值要和原方法一致
public static string blockHandler(Integer age,BlockException e) {
System.out.println("bolockHanlder age ="+ age +",e="+e);
return"资源被限流”;
}
}
Feign整合Sentinel实现降级
Feign整合Sentinel后不同异常调用不同的处理器来解决异常。
流控异常调用:blockHandler
服务运行时异常调用:fallback
feign调用异常调用:feign降级
1、导入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactIdx
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、FeignFallbackFactory
@Component
public class FeignFallbackFactory implements FallbackFactory<HelloService>(
@Autowired
private HelloServiceImpl helloService;
@Override
public HelloService create(Throwable throwable) {
System.out.println(throwable);
return helloService;
}
}
3、Feign接口
@FeignClient(value = "provider-1",fallbackFactory = FeignFallbackFactory.class)
public interface HelloService {
@RequestMapping("/hello")
public string hello();
}
4、开启sentinel
feign:
sentinel:
enabled: true
5、版本问题
SpringCloud版本和SpringCloudAlibaba版本冲突的问题。
Caused by:at feien.FeignsBuilder.com.alibaba.cloud.sentinel.feign,sentinelcontractHolder.parseAndvalidateMetadajava .lang.AbstractMethoderror:lane/class;)Liava/util/list:
at feignReflectiveFeigsParseHandlersByllame,apply(Reflectivefeign.java:151) feign-(ore-10.7,4,jar:na
at feign,ReflectiveFein,newinstance(ReflectiveFeign.java:49) [feign-core-10.7.4jar:na)
target(feien.ia
core-18.7.4.ar;na7
at or3.sorineframework.coudopenfeien.-strixtareter.tareetHystrixtmeter, ava:33) sorine-cloud-enfee-ore-2.2.2,RELEASE,m2.2.2RELEASE
at r.trmewo.cou.ttr da ertat -
at org.sprineframevwork,cIod.0pfeignFegclietactoryBen-gtTretFeclitFto Bean av282 gprn-coud-Efe-0re-2-22RELEASE.ar:2.2.2ELEASE
am.Co.0 it B- tat 2----S22S
t org.pringframework.beans.atory, support.Fto Beamegistryuprt,0etbjectfrnFtr Ben (to Beamepistry supprtaa71)re-ns-52.4ELEASE5.2.4ELEASE
... 67 common frames omitted
解决方式
自定义一个SentinelContractHolder类,包名和源码保持一致。
packagecom.alibaba.cloud.sentinel.feign;
import feign.Contract;
import feign.MethodMetadata;
import java.util.HashMap;import
import java.util.List;import
import java.util.Map;
public class SentinelContractHolder implements Contract {
private final Contract delegate;
/* map key is constructed by ClassFullName + configkey. configkey is constructed by
* (@link feign.Feign#configKey}
*/
public final static Map<String, MethodMetadata> METADATA MAP = new HashMap<>();
public SentinelContractHolder(Contract delegate) {
this.delegate = delegate!
}
@Override
public List<MethodMetadata> parseAndValidateMetadata(Class<?> targetType) {
List<MethodMetadata> metadatas = delegate.parseAndValidateMetadata(targetType);
metadatas.forEach(metadata -> METADATA MAP.put(targetType.getName() + metadata.configkey(), metadata));
return metadatas;
}
}
Feign调用服务过程中,服务出现故障,如果服务中存在全局异常管理器,会认为这个故障已经被服务处理了,然后返回一个空的对象,feign不会调用自己的降级方法。
sentinel持久化
1、sentinel工作模式
在Sentinel客户端(微服务)中用代码写的配置,在启动后,当有第一次流量进来的时候,会推送给Sentinel-Dashboard;在Sentinel-Dashboard中的配置,会被推送到Sentinel客户端(微服务);默认情况下,不论 Sentinel-Dashboard中的配置还是Sentinel客户端中的配置,都是在内存中的,一点重启,这些变化过的规则就全部消失了。
2、semtinel持久化
在此将规则持久化到nacos中,在nacos中添加规则,然后同步到dashboard中。
1、导入依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
2、在yml中配置nacos信息
spring:
application:
name: sentinel-server
cloud:
nacos:
discovery:
server-addr: 192.168.147.11.8848
sentinel:
transport:
dashboard: 192.168.147.11:8080
port: 8719
eager: true
datasource:
sentinel1:
nacos:
serverAddr: 192.168.147.11:8848
dataId: ${spring.application.name}
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
3、在nacos中添加规则
[
{
"resource":"he11o4",
"limitApp":"default",
"grade": 1,
"count": 5,
"strategy": 0,
"controlBehavior":0,
'clusterMode": false
}
]
- resource: 资源名称
- limitApp: 来源应用
- grade: 阈值类型, 0-线程数 1-qps
- count: 单机阈值
- strategy: 流控模式, 0-直接 1-关联 2-链路
- controlBehavior:流控效果、0-快速失败,1-warm up,2-排队等待
- clusterMode: 是否集群
4、测试
服务启动后,当有第一次流量进来的时候,Sentinel-Dashboard会从nacos中拉取流控信息。