|
17 | 17 |
|
18 | 18 | package com.tencent.polaris.plugins.circuitbreaker.composite.utils; |
19 | 19 |
|
| 20 | +import com.google.common.collect.Lists; |
| 21 | +import com.google.protobuf.StringValue; |
20 | 22 | import com.tencent.polaris.api.config.consumer.CircuitBreakerConfig; |
21 | 23 | import com.tencent.polaris.api.plugin.circuitbreaker.ResourceStat; |
| 24 | +import com.tencent.polaris.api.plugin.circuitbreaker.entity.Resource; |
22 | 25 | import com.tencent.polaris.api.plugin.event.FlowEventConstants; |
23 | 26 | import com.tencent.polaris.api.pojo.CircuitBreakerStatus; |
24 | 27 | import com.tencent.polaris.api.pojo.RetStatus; |
| 28 | +import com.tencent.polaris.api.pojo.ServiceRule; |
25 | 29 | import com.tencent.polaris.api.utils.CollectionUtils; |
26 | 30 | import com.tencent.polaris.api.utils.IPAddressUtils; |
27 | 31 | import com.tencent.polaris.api.utils.RuleUtils; |
| 32 | +import com.tencent.polaris.client.pojo.ServiceRuleByProto; |
| 33 | +import com.tencent.polaris.logging.LoggerFactory; |
28 | 34 | import com.tencent.polaris.specification.api.v1.fault.tolerance.CircuitBreakerProto; |
29 | 35 | import com.tencent.polaris.specification.api.v1.model.ModelProto; |
| 36 | +import org.slf4j.Logger; |
30 | 37 |
|
31 | 38 | import java.util.List; |
32 | 39 | import java.util.function.Function; |
33 | 40 | import java.util.regex.Pattern; |
| 41 | +import java.util.stream.Collectors; |
| 42 | +import java.util.stream.IntStream; |
34 | 43 |
|
35 | 44 | public class CircuitBreakerUtils { |
36 | 45 |
|
| 46 | + private static final Logger LOG = LoggerFactory.getLogger(CircuitBreakerUtils.class); |
| 47 | + |
37 | 48 | public static long DEFAULT_ERROR_RATE_INTERVAL_MS = 60 * 1000; |
38 | 49 |
|
39 | 50 | public static long MIN_CLEANUP_INTERVAL = 60 * 1000; |
@@ -142,4 +153,94 @@ public static String getInstanceCircuitBreakerName(String host, int port) { |
142 | 153 | public static String getServiceCircuitBreakerName(String targetNamespaceId, String serviceName) { |
143 | 154 | return targetNamespaceId + "#" + serviceName; |
144 | 155 | } |
| 156 | + |
| 157 | + public static ServiceRule fillDefaultCircuitBreakerRuleInNeeded(Resource resource, ServiceRule serviceRule, CircuitBreakerConfig circuitBreakerConfig) { |
| 158 | + if (serviceRule instanceof ServiceRuleByProto && serviceRule.getRule() instanceof CircuitBreakerProto.CircuitBreaker) { |
| 159 | + List<CircuitBreakerProto.CircuitBreakerRule> rules = ((CircuitBreakerProto.CircuitBreaker) serviceRule.getRule()).getRulesList(); |
| 160 | + if (shouldFilled(circuitBreakerConfig, rules)) { |
| 161 | + CircuitBreakerProto.CircuitBreaker.Builder newCircuitBreakerBuilder = CircuitBreakerProto.CircuitBreaker.newBuilder().mergeFrom((CircuitBreakerProto.CircuitBreaker) serviceRule.getRule()); |
| 162 | + CircuitBreakerProto.CircuitBreakerRule.Builder defaultCircuitBreakerRuleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder(); |
| 163 | + // set name |
| 164 | + defaultCircuitBreakerRuleBuilder.setName("default-polaris-instance-circuit-breaker"); |
| 165 | + // set enable |
| 166 | + defaultCircuitBreakerRuleBuilder.setEnable(true); |
| 167 | + // set level |
| 168 | + defaultCircuitBreakerRuleBuilder.setLevel(CircuitBreakerProto.Level.INSTANCE); |
| 169 | + // build ruleMatcher |
| 170 | + CircuitBreakerProto.RuleMatcher.Builder ruleMatcher = CircuitBreakerProto.RuleMatcher.newBuilder(); |
| 171 | + CircuitBreakerProto.RuleMatcher.SourceService.Builder sourceServiceBuilder = CircuitBreakerProto.RuleMatcher.SourceService.newBuilder(); |
| 172 | + sourceServiceBuilder.setNamespace(resource.getCallerService().getNamespace()); |
| 173 | + sourceServiceBuilder.setService(resource.getCallerService().getService()); |
| 174 | + ruleMatcher.setSource(sourceServiceBuilder); |
| 175 | + CircuitBreakerProto.RuleMatcher.DestinationService.Builder destinationServiceBuilder = CircuitBreakerProto.RuleMatcher.DestinationService.newBuilder(); |
| 176 | + destinationServiceBuilder.setNamespace(resource.getService().getNamespace()); |
| 177 | + destinationServiceBuilder.setService(resource.getService().getService()); |
| 178 | + ruleMatcher.setDestination(destinationServiceBuilder); |
| 179 | + defaultCircuitBreakerRuleBuilder.setRuleMatcher(ruleMatcher); |
| 180 | + // build blockConfigs |
| 181 | + List<CircuitBreakerProto.BlockConfig> blockConfigList = Lists.newArrayList(); |
| 182 | + // build failure block config |
| 183 | + CircuitBreakerProto.BlockConfig.Builder failureBlockConfigBuilder = CircuitBreakerProto.BlockConfig.newBuilder(); |
| 184 | + failureBlockConfigBuilder.setName("failure-block-config"); |
| 185 | + // build ret code error condition |
| 186 | + CircuitBreakerProto.ErrorCondition.Builder errorConditionBuilder = CircuitBreakerProto.ErrorCondition.newBuilder(); |
| 187 | + errorConditionBuilder.setInputType(CircuitBreakerProto.ErrorCondition.InputType.RET_CODE); |
| 188 | + ModelProto.MatchString.Builder codeMatchStringBuilder = ModelProto.MatchString.newBuilder(); |
| 189 | + codeMatchStringBuilder.setType(ModelProto.MatchString.MatchStringType.IN); |
| 190 | + String statusCodes = IntStream.range(500, 600) |
| 191 | + .mapToObj(String::valueOf) |
| 192 | + .collect(Collectors.joining(",")); |
| 193 | + codeMatchStringBuilder.setValue(StringValue.of(statusCodes)); |
| 194 | + errorConditionBuilder.setCondition(codeMatchStringBuilder); |
| 195 | + failureBlockConfigBuilder.addErrorConditions(errorConditionBuilder); |
| 196 | + // build failure trigger conditions |
| 197 | + // build error rate trigger condition |
| 198 | + CircuitBreakerProto.TriggerCondition.Builder errorRateTriggerConditionBuilder = CircuitBreakerProto.TriggerCondition.newBuilder(); |
| 199 | + errorRateTriggerConditionBuilder.setTriggerType(CircuitBreakerProto.TriggerCondition.TriggerType.ERROR_RATE); |
| 200 | + errorRateTriggerConditionBuilder.setErrorPercent(circuitBreakerConfig.getDefaultErrorPercent()); |
| 201 | + errorRateTriggerConditionBuilder.setInterval(circuitBreakerConfig.getDefaultInterval() / 1000); |
| 202 | + errorRateTriggerConditionBuilder.setMinimumRequest(circuitBreakerConfig.getDefaultMinimumRequest()); |
| 203 | + failureBlockConfigBuilder.addTriggerConditions(errorRateTriggerConditionBuilder); |
| 204 | + // build consecutive error trigger condition |
| 205 | + CircuitBreakerProto.TriggerCondition.Builder consecutiveErrorTriggerConditionBuilder = CircuitBreakerProto.TriggerCondition.newBuilder(); |
| 206 | + consecutiveErrorTriggerConditionBuilder.setTriggerType(CircuitBreakerProto.TriggerCondition.TriggerType.CONSECUTIVE_ERROR); |
| 207 | + consecutiveErrorTriggerConditionBuilder.setErrorCount(circuitBreakerConfig.getDefaultErrorCount()); |
| 208 | + failureBlockConfigBuilder.addTriggerConditions(consecutiveErrorTriggerConditionBuilder); |
| 209 | + blockConfigList.add(failureBlockConfigBuilder.build()); |
| 210 | + defaultCircuitBreakerRuleBuilder.addAllBlockConfigs(blockConfigList); |
| 211 | + // build recoverCondition |
| 212 | + CircuitBreakerProto.RecoverCondition.Builder recoverConditionBuilder = CircuitBreakerProto.RecoverCondition.newBuilder(); |
| 213 | + recoverConditionBuilder.setSleepWindow((int) circuitBreakerConfig.getSleepWindow() / 1000); |
| 214 | + recoverConditionBuilder.setConsecutiveSuccess(circuitBreakerConfig.getSuccessCountAfterHalfOpen()); |
| 215 | + defaultCircuitBreakerRuleBuilder.setRecoverCondition(recoverConditionBuilder); |
| 216 | + newCircuitBreakerBuilder.addRules(defaultCircuitBreakerRuleBuilder); |
| 217 | + CircuitBreakerProto.CircuitBreaker newCircuitBreaker = newCircuitBreakerBuilder.build(); |
| 218 | + if (LOG.isDebugEnabled()) { |
| 219 | + LOG.debug("Resource {} set default circuit breaker rule {}", resource, newCircuitBreaker); |
| 220 | + } else { |
| 221 | + LOG.info("Resource {} set default circuit breaker rule with DefaultErrorCount:{}, " + |
| 222 | + "DefaultErrorPercent:{}, DefaultInterval:{}, DefaultMinimumRequest:{}", |
| 223 | + resource, circuitBreakerConfig.getDefaultErrorCount(), circuitBreakerConfig.getDefaultErrorPercent(), |
| 224 | + circuitBreakerConfig.getDefaultInterval(), circuitBreakerConfig.getDefaultMinimumRequest()); |
| 225 | + } |
| 226 | + return new ServiceRuleByProto(newCircuitBreaker, serviceRule.getRevision(), ((ServiceRuleByProto) serviceRule).isLoadedFromFile(), ((ServiceRuleByProto) serviceRule).getEventType()); |
| 227 | + } |
| 228 | + } |
| 229 | + return serviceRule; |
| 230 | + } |
| 231 | + |
| 232 | + private static boolean shouldFilled(CircuitBreakerConfig circuitBreakerConfig, List<CircuitBreakerProto.CircuitBreakerRule> rules) { |
| 233 | + if (!circuitBreakerConfig.isDefaultRuleEnable()) { |
| 234 | + return false; |
| 235 | + } |
| 236 | + if (CollectionUtils.isEmpty(rules)) { |
| 237 | + return true; |
| 238 | + } |
| 239 | + for (CircuitBreakerProto.CircuitBreakerRule rule : rules) { |
| 240 | + if (rule.getEnable() && CircuitBreakerUtils.checkRule(rule)) { |
| 241 | + return false; |
| 242 | + } |
| 243 | + } |
| 244 | + return true; |
| 245 | + } |
145 | 246 | } |
0 commit comments