除了下载Sentinel控制台之外,sentinel还有javaAPI的方式设置限流降级策略:
限流降级对于OpenFeign和Sentinel整合来说有两种策略:
1.设置ribbon超时时间,调用超时后,自动会降级
(如果不设置,自己测试了一下两个属性默认都是2秒,即不设置则自动使用2秒超时服务降级方案)
#连接服务超时时间为5秒
ribbon.ConnectTimeout=5000
#连接后,处理请求的超时时间为5秒
ReadTimeout: 5000
2其次就是设置Sentinel降级配置,如设置超过平均响应时间则降级
添加以下代码实现降级配置(可以放在启动的main方法里面执行,若放在@Configuration类的静态代码块中执行会注册不了,有bug)
private static void initRtRule() {
List<DegradeRule> rules = new ArrayList<DegradeRule>();
DegradeRule rule = new DegradeRule();
rule.setResource("GET:http://order/getOrder.do");//资源名称
rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);//降级模式,根据平均响应时间降级
rule.setCount(1000);//设置平均响应时间为1000ms
rule.setTimeWindow(10);//设置降级持续时间为10s
rules.add(rule);
DegradeRuleManager.loadRules(rules);
}
说明:当持续进入的5个请求响应时间都超过1000ms,接下来的10s内对这个接口的调用都会直接返回并抛出DegradeException,然后执行降级方法
ps:添加以下代码可以实现对接口的限流
private static void initFlowQpsRule() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("/getUserOrder.do");
rule.setCount(1);//限制每秒只能接受1个请求
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);//默认
rule.setLimitApp("default");//默认
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
ps:热点限流
public static void initParamFlowRule(){
List<ParamFlowRule> rules = new ArrayList<>();
ParamFlowRule rule = new ParamFlowRule();
//阈值类型:只支持QPS
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
//阈值
rule.setCount(1);
//资源名
rule.setResource("test");
rule.setParamIdx(0);//指配热点参数的下标
//统计窗口时间长度
rule.setDurationInSec(10);
List<ParamFlowItem> items = new ArrayList<>();
ParamFlowItem item = new ParamFlowItem();
item.setClassType(String.class.getTypeName());
item.setCount(2);
item.setObject("123456");//需要统计的值
ParamFlowItem item1 = new ParamFlowItem();
item1.setClassType(int.class.getName());
item1.setCount(3);
item1.setObject("12");
items.add(item);
items.add(item1);
rule.setParamFlowItemList(items);
rules.add(rule);
ParamFlowRuleManager.loadRules(rules);
但是这样子太丑啦。当然我们可以通过@SentinelResource设置定制的fallback、blockhandler方法。
@SentinelResource 用于定义资源(方法
),并提供可选的异常处理和 fallback 配置项。 @SentinelResource 注解包含以下属性:
1value: 资源名称,必需项(不能为空)
。
2entryType: 入口类型,可选项: EntryType.IN和EntryType.OUT(默认为 EntryType.OUT)
3blockHandler / blockHandlerClass: blockHandler 对应处理 BlockException 的函数名称,可选项。
若未配置,则将 BlockException 直接抛出。blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
4fallback: fallback 函数名称,可选项,仅针对降级功能生效(DegradeException)。
fallback 函数的访问范围需要是 public,参数类型和返回类型都需要与原方法相匹配,并且需要和原方法在同一个类中。业务异常不会进入 fallback 逻辑。
但是我们也不可能每个限制的方法上面,都要去设置@SentinelResource;这样代码太冗余了。
获取控制台:地址 https://github.com/alibaba/Sentinel/releases
启动控制台:start javaw -jar sentinel-dashboard-1.7.0.jar
Feign 对应的接口中的资源名策略定义:
httpmethod:protocol://requesturl
GET:http://accountprovider/login
需要注意的是,需要对画线的资源名对应进行策略操作,如果对上级进行操作,fallback返回的仍然是默认值 BlockedbySentinel(flow limiting)
openfeign服务调用接口
package fengbo.service;
import fengbo.entity.Account;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
/*
* Created by @author LiuChunhang on 2020/7/27.
*/
/**使用openfeign,定制化服务*/
@FeignClient(value = "accountprovider",fallback = SentinelEcho.class)
@Component
public interface FeignOpenServiceFace {
@RequestMapping(value = "login")
List<Account> fengbo();
}
openfeigen fallback类
package fengbo.service;
import fengbo.entity.Account;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* Created by @author LiuChunhang on 2020/7/29.
*/
@Component
public class SentinelEcho implements FeignOpenServiceFace{
@Override
public List<Account> fengbo() {
System.out.println("!!!!!!!!!!!!!!!!!");
ArrayList<Account> accounts = new ArrayList<>();
Account account = new Account(1,"降级", "降级", "降级", "降级", "降级", 2);
accounts.add(account);
return accounts;
}
}
资源名: 唯一名称,默认请求路径
针对来源: Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)
阈值类型/单机阈值:
QPS(每秒请求数量):当调用该api的QPS达到阈值的时候,进行限流
线程数:当调用该api的线程数达到阈值的时候,进行限流
是否集群: 不需要集群/不需要集群
流控模式:
直接:api达到限流条件时,直接限流
关联:当关联的资源达到限流阈值时,就限流自己
链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到峰值,就进行限流)【api级别的针对来源】
流控效果:
快速失败:直接失败,抛异常
Warm Up:根据coldFactor(冷加载因子,默认3)的值,从阈值/coldFactor,经过预热时长,才达到设置的QPS阈值
排队等待:匀速排队,让请求以匀速通过,阈值类型必须设置为QPS,否则无效
javaAPI(可以放在启动的main方法里面执行,若放在@Configuration类的静态代码块中执行会注册不了,有bug)
private static void initFlowQpsRule() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("/getUserOrder.do");
rule.setCount(1);//限制每秒只能接受1个请求
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);//默认
rule.setLimitApp("default");//默认
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
我们通常用以下几种方式来衡量资源是否处于稳定的状态:
平均响应时间 (DEGRADE_GRADE_RT):当资源的平均响应时间超过阈值(DegradeRule 中的 count,以 ms 为单位)之后,资源进入准降级状态。接下来如果持续进入 5 个请求,它们的 RT 都持续超过这个阈值,那么在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地返回(抛出 DegradeException)。
异常比例 (DEGRADE_GRADE_EXCEPTION_RATIO):当资源的每秒异常总数占通过量的比值超过阈值(DegradeRule 中的 count)之后,资源进入降级状态,即在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
异常数 (DEGRADE_GRADE_EXCEPTION_COUNT):当资源近 1 分钟的异常数目超过阈值之后会进行熔断。
注意:异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。为了统计异常比例或异常数,需要通过 Tracer.trace(ex) 记录业务异常。
javaAPI(可以放在启动的main方法里面执行,若放在@Configuration类的静态代码块中执行会注册不了,有bug)
private static void initRtRule() {
List<DegradeRule> rules = new ArrayList<DegradeRule>();
DegradeRule rule = new DegradeRule();
rule.setResource("GET:http://order/getOrder.do");//资源名称
rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);//降级模式,根据平均响应时间降级
rule.setCount(1000);//设置平均响应时间为1000ms
rule.setTimeWindow(10);//设置降级持续时间为10s
rules.add(rule);
DegradeRuleManager.loadRules(rules);
}
javaAPI(可以放在启动的main方法里面执行,若放在@Configuration类的静态代码块中执行会注册不了,有bug)
public static void initParamFlowRule(){
List<ParamFlowRule> rules = new ArrayList<>();
ParamFlowRule rule = new ParamFlowRule();
//阈值类型:只支持QPS
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
//阈值
rule.setCount(1);
//资源名
rule.setResource("test");
rule.setParamIdx(0);//指配热点参数的下标
//统计窗口时间长度
rule.setDurationInSec(10);
List<ParamFlowItem> items = new ArrayList<>();
ParamFlowItem item = new ParamFlowItem();
item.setClassType(String.class.getTypeName());
item.setCount(2);
item.setObject("123456");//需要统计的值
ParamFlowItem item1 = new ParamFlowItem();
item1.setClassType(int.class.getName());
item1.setCount(3);
item1.setObject("12");
items.add(item);
items.add(item1);
rule.setParamFlowItemList(items);
rules.add(rule);
ParamFlowRuleManager.loadRules(rules);