Skip to content

Commit 30bda8b

Browse files
committed
feat:support default instance circuit breaker rule.
1 parent d21ee97 commit 30bda8b

File tree

7 files changed

+313
-1
lines changed

7 files changed

+313
-1
lines changed

polaris-common/polaris-config-default/src/main/resources/conf/default-config.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,16 @@ consumer:
248248
#描述:熔断策略,SDK会根据策略名称加载对应的熔断器插件(已注册的熔断器插件名)
249249
chain:
250250
- composite
251+
# 描述:是否启用默认熔断规则
252+
defaultRuleEnable: true
253+
# 描述:连续错误数熔断器默认连续错误数
254+
defaultErrorCount: 10
255+
# 描述:错误率熔断器默认错误率
256+
defaultErrorPercent: 50
257+
# 描述:错误率熔断器默认统计周期(单位:毫秒)
258+
defaultInterval: 60000
259+
# 描述:错误率熔断器默认最小请求数
260+
defaultMinimumRequest: 10
251261
#描述: 熔断插件配置
252262
plugin:
253263
#描述:基于周期连续错误数熔断策略配置

polaris-common/polaris-config/src/main/java/com/tencent/polaris/api/config/consumer/CircuitBreakerConfig.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import com.tencent.polaris.api.config.plugin.PluginConfig;
2121
import com.tencent.polaris.api.config.verify.Verifier;
22+
2223
import java.util.List;
2324

2425
/**
@@ -84,5 +85,39 @@ public interface CircuitBreakerConfig extends PluginConfig, Verifier {
8485
*/
8586
long getCountersExpireInterval();
8687

88+
/**
89+
* 是否启用默认规则
90+
*
91+
* @return boolean
92+
*/
93+
boolean isDefaultRuleEnable();
94+
95+
/**
96+
* 连续错误数熔断器默认连续错误数
97+
*
98+
* @return 连续错误数
99+
*/
100+
int getDefaultErrorCount();
101+
102+
/**
103+
* 错误率熔断器默认错误率
104+
*
105+
* @return 错误率
106+
*/
107+
int getDefaultErrorPercent();
108+
109+
/**
110+
* 错误率熔断器默认统计周期
111+
*
112+
* @return 统计周期
113+
*/
114+
int getDefaultInterval();
115+
116+
/**
117+
* 错误率熔断器默认最小请求数
118+
*
119+
* @return 最小请求数
120+
*/
121+
int getDefaultMinimumRequest();
87122

88123
}

polaris-common/polaris-config/src/main/java/com/tencent/polaris/factory/config/consumer/CircuitBreakerConfigImpl.java

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.tencent.polaris.factory.config.plugin.PluginConfigImpl;
2525
import com.tencent.polaris.factory.util.ConfigUtils;
2626
import com.tencent.polaris.factory.util.TimeStrJsonDeserializer;
27+
2728
import java.util.List;
2829

