feat: filter级别降级处理
原因
需要支持降级处理
修改
修改filterHook, 支持降级
This commit is contained in:
parent
35bfdff8e4
commit
06a8b49c54
@ -45,6 +45,11 @@
|
|||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-core</artifactId>
|
||||||
|
<version>1.8.0</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
@ -1,5 +1,6 @@
|
|||||||
package cn.axzo.foundation.gateway.support.plugin.impl;
|
package cn.axzo.foundation.gateway.support.plugin.impl;
|
||||||
|
|
||||||
|
import cn.axzo.foundation.exception.BusinessException;
|
||||||
import cn.axzo.foundation.gateway.support.entity.GateResponse;
|
import cn.axzo.foundation.gateway.support.entity.GateResponse;
|
||||||
import cn.axzo.foundation.gateway.support.entity.ProxyContext;
|
import cn.axzo.foundation.gateway.support.entity.ProxyContext;
|
||||||
import cn.axzo.foundation.gateway.support.entity.RequestContext;
|
import cn.axzo.foundation.gateway.support.entity.RequestContext;
|
||||||
@ -8,6 +9,13 @@ import cn.axzo.foundation.gateway.support.plugin.impl.filters.*;
|
|||||||
import cn.axzo.foundation.util.FastjsonUtils;
|
import cn.axzo.foundation.util.FastjsonUtils;
|
||||||
import cn.axzo.foundation.web.support.rpc.RequestParams;
|
import cn.axzo.foundation.web.support.rpc.RequestParams;
|
||||||
import cn.axzo.foundation.web.support.rpc.RpcClient;
|
import cn.axzo.foundation.web.support.rpc.RpcClient;
|
||||||
|
import com.alibaba.csp.sentinel.Entry;
|
||||||
|
import com.alibaba.csp.sentinel.EntryType;
|
||||||
|
import com.alibaba.csp.sentinel.SphU;
|
||||||
|
import com.alibaba.csp.sentinel.Tracer;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
@ -15,6 +23,7 @@ import com.google.common.base.Splitter;
|
|||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@ -74,6 +83,17 @@ public class RequestFilterHook implements ProxyHook {
|
|||||||
.put("requestParamCheckFilter", new RequestParamCheckFilter())
|
.put("requestParamCheckFilter", new RequestParamCheckFilter())
|
||||||
.put("moveInputFieldFilter", new MoveInputFieldFilter())
|
.put("moveInputFieldFilter", new MoveInputFieldFilter())
|
||||||
.put("keyNoQueryFilter", new KeyNoQueryFilter())
|
.put("keyNoQueryFilter", new KeyNoQueryFilter())
|
||||||
|
.put("emptyFilter", new RequestFilter() {
|
||||||
|
@Override
|
||||||
|
public JSON filterIn(RequestContext reqContext, JSON params, JSONObject config) {
|
||||||
|
return RequestFilter.super.filterIn(reqContext, params, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSON filterOut(RequestContext reqContext, JSON response, JSONObject config) {
|
||||||
|
return RequestFilter.super.filterOut(reqContext, response, config);
|
||||||
|
}
|
||||||
|
})
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@Builder
|
@Builder
|
||||||
@ -103,9 +123,32 @@ public class RequestFilterHook implements ProxyHook {
|
|||||||
for (FilterBean bean : beans) {
|
for (FilterBean bean : beans) {
|
||||||
RequestFilter requestFilter = filterBeanResolver.apply(bean.getName());
|
RequestFilter requestFilter = filterBeanResolver.apply(bean.getName());
|
||||||
Preconditions.checkState(requestFilter != null, bean.getName() + " 没在系统注册");
|
Preconditions.checkState(requestFilter != null, bean.getName() + " 没在系统注册");
|
||||||
requestBody = requestFilter.filterIn(reqContext, requestBody, bean.getConfig());
|
FallBackConfig fallBackConfig = bean.getFallBackConfig();
|
||||||
}
|
|
||||||
|
|
||||||
|
Entry entry = null;
|
||||||
|
try {
|
||||||
|
if (fallBackConfig != null) {
|
||||||
|
String resourceName = bean.getResourceName(reqContext.getRequestURI());
|
||||||
|
fallBackConfig.registerRule(resourceName);
|
||||||
|
entry = SphU.entry(resourceName, EntryType.IN);
|
||||||
|
}
|
||||||
|
requestBody = requestFilter.filterIn(reqContext, requestBody, bean.getConfig());
|
||||||
|
} catch (BlockException ex) {
|
||||||
|
//降级处理
|
||||||
|
requestBody = filterBeanResolver.apply(fallBackConfig.getFallBackFilter())
|
||||||
|
.filterIn(reqContext, requestBody, fallBackConfig.getConfig());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
//非业务异常记录trace
|
||||||
|
if (!BusinessException.class.isAssignableFrom(ex.getClass())) {
|
||||||
|
Tracer.traceEntry(ex, entry);
|
||||||
|
}
|
||||||
|
throw ex;
|
||||||
|
} finally {
|
||||||
|
if (entry != null) {
|
||||||
|
entry.exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// 只支持 json 格式
|
// 只支持 json 格式
|
||||||
return ((RequestParams.BodyParams) postParams).toBuilder().content(requestBody).build();
|
return ((RequestParams.BodyParams) postParams).toBuilder().content(requestBody).build();
|
||||||
}
|
}
|
||||||
@ -133,7 +176,31 @@ public class RequestFilterHook implements ProxyHook {
|
|||||||
for (FilterBean bean : beans) {
|
for (FilterBean bean : beans) {
|
||||||
RequestFilter requestFilter = filterBeanResolver.apply(bean.getName());
|
RequestFilter requestFilter = filterBeanResolver.apply(bean.getName());
|
||||||
Preconditions.checkState(requestFilter != null, bean.getName() + " 没在系统注册");
|
Preconditions.checkState(requestFilter != null, bean.getName() + " 没在系统注册");
|
||||||
|
FallBackConfig fallBackConfig = bean.getFallBackConfig();
|
||||||
|
|
||||||
|
Entry entry = null;
|
||||||
|
try {
|
||||||
|
if (fallBackConfig != null) {
|
||||||
|
String resourceName = bean.getResourceName(reqContext.getRequestURI());
|
||||||
|
fallBackConfig.registerRule(resourceName);
|
||||||
|
entry = SphU.entry(resourceName, EntryType.OUT);
|
||||||
|
}
|
||||||
responseBody = requestFilter.filterOut(reqContext, responseBody, bean.getConfig());
|
responseBody = requestFilter.filterOut(reqContext, responseBody, bean.getConfig());
|
||||||
|
} catch (BlockException ex) {
|
||||||
|
//降级处理
|
||||||
|
responseBody = filterBeanResolver.apply(fallBackConfig.getFallBackFilter())
|
||||||
|
.filterIn(reqContext, responseBody, fallBackConfig.getConfig());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
//非业务异常记录trace
|
||||||
|
if (!BusinessException.class.isAssignableFrom(ex.getClass())) {
|
||||||
|
Tracer.traceEntry(ex, entry);
|
||||||
|
}
|
||||||
|
throw ex;
|
||||||
|
} finally {
|
||||||
|
if (entry != null) {
|
||||||
|
entry.exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GateResponse res = response.toBuilder().build();
|
GateResponse res = response.toBuilder().build();
|
||||||
@ -195,5 +262,49 @@ public class RequestFilterHook implements ProxyHook {
|
|||||||
private static class FilterBean {
|
private static class FilterBean {
|
||||||
private String name;
|
private String name;
|
||||||
private JSONObject config;
|
private JSONObject config;
|
||||||
|
|
||||||
|
public FallBackConfig getFallBackConfig() {
|
||||||
|
return Optional.ofNullable(config)
|
||||||
|
.flatMap(e -> Optional.ofNullable(e.getJSONObject("fallBack"))
|
||||||
|
.map(fallBack -> fallBack.toJavaObject(FallBackConfig.class)))
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResourceName(String requestUrl) {
|
||||||
|
return "RequestFilterHook:" + name + "@" + requestUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
private static class FallBackConfig {
|
||||||
|
String fallBackFilter = "emptyFilter";
|
||||||
|
JSONObject config;
|
||||||
|
/** 策略, 支持FLOW_GRADE_QPS慢查询比例, DEGRADE_GRADE_EXCEPTION_RATIO异常比例, DEGRADE_GRADE_EXCEPTION_COUNT异常数 */
|
||||||
|
Integer grade = 2;
|
||||||
|
/** 默认10s内请求大于5个, 同时错误超过一半则降级30s */
|
||||||
|
Double count = 0.5D;
|
||||||
|
Integer timeWindow = 30;
|
||||||
|
Integer minRequestAmount = 5;
|
||||||
|
/** 慢比例有效 */
|
||||||
|
Double slowRatioThreshold = 1.0;
|
||||||
|
Integer statIntervalMs = 10000;
|
||||||
|
|
||||||
|
public void registerRule(String resourceName) {
|
||||||
|
if (DegradeRuleManager.hasConfig(resourceName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DegradeRule degradeRule = new DegradeRule(resourceName);
|
||||||
|
degradeRule.setGrade(grade);
|
||||||
|
degradeRule.setCount(count);
|
||||||
|
degradeRule.setTimeWindow(timeWindow);
|
||||||
|
degradeRule.setMinRequestAmount(minRequestAmount);
|
||||||
|
degradeRule.setSlowRatioThreshold(slowRatioThreshold);
|
||||||
|
degradeRule.setStatIntervalMs(statIntervalMs);
|
||||||
|
|
||||||
|
DegradeRuleManager.setRulesForResource(resourceName, ImmutableSet.of(degradeRule));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,57 @@
|
|||||||
|
package cn.axzo.foundation.gateway.support.plugin.impl;
|
||||||
|
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.Entry;
|
||||||
|
import com.alibaba.csp.sentinel.EntryType;
|
||||||
|
import com.alibaba.csp.sentinel.SphU;
|
||||||
|
import com.alibaba.csp.sentinel.Tracer;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
class RequestFilterHookTest {
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
String resourceName = "aaaa";
|
||||||
|
|
||||||
|
DegradeRule degradeRule = new DegradeRule(resourceName);
|
||||||
|
degradeRule.setGrade(2);
|
||||||
|
degradeRule.setCount(0.5);
|
||||||
|
degradeRule.setTimeWindow(30);
|
||||||
|
degradeRule.setMinRequestAmount(5);
|
||||||
|
degradeRule.setStatIntervalMs(10);
|
||||||
|
|
||||||
|
DegradeRuleManager.setRulesForResource(resourceName, ImmutableSet.of(degradeRule));
|
||||||
|
|
||||||
|
List<Integer> blocked = IntStream.range(0, 20).mapToObj(e -> {
|
||||||
|
Entry entry = null;
|
||||||
|
try {
|
||||||
|
entry = SphU.entry(resourceName, EntryType.IN);
|
||||||
|
if (e % 2 == 0) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
return e;
|
||||||
|
} catch (BlockException ex) {
|
||||||
|
return -1;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Tracer.traceEntry(ex, entry);
|
||||||
|
return -2;
|
||||||
|
} finally {
|
||||||
|
if (entry != null) {
|
||||||
|
entry.exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
System.out.printf(blocked.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user