From b8529c1b0675e7b6401a1f5445dd5d9e24651054 Mon Sep 17 00:00:00 2001 From: zhongjie Date: Thu, 6 Jan 2022 16:40:39 +0800 Subject: [PATCH] Add degrade rule data to ResourceConfig. --- .../java/we/filter/FlowControlFilter.java | 107 ++++++++++++++---- .../filter/FlowControlFilterProperties.java | 6 + .../src/main/java/we/stats/BlockType.java | 7 +- .../main/java/we/stats/ResourceConfig.java | 84 ++++++++------ .../java/we/stats/degrade/DegradeRule.java | 32 +++--- .../we/stats/degrade/DegradeRuleService.java | 4 + 6 files changed, 170 insertions(+), 70 deletions(-) diff --git a/fizz-core/src/main/java/we/filter/FlowControlFilter.java b/fizz-core/src/main/java/we/filter/FlowControlFilter.java index 36cf306..b388984 100644 --- a/fizz-core/src/main/java/we/filter/FlowControlFilter.java +++ b/fizz-core/src/main/java/we/filter/FlowControlFilter.java @@ -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 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 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 resourceConfigs, String resource, String defaultRateLimitConfigId) { + private void checkRateLimitConfigAndAddTo(List 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 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()); + } } diff --git a/fizz-core/src/main/java/we/filter/FlowControlFilterProperties.java b/fizz-core/src/main/java/we/filter/FlowControlFilterProperties.java index b3129bb..7ae08c4 100644 --- a/fizz-core/src/main/java/we/filter/FlowControlFilterProperties.java +++ b/fizz-core/src/main/java/we/filter/FlowControlFilterProperties.java @@ -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; } diff --git a/fizz-core/src/main/java/we/stats/BlockType.java b/fizz-core/src/main/java/we/stats/BlockType.java index 70ce566..7b7a861 100644 --- a/fizz-core/src/main/java/we/stats/BlockType.java +++ b/fizz-core/src/main/java/we/stats/BlockType.java @@ -31,5 +31,10 @@ public enum BlockType { /** * Blocked by QPS */ - QPS; + QPS, + + /** + * Blocked by degrade + */ + DEGRADE } diff --git a/fizz-core/src/main/java/we/stats/ResourceConfig.java b/fizz-core/src/main/java/we/stats/ResourceConfig.java index 8faab86..c5b95be 100644 --- a/fizz-core/src/main/java/we/stats/ResourceConfig.java +++ b/fizz-core/src/main/java/we/stats/ResourceConfig.java @@ -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; } diff --git a/fizz-core/src/main/java/we/stats/degrade/DegradeRule.java b/fizz-core/src/main/java/we/stats/degrade/DegradeRule.java index b7ef705..97851ff 100644 --- a/fizz-core/src/main/java/we/stats/degrade/DegradeRule.java +++ b/fizz-core/src/main/java/we/stats/degrade/DegradeRule.java @@ -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 service,1-enable 0-disable */ private Integer enable; /** - * 是否删除 1-是 2-否 + * Is deleted, 1-yes 2-no */ private Integer isDeleted; diff --git a/fizz-core/src/main/java/we/stats/degrade/DegradeRuleService.java b/fizz-core/src/main/java/we/stats/degrade/DegradeRuleService.java index 3870080..fb83421 100644 --- a/fizz-core/src/main/java/we/stats/degrade/DegradeRuleService.java +++ b/fizz-core/src/main/java/we/stats/degrade/DegradeRuleService.java @@ -68,6 +68,10 @@ public class DegradeRuleService { } } + public DegradeRule getDegradeRule(String resourceId) { + return resourceId2DegradeRuleMap.get(resourceId); + } + public void refreshLocalCache() throws Throwable { this.initDegradeRule(); }