2930
/**
@@ -61,6 +62,21 @@ public class CircuitBreakerConfigImpl extends PluginConfigImpl implements Circui
6162
@JsonDeserialize(using = TimeStrJsonDeserializer.class)
6263
private Long countersExpireInterval;
6364

65+
@JsonProperty
66+
private Boolean defaultRuleEnable;
67+
68+
@JsonProperty
69+
private Integer defaultErrorCount;
70+
71+
@JsonProperty
72+
private Integer defaultErrorPercent;
73+
74+
@JsonProperty
75+
private Integer defaultInterval;
76+
77+
@JsonProperty
78+
private Integer defaultMinimumRequest;
79+
6480
@Override
6581
public boolean isEnable() {
6682
if (null == enable) {
@@ -148,6 +164,54 @@ public void setEnableRemotePull(boolean enableRemotePull) {
148164
this.enableRemotePull = enableRemotePull;
149165
}
150166

167+
@Override
168+
public boolean isDefaultRuleEnable() {
169+
if (null == defaultRuleEnable) {
170+
defaultRuleEnable = true;
171+
}
172+
return defaultRuleEnable;
173+
}
174+
175+
public void setDefaultRuleEnable(Boolean defaultRuleEnable) {
176+
this.defaultRuleEnable = defaultRuleEnable;
177+
}
178+
179+
@Override
180+
public int getDefaultErrorCount() {
181+
return defaultErrorCount;
182+
}
183+
184+
public void setDefaultErrorCount(Integer defaultErrorCount) {
185+
this.defaultErrorCount = defaultErrorCount;
186+
}
187+
188+
@Override
189+
public int getDefaultErrorPercent() {
190+
return defaultErrorPercent;
191+
}
192+
193+
public void setDefaultErrorPercent(Integer defaultErrorPercent) {
194+
this.defaultErrorPercent = defaultErrorPercent;
195+
}
196+
197+
@Override
198+
public int getDefaultInterval() {
199+
return defaultInterval;
200+
}
201+
202+
public void setDefaultInterval(Integer defaultInterval) {
203+
this.defaultInterval = defaultInterval;
204+
}
205+
206+
@Override
207+
public int getDefaultMinimumRequest() {
208+
return defaultMinimumRequest;
209+
}
210+
211+
public void setDefaultMinimumRequest(Integer defaultMinimumRequest) {
212+
this.defaultMinimumRequest = defaultMinimumRequest;
213+
}
214+
151215
@Override
152216
public void verify() {
153217
ConfigUtils.validateNull(enable, "circuitBreaker.enable");
@@ -163,6 +227,11 @@ public void verify() {
163227
ConfigUtils.validatePositive(requestCountAfterHalfOpen, "circuitBreaker.requestCountAfterHalfOpen");
164228
ConfigUtils.validatePositive(successCountAfterHalfOpen, "circuitBreaker.successCountAfterHalfOpen");
165229
ConfigUtils.validateNull(enableRemotePull, "circuitBreaker.enableRemotePull");
230+
ConfigUtils.validateNull(defaultRuleEnable, "circuitBreaker.defaultRuleEnable");
231+
ConfigUtils.validatePositive(defaultErrorCount, "circuitBreaker.defaultErrorCount");
232+
ConfigUtils.validatePositive(defaultErrorPercent, "circuitBreaker.defaultErrorPercent");
233+
ConfigUtils.validatePositive(defaultInterval, "circuitBreaker.defaultInterval");
234+
ConfigUtils.validatePositive(defaultMinimumRequest, "circuitBreaker.defaultMinimumRequest");
166235
verifyPluginConfig();
167236
}
168237

@@ -194,6 +263,21 @@ public void setDefault(Object defaultObject) {
194263
if (null == enableRemotePull) {
195264
setEnableRemotePull(circuitBreakerConfig.isEnableRemotePull());
196265
}
266+
if (null == defaultRuleEnable) {
267+
setDefaultRuleEnable(circuitBreakerConfig.isDefaultRuleEnable());
268+
}
269+
if (null == defaultErrorCount) {
270+
setDefaultErrorCount(circuitBreakerConfig.getDefaultErrorCount());
271+
}
272+
if (null == defaultErrorPercent) {
273+
setDefaultErrorPercent(circuitBreakerConfig.getDefaultErrorPercent());
274+
}
275+
if (null == defaultInterval) {
276+
setDefaultInterval(circuitBreakerConfig.getDefaultInterval());
277+
}
278+
if (null == defaultMinimumRequest) {
279+
setDefaultMinimumRequest(circuitBreakerConfig.getDefaultMinimumRequest());
280+
}
197281
if (enable) {
198282
setDefaultPluginConfig(circuitBreakerConfig);
199283
}
@@ -211,6 +295,11 @@ public String toString() {
211295
", successCountAfterHalfOpen=" + successCountAfterHalfOpen +
212296
", enableRemotePull=" + enableRemotePull +
213297
", countersExpireInterval=" + countersExpireInterval +
298+
", defaultRuleEnable=" + defaultRuleEnable +
299+
", defaultErrorCount=" + defaultErrorCount +
300+
", defaultErrorPercent=" + defaultErrorPercent +
301+
", defaultInterval=" + defaultInterval +
302+
", defaultMinimumRequest=" + defaultMinimumRequest +
214303
'}';
215304
}
216305
}

polaris-plugins/polaris-plugins-circuitbreaker/circuitbreaker-composite/src/main/java/com/tencent/polaris/plugins/circuitbreaker/composite/PolarisCircuitBreaker.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@
3737
import com.tencent.polaris.api.plugin.compose.Extensions;
3838
import com.tencent.polaris.api.plugin.detect.HealthChecker;
3939
import com.tencent.polaris.api.pojo.*;
40-
import com.tencent.polaris.api.utils.TrieUtil;
4140
import com.tencent.polaris.api.utils.CollectionUtils;
41+
import com.tencent.polaris.api.utils.TrieUtil;
4242
import com.tencent.polaris.client.flow.DefaultServiceResourceProvider;
4343
import com.tencent.polaris.client.util.NamedThreadFactory;
4444
import com.tencent.polaris.logging.LoggerFactory;
@@ -241,6 +241,8 @@ private Optional<ResourceCounters> initResourceCounter(Resource resource) throws
241241
throw t;
242242
}
243243

244+
cbSvcRule = CircuitBreakerUtils.fillDefaultCircuitBreakerRuleInNeeded(resource, cbSvcRule, circuitBreakerConfig);
245+
244246
// pull fd rule
245247
ServiceEventKey fdEventKey = new ServiceEventKey(resource.getService(),
246248
ServiceEventKey.EventType.FAULT_DETECTING);

polaris-plugins/polaris-plugins-circuitbreaker/circuitbreaker-composite/src/main/java/com/tencent/polaris/plugins/circuitbreaker/composite/utils/CircuitBreakerUtils.java

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,34 @@
1717

1818
package com.tencent.polaris.plugins.circuitbreaker.composite.utils;
1919

20+
import com.google.common.collect.Lists;
21+
import com.google.protobuf.StringValue;
2022
import com.tencent.polaris.api.config.consumer.CircuitBreakerConfig;
2123
import com.tencent.polaris.api.plugin.circuitbreaker.ResourceStat;
24+
import com.tencent.polaris.api.plugin.circuitbreaker.entity.Resource;
2225
import com.tencent.polaris.api.plugin.event.FlowEventConstants;
2326
import com.tencent.polaris.api.pojo.CircuitBreakerStatus;
2427
import com.tencent.polaris.api.pojo.RetStatus;
28+
import com.tencent.polaris.api.pojo.ServiceRule;
2529
import com.tencent.polaris.api.utils.CollectionUtils;
2630
import com.tencent.polaris.api.utils.IPAddressUtils;
2731
import com.tencent.polaris.api.utils.RuleUtils;
32+
import com.tencent.polaris.client.pojo.ServiceRuleByProto;
33+
import com.tencent.polaris.logging.LoggerFactory;
2834
import com.tencent.polaris.specification.api.v1.fault.tolerance.CircuitBreakerProto;
2935
import com.tencent.polaris.specification.api.v1.model.ModelProto;
36+
import org.slf4j.Logger;
3037

3138
import java.util.List;
3239
import java.util.function.Function;
3340
import java.util.regex.Pattern;
41+
import java.util.stream.Collectors;
42+
import java.util.stream.IntStream;
3443

3544
public class CircuitBreakerUtils {
3645

46+
private static final Logger LOG = LoggerFactory.getLogger(CircuitBreakerUtils.class);
47+
3748
public static long DEFAULT_ERROR_RATE_INTERVAL_MS = 60 * 1000;
3849

3950
public static long MIN_CLEANUP_INTERVAL = 60 * 1000;
@@ -142,4 +153,94 @@ public static String getInstanceCircuitBreakerName(String host, int port) {
142153
public static String getServiceCircuitBreakerName(String targetNamespaceId, String serviceName) {
143154
return targetNamespaceId + "#" + serviceName;
144155
}
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+
}
145246
}

0 commit comments

Comments
 (0)