feat: filter级别降级处理
原因
需要支持降级处理
修改
修改filterHook, 支持降级
This commit is contained in:
parent
35bfdff8e4
commit
06a8b49c54
@ -45,6 +45,11 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-core</artifactId>
|
||||
<version>1.8.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -1,5 +1,6 @@
|
||||
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.ProxyContext;
|
||||
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.web.support.rpc.RequestParams;
|
||||
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.JSONObject;
|
||||
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.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import lombok.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -74,6 +83,17 @@ public class RequestFilterHook implements ProxyHook {
|
||||
.put("requestParamCheckFilter", new RequestParamCheckFilter())
|
||||
.put("moveInputFieldFilter", new MoveInputFieldFilter())
|
||||
.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();
|
||||
|
||||
@Builder
|
||||
@ -103,9 +123,32 @@ public class RequestFilterHook implements ProxyHook {
|
||||
for (FilterBean bean : beans) {
|
||||
RequestFilter requestFilter = filterBeanResolver.apply(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 格式
|
||||
return ((RequestParams.BodyParams) postParams).toBuilder().content(requestBody).build();
|
||||
}
|
||||
@ -133,7 +176,31 @@ public class RequestFilterHook implements ProxyHook {
|
||||
for (FilterBean bean : beans) {
|
||||
RequestFilter requestFilter = filterBeanResolver.apply(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());
|
||||
} 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();
|
||||
@ -195,5 +262,49 @@ public class RequestFilterHook implements ProxyHook {
|
||||
private static class FilterBean {
|
||||
private String name;
|
||||
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