Add degrade rule data to ResourceConfig.

This commit is contained in:
zhongjie
2022-01-06 16:40:39 +08:00
parent 830976cbd6
commit b8529c1b06
6 changed files with 170 additions and 70 deletions

View File

@@ -38,6 +38,8 @@ import we.stats.BlockType;
import we.stats.FlowStat;
import we.stats.IncrRequestResult;
import we.stats.ResourceConfig;
import we.stats.degrade.DegradeRule;
import we.stats.degrade.DegradeRuleService;
import we.stats.ratelimit.ResourceRateLimitConfig;
import we.stats.ratelimit.ResourceRateLimitConfigService;
import we.util.*;
@@ -87,6 +89,9 @@ public class FlowControlFilter extends FizzWebFilter {
@Resource
private SystemConfig systemConfig;
@Resource
DegradeRuleService degradeRuleService;
@Override
public Mono<Void> doFilter(ServerWebExchange exchange, WebFilterChain chain) {
@@ -129,29 +134,56 @@ public class FlowControlFilter extends FizzWebFilter {
if (result != null && !result.isSuccess()) {
String blockedResourceId = result.getBlockedResourceId();
if (BlockType.CONCURRENT_REQUEST == result.getBlockType()) {
log.info("{} exceed {} flow limit, blocked by maximum concurrent requests", traceId, blockedResourceId, LogService.BIZ_ID, traceId);
if (BlockType.DEGRADE == result.getBlockType()) {
log.info("{} exceed {} degrade limit, trigger degrade", traceId, blockedResourceId, LogService.BIZ_ID, traceId);
String responseContentType = flowControlFilterProperties.getDegradeDefaultResponseContentType();
String responseContent = flowControlFilterProperties.getDegradeDefaultResponseContent();
DegradeRule degradeRule = degradeRuleService.getDegradeRule(ResourceIdUtils.SERVICE_DEFAULT_RESOURCE);
if (degradeRule != null) {
responseContentType = degradeRule.getResponseContentType();
responseContent = degradeRule.getResponseContent();
}
degradeRule = degradeRuleService.getDegradeRule(blockedResourceId);
if (degradeRule != null) {
if (StringUtils.isNotBlank(degradeRule.getResponseContentType())) {
responseContentType = degradeRule.getResponseContentType();
}
if (StringUtils.isNotBlank(degradeRule.getResponseContent())) {
responseContent = degradeRule.getResponseContent();
}
}
ServerHttpResponse resp = exchange.getResponse();
resp.setStatusCode(HttpStatus.OK);
resp.getHeaders().add(HttpHeaders.CONTENT_TYPE, responseContentType);
return resp.writeWith(Mono.just(resp.bufferFactory().wrap(responseContent.getBytes())));
} else {
log.info("{} exceed {} flow limit, blocked by maximum QPS", traceId, blockedResourceId, LogService.BIZ_ID, traceId);
}
ResourceRateLimitConfig c = resourceRateLimitConfigService.getResourceRateLimitConfig(ResourceIdUtils.NODE_RESOURCE);
String rt = c.responseType, rc = c.responseContent;
c = resourceRateLimitConfigService.getResourceRateLimitConfig(blockedResourceId);
if (c != null) {
if (StringUtils.isNotBlank(c.responseType)) {
rt = c.responseType;
if (BlockType.CONCURRENT_REQUEST == result.getBlockType()) {
log.info("{} exceed {} flow limit, blocked by maximum concurrent requests", traceId, blockedResourceId, LogService.BIZ_ID, traceId);
} else {
log.info("{} exceed {} flow limit, blocked by maximum QPS", traceId, blockedResourceId, LogService.BIZ_ID, traceId);
}
if (StringUtils.isNotBlank(c.responseContent)) {
rc = c.responseContent;
ResourceRateLimitConfig c = resourceRateLimitConfigService.getResourceRateLimitConfig(ResourceIdUtils.NODE_RESOURCE);
String rt = c.responseType, rc = c.responseContent;
c = resourceRateLimitConfigService.getResourceRateLimitConfig(blockedResourceId);
if (c != null) {
if (StringUtils.isNotBlank(c.responseType)) {
rt = c.responseType;
}
if (StringUtils.isNotBlank(c.responseContent)) {
rc = c.responseContent;
}
}
ServerHttpResponse resp = exchange.getResponse();
resp.setStatusCode(HttpStatus.OK);
resp.getHeaders().add(HttpHeaders.CONTENT_TYPE, rt);
return resp.writeWith(Mono.just(resp.bufferFactory().wrap(rc.getBytes())));
}
ServerHttpResponse resp = exchange.getResponse();
resp.setStatusCode(HttpStatus.OK);
resp.getHeaders().add(HttpHeaders.CONTENT_TYPE, rt);
return resp.writeWith(Mono.just(resp.bufferFactory().wrap(rc.getBytes())));
} else {
long start = System.currentTimeMillis();
setTraceId(exchange);
@@ -264,11 +296,15 @@ public class FlowControlFilter extends FizzWebFilter {
private void checkRateLimitConfigAndAddTo(List<ResourceConfig> resourceConfigs, StringBuilder b, String app, String ip, String node, String service, String path, String defaultRateLimitConfigId) {
ResourceIdUtils.buildResourceIdTo(b, app, ip, node, service, path);
String resourceId = b.toString();
checkRateLimitConfigAndAddTo(resourceConfigs, resourceId, defaultRateLimitConfigId);
// degrade rule only support service and path
boolean checkDegradeRule = app == null && ip == null && node == null;
checkRateLimitConfigAndAddTo(resourceConfigs, resourceId, defaultRateLimitConfigId, checkDegradeRule);
b.delete(0, b.length());
}
private void checkRateLimitConfigAndAddTo(List<ResourceConfig> resourceConfigs, String resource, String defaultRateLimitConfigId) {
private void checkRateLimitConfigAndAddTo(List<ResourceConfig> resourceConfigs, String resource, String defaultRateLimitConfigId, boolean checkDegradeRule) {
ResourceConfig rc = null;
ResourceRateLimitConfig rateLimitConfig = resourceRateLimitConfigService.getResourceRateLimitConfig(resource);
if (rateLimitConfig != null && rateLimitConfig.isEnable()) {
@@ -300,6 +336,24 @@ public class FlowControlFilter extends FizzWebFilter {
resourceConfigs.add(rc);
}
}
if (checkDegradeRule) {
DegradeRule degradeRule = degradeRuleService.getDegradeRule(resource);
if (degradeRule != null && degradeRule.isEnable()) {
if (rc == null) {
rc = new ResourceConfig(resource, 0, 0);
resourceConfigs.add(rc);
}
fillDegradeRuleData(rc, degradeRule);
} else {
if (defaultRateLimitConfigId != null && defaultRateLimitConfigId.equals(ResourceIdUtils.SERVICE_DEFAULT)) {
degradeRule = degradeRuleService.getDegradeRule(ResourceIdUtils.SERVICE_DEFAULT_RESOURCE);
if (degradeRule != null && degradeRule.isEnable()) {
fillDegradeRuleData(rc, degradeRule);
}
}
}
}
}
private void something4appAndIp(List<ResourceConfig> resourceConfigs, ResourceRateLimitConfig rateLimitConfig) {
@@ -366,4 +420,15 @@ public class FlowControlFilter extends FizzWebFilter {
ResourceConfig rc = new ResourceConfig(r, 0, 0);
resourceConfigs.add(rc);
}
private void fillDegradeRuleData(ResourceConfig resourceConfig, DegradeRule degradeRule) {
resourceConfig.setStrategy(degradeRule.getStrategy());
resourceConfig.setRatioThreshold(degradeRule.getRatioThreshold());
resourceConfig.setExceptionCount(degradeRule.getExceptionCount());
resourceConfig.setMinRequestCount(degradeRule.getMinRequestCount());
resourceConfig.setTimeWindow(degradeRule.getTimeWindow());
resourceConfig.setStatInterval(degradeRule.getStatInterval());
resourceConfig.setRecoveryStrategy(degradeRule.getRecoveryStrategy());
resourceConfig.setRecoveryTimeWindow(degradeRule.getRecoveryTimeWindow());
}
}

View File

@@ -33,4 +33,10 @@ public class FlowControlFilterProperties {
@Value("${flowControl:false}")
private boolean flowControl;
@Value("${fizz.degrade.default-response-content-type:application/json; charset=UTF-8;}")
private String degradeDefaultResponseContentType;
@Value("${fizz.degrade.default-response-content:{\"code\":6002,\"msg\":\"The current service is unavailable, Please try again later.\"}}")
private String degradeDefaultResponseContent;
}

View File

@@ -31,5 +31,10 @@ public enum BlockType {
/**
* Blocked by QPS
*/
QPS;
QPS,
/**
* Blocked by degrade
*/
DEGRADE
}

View File

@@ -17,17 +17,34 @@
package we.stats;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
*
* @author Francis Dong
*
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ResourceConfig {
public ResourceConfig(String resourceId, long maxCon, long maxQPS) {
this.resourceId = resourceId;
this.maxCon = maxCon;
this.maxQPS = maxQPS;
}
/**
* Resouce ID
*/
private String resourceId;
//---------------------------------------------------------------------
// Flow control rule
//---------------------------------------------------------------------
/**
* Maximum concurrent request, zero or negative for no limit
*/
@@ -38,37 +55,40 @@ public class ResourceConfig {
*/
private long maxQPS;
public ResourceConfig(String resourceId, long maxCon, long maxQPS) {
this.resourceId = resourceId;
this.maxCon = maxCon;
this.maxQPS = maxQPS;
}
public ResourceConfig() {
}
public String getResourceId() {
return resourceId;
}
public void setResourceId(String resourceId) {
this.resourceId = resourceId;
}
public long getMaxCon() {
return maxCon;
}
public void setMaxCon(long maxCon) {
this.maxCon = maxCon;
}
public long getMaxQPS() {
return maxQPS;
}
public void setMaxQPS(long maxQPS) {
this.maxQPS = maxQPS;
}
//---------------------------------------------------------------------
// Degrade rule
//---------------------------------------------------------------------
/**
* Degrade strategy: 1-exception ratio 2-exception count
*/
private Byte strategy;
/**
* Ratio threshold, not null when degrade strategy is 1-exception ratio
*/
private Float ratioThreshold;
/**
* Exception count, not null when degrade strategy is 2-exception count
*/
private Long exceptionCount;
/**
* Minimal request count
*/
private Long minRequestCount;
/**
* Time window(second)
*/
private Integer timeWindow;
/**
* Statistic interval(second)
*/
private Integer statInterval;
/**
* Recovery strategy: 1-try one 2-recover gradually 3-recover immediately
*/
private Byte recoveryStrategy;
/**
* Recovery time window(second)not null when recovery strategy is 2-recover gradually
*/
private Integer recoveryTimeWindow;
}

View File

@@ -31,68 +31,68 @@ import static we.util.ResourceIdUtils.SERVICE_DEFAULT;
@Data
public class DegradeRule {
/**
* 整型自增主键
* ID
*/
private Long id;
/**
* 熔断类型 1-服务默认配置 2-服务 3-接口
* Degrade type: 1-default service 2-service 3-path
*/
private Byte type;
/**
* 前端服务名
* Front service name
*/
private String service;
/**
* 前端API路径
* Front API path
*/
private String path;
/**
* 熔断策略 1-异常比例 2-异常数
* Degrade strategy: 1-exception ratio 2-exception count
*/
private Byte strategy;
/**
* 比例阈值,当熔断策略为 1-异常比例 时该字段有值
* Ratio threshold, not null when degrade strategy is 1-exception ratio
*/
private Float ratioThreshold;
/**
* 异常数,当熔断策略为 2-异常数 时该字段有值
* Exception count, not null when degrade strategy is 2-exception count
*/
private Long exceptionCount;
/**
* 最小请求数
* Minimal request count
*/
private Long minRequestCount;
/**
* 熔断时长(秒)
* Time window(second)
*/
private Integer timeWindow;
/**
* 统计时长(秒)
* Statistic interval(second)
*/
private Integer statInterval;
/**
* 恢复策略 1-尝试恢复 2-逐步恢复 3-立即恢复
* Recovery strategy: 1-try one 2-recover gradually 3-recover immediately
*/
private Byte recoveryStrategy;
/**
* 恢复时长(秒),当恢复策略为 2-逐步恢复 时该字段有值
* Recovery time window(second)not null when recovery strategy is 2-recover gradually
*/
private Integer recoveryTimeWindow;
/**
* 熔断响应ContentType
* Response ContentType
*/
private String responseContentType;
/**
* 熔断响应报文
* Response Content
*/
private String responseContent;
/**
* 当type为1时1启用0反之
* When type is 1-default service1-enable 0-disable
*/
private Integer enable;
/**
* 是否删除 1-是 2-
* Is deleted, 1-yes 2-no
*/
private Integer isDeleted;

View File

@@ -68,6 +68,10 @@ public class DegradeRuleService {
}
}
public DegradeRule getDegradeRule(String resourceId) {
return resourceId2DegradeRuleMap.get(resourceId);
}
public void refreshLocalCache() throws Throwable {
this.initDegradeRule();
}