You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2022/11/12 06:55:55 UTC
[servicecomb-java-chassis] branch master updated: [SCB-2726] add TimeLimiter and Cache governance (#3474)
This is an automated email from the ASF dual-hosted git repository.
liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git
The following commit(s) were added to refs/heads/master by this push:
new a9d8d301a [SCB-2726] add TimeLimiter and Cache governance (#3474)
a9d8d301a is described below
commit a9d8d301ae6fc1e67690fd9757f82803c2828bfa
Author: zzj8886 <11...@users.noreply.github.com>
AuthorDate: Sat Nov 12 14:55:48 2022 +0800
[SCB-2726] add TimeLimiter and Cache governance (#3474)
---
.../governance/GovernanceConfiguration.java | 24 +++++++
.../governance/handler/DisposableTimeLimiter.java | 49 ++++++++++++++
.../governance/handler/GovernanceCacheHandler.java | 68 ++++++++++++++++++++
.../governance/handler/TimeLimiterHandler.java | 74 ++++++++++++++++++++++
.../governance/policy/GovernanceCachePolicy.java | 64 +++++++++++++++++++
.../governance/policy/TimeLimiterPolicy.java | 45 +++++++++++++
.../properties/GovernanceCacheProperties.java | 36 +++++++++++
.../properties/TimeLimiterProperties.java | 37 +++++++++++
.../governance/service/GovernanceCache.java | 33 ++++++++++
.../governance/service/GovernanceCacheImpl.java | 52 +++++++++++++++
.../governance/GovernanceCacheHandlerTest.java | 54 ++++++++++++++++
.../governance/GovernancePropertiesTest.java | 71 ++++++++++++++++++++-
.../governance/TimeLimiterHandlerTest.java | 52 +++++++++++++++
governance/src/test/resources/application.yaml | 24 +++++++
14 files changed, 682 insertions(+), 1 deletion(-)
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/GovernanceConfiguration.java b/governance/src/main/java/org/apache/servicecomb/governance/GovernanceConfiguration.java
index efe058039..2b06b2172 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/GovernanceConfiguration.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/GovernanceConfiguration.java
@@ -22,6 +22,7 @@ import java.util.Map;
import org.apache.servicecomb.governance.handler.BulkheadHandler;
import org.apache.servicecomb.governance.handler.CircuitBreakerHandler;
import org.apache.servicecomb.governance.handler.FaultInjectionHandler;
+import org.apache.servicecomb.governance.handler.GovernanceCacheHandler;
import org.apache.servicecomb.governance.handler.IdentifierRateLimitingHandler;
import org.apache.servicecomb.governance.handler.InstanceBulkheadHandler;
import org.apache.servicecomb.governance.handler.InstanceIsolationHandler;
@@ -29,6 +30,7 @@ import org.apache.servicecomb.governance.handler.LoadBalanceHandler;
import org.apache.servicecomb.governance.handler.MapperHandler;
import org.apache.servicecomb.governance.handler.RateLimitingHandler;
import org.apache.servicecomb.governance.handler.RetryHandler;
+import org.apache.servicecomb.governance.handler.TimeLimiterHandler;
import org.apache.servicecomb.governance.handler.ext.AbstractCircuitBreakerExtension;
import org.apache.servicecomb.governance.handler.ext.AbstractInstanceIsolationExtension;
import org.apache.servicecomb.governance.handler.ext.AbstractRetryExtension;
@@ -40,6 +42,8 @@ import org.apache.servicecomb.governance.marker.operator.MatchOperator;
import org.apache.servicecomb.governance.marker.operator.PrefixOperator;
import org.apache.servicecomb.governance.marker.operator.SuffixOperator;
import org.apache.servicecomb.governance.properties.BulkheadProperties;
+import org.apache.servicecomb.governance.properties.TimeLimiterProperties;
+import org.apache.servicecomb.governance.properties.GovernanceCacheProperties;
import org.apache.servicecomb.governance.properties.CircuitBreakerProperties;
import org.apache.servicecomb.governance.properties.FaultInjectionProperties;
import org.apache.servicecomb.governance.properties.IdentifierRateLimitProperties;
@@ -101,6 +105,16 @@ public class GovernanceConfiguration {
return new RetryProperties();
}
+ @Bean
+ public TimeLimiterProperties timeLimiterProperties() {
+ return new TimeLimiterProperties();
+ }
+
+ @Bean
+ public GovernanceCacheProperties cacheProperties() {
+ return new GovernanceCacheProperties();
+ }
+
@Bean
public FaultInjectionProperties faultInjectionProperties() {
return new FaultInjectionProperties();
@@ -161,6 +175,16 @@ public class GovernanceConfiguration {
return new RetryHandler(retryProperties, retryExtension);
}
+ @Bean
+ public TimeLimiterHandler timeLimiterHandler(TimeLimiterProperties timeLimiterProperties) {
+ return new TimeLimiterHandler(timeLimiterProperties);
+ }
+
+ @Bean
+ public GovernanceCacheHandler<String, Object> governanceCacheHandler(GovernanceCacheProperties cacheProperties) {
+ return new GovernanceCacheHandler<String, Object>(cacheProperties);
+ }
+
@Bean
public FaultInjectionHandler faultInjectionHandler(FaultInjectionProperties faultInjectionProperties) {
return new FaultInjectionHandler(faultInjectionProperties);
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableTimeLimiter.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableTimeLimiter.java
new file mode 100644
index 000000000..4a23b72d6
--- /dev/null
+++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableTimeLimiter.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicecomb.governance.handler;
+
+import io.github.resilience4j.timelimiter.TimeLimiter;
+import io.github.resilience4j.timelimiter.TimeLimiterRegistry;
+
+public class DisposableTimeLimiter extends Disposable<TimeLimiter> {
+ private final String key;
+
+ private final TimeLimiterRegistry timeLimiterRegistry;
+
+ private final TimeLimiter timeLimiter;
+
+ public DisposableTimeLimiter(String key, TimeLimiterRegistry registry, TimeLimiter timeLimiter) {
+ this.key = key;
+ this.timeLimiterRegistry = registry;
+ this.timeLimiter = timeLimiter;
+ }
+
+ @Override
+ public void dispose() {
+ timeLimiterRegistry.remove(key);
+ }
+
+ @Override
+ public TimeLimiter getValue() {
+ return timeLimiter;
+ }
+
+ @Override
+ public String getKey() {
+ return key;
+ }
+}
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/GovernanceCacheHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/GovernanceCacheHandler.java
new file mode 100644
index 000000000..88d96f937
--- /dev/null
+++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/GovernanceCacheHandler.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicecomb.governance.handler;
+
+import org.apache.servicecomb.governance.marker.GovernanceRequest;
+import org.apache.servicecomb.governance.policy.GovernanceCachePolicy;
+import org.apache.servicecomb.governance.properties.GovernanceCacheProperties;
+import org.apache.servicecomb.governance.service.GovernanceCache;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.time.Duration;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+
+public class GovernanceCacheHandler<K, V>
+ extends AbstractGovernanceHandler<GovernanceCache<K, V>, GovernanceCachePolicy> {
+ private static final Logger LOGGER = LoggerFactory.getLogger(GovernanceCacheHandler.class);
+
+ private final GovernanceCacheProperties cacheProperties;
+
+ public GovernanceCacheHandler(GovernanceCacheProperties cacheProperties) {
+ this.cacheProperties = cacheProperties;
+ }
+
+ @Override
+ public GovernanceCachePolicy matchPolicy(GovernanceRequest governanceRequest) {
+ return matchersManager.match(governanceRequest, cacheProperties.getParsedEntity());
+ }
+
+ @Override
+ protected String createKey(GovernanceRequest governanceRequest, GovernanceCachePolicy policy) {
+ return cacheProperties.getConfigKey() + "." + policy.getName();
+ }
+
+ @Override
+ protected Disposable<GovernanceCache<K, V>> createProcessor(String key, GovernanceRequest governanceRequest,
+ GovernanceCachePolicy policy) {
+ return getGovernanceCache(key, policy);
+ }
+
+ protected Disposable<GovernanceCache<K, V>> getGovernanceCache(String key, GovernanceCachePolicy policy) {
+ LOGGER.info("applying new policy {} for {}", key, policy.toString());
+ Cache<K,
+ V> cache = CacheBuilder.newBuilder()
+ .expireAfterWrite(Duration.parse(policy.getTtl()))
+ .maximumSize(policy.getMaximumSize())
+ .concurrencyLevel(policy.getConcurrencyLevel())
+ .build();
+ GovernanceCache<K, V> governanceCache = GovernanceCache.of(cache);
+ return new DisposableHolder<>(key, governanceCache);
+ }
+}
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/TimeLimiterHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/TimeLimiterHandler.java
new file mode 100644
index 000000000..357951bee
--- /dev/null
+++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/TimeLimiterHandler.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.governance.handler;
+
+import io.github.resilience4j.micrometer.tagged.TaggedTimeLimiterMetrics;
+import io.github.resilience4j.micrometer.tagged.TimeLimiterMetricNames;
+import io.github.resilience4j.timelimiter.TimeLimiter;
+import io.github.resilience4j.timelimiter.TimeLimiterConfig;
+import io.github.resilience4j.timelimiter.TimeLimiterRegistry;
+
+import org.apache.servicecomb.governance.marker.GovernanceRequest;
+import org.apache.servicecomb.governance.policy.TimeLimiterPolicy;
+import org.apache.servicecomb.governance.properties.TimeLimiterProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.time.Duration;
+
+public class TimeLimiterHandler extends AbstractGovernanceHandler<TimeLimiter, TimeLimiterPolicy> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(TimeLimiterHandler.class);
+
+ private final TimeLimiterProperties timeLimiterProperties;
+
+ public TimeLimiterHandler(TimeLimiterProperties timeLimiterProperties) {
+ this.timeLimiterProperties = timeLimiterProperties;
+ }
+
+ @Override
+ protected String createKey(GovernanceRequest governanceRequest, TimeLimiterPolicy policy) {
+ return timeLimiterProperties.getConfigKey() + "." + policy.getName();
+ }
+
+ @Override
+ public TimeLimiterPolicy matchPolicy(GovernanceRequest governanceRequest) {
+ return matchersManager.match(governanceRequest, timeLimiterProperties.getParsedEntity());
+ }
+
+ @Override
+ public Disposable<TimeLimiter> createProcessor(String key, GovernanceRequest governanceRequest,
+ TimeLimiterPolicy policy) {
+ return getTimeLimiter(key, policy);
+ }
+
+ private Disposable<TimeLimiter> getTimeLimiter(String key, TimeLimiterPolicy policy) {
+ LOGGER.info("applying new policy {} for {}", key, policy);
+ TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom()
+ .timeoutDuration(Duration.parse(policy.getTimeoutDuration()))
+ .cancelRunningFuture(policy.isCancelRunningFuture())
+ .build();
+ TimeLimiterRegistry timeLimiterRegistry = TimeLimiterRegistry.of(timeLimiterConfig);
+ if (meterRegistry != null) {
+ TaggedTimeLimiterMetrics.ofTimeLimiterRegistry(TimeLimiterMetricNames.custom()
+ .callsMetricName(timeLimiterProperties.getConfigKey() + ".calls")
+ .build(), timeLimiterRegistry).bindTo(meterRegistry);
+ }
+ return new DisposableTimeLimiter(key, timeLimiterRegistry, timeLimiterRegistry.timeLimiter(key));
+ }
+}
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/policy/GovernanceCachePolicy.java b/governance/src/main/java/org/apache/servicecomb/governance/policy/GovernanceCachePolicy.java
new file mode 100644
index 000000000..719c9cf41
--- /dev/null
+++ b/governance/src/main/java/org/apache/servicecomb/governance/policy/GovernanceCachePolicy.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.governance.policy;
+
+import java.time.Duration;
+
+public class GovernanceCachePolicy extends AbstractPolicy {
+ public static final Duration DEFAULT_TTL = Duration.ofMillis(21600000);
+
+ public static final long DEFAULT_MAXIMUM_SIZE = 60000;
+
+ public static final int DEFAULT_CONCURRENCY_LEVEL = 8;
+
+ private String ttl = DEFAULT_TTL.toString();
+
+ private long maximumSize = DEFAULT_MAXIMUM_SIZE;
+
+ private int concurrencyLevel = DEFAULT_CONCURRENCY_LEVEL;
+
+ public String getTtl() {
+ return ttl;
+ }
+
+ public void setTtl(String ttl) {
+ this.ttl = stringOfDuration(ttl, DEFAULT_TTL);
+ }
+
+ public Long getMaximumSize() {
+ return maximumSize;
+ }
+
+ public void setMaximumSize(Long maximumSize) {
+ this.maximumSize = maximumSize;
+ }
+
+ public int getConcurrencyLevel() {
+ return concurrencyLevel;
+ }
+
+ public void setConcurrencyLevel(int concurrencyLevel) {
+ this.concurrencyLevel = concurrencyLevel;
+ }
+
+ @Override
+ public String toString() {
+ return "CachePolicy{" + "ttl=" + ttl + ",concurrencyLevel=" + concurrencyLevel + ", maximumSize=" + maximumSize
+ + '}';
+ }
+}
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/policy/TimeLimiterPolicy.java b/governance/src/main/java/org/apache/servicecomb/governance/policy/TimeLimiterPolicy.java
new file mode 100644
index 000000000..e00300127
--- /dev/null
+++ b/governance/src/main/java/org/apache/servicecomb/governance/policy/TimeLimiterPolicy.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicecomb.governance.policy;
+
+import java.time.Duration;
+
+public class TimeLimiterPolicy extends AbstractPolicy {
+ public static final Duration DEFAULT_TIMEOUT_DURATION = Duration.ofMillis(1000);
+
+ public static final boolean DEFAULT_CANCEL_RUNNING_FUTURE = true;
+
+ private String timeoutDuration = DEFAULT_TIMEOUT_DURATION.toString();
+
+ private boolean cancelRunningFuture = DEFAULT_CANCEL_RUNNING_FUTURE;
+
+ public String getTimeoutDuration() {
+ return timeoutDuration;
+ }
+
+ public void setTimeoutDuration(String timeoutDuration) {
+ this.timeoutDuration = stringOfDuration(timeoutDuration, DEFAULT_TIMEOUT_DURATION);
+ }
+
+ public boolean isCancelRunningFuture() {
+ return cancelRunningFuture;
+ }
+
+ public void setCancelRunningFuture(boolean cancelRunningFuture) {
+ this.cancelRunningFuture = cancelRunningFuture;
+ }
+}
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/GovernanceCacheProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/GovernanceCacheProperties.java
new file mode 100644
index 000000000..9ae9a8daa
--- /dev/null
+++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/GovernanceCacheProperties.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicecomb.governance.properties;
+
+import org.apache.servicecomb.governance.policy.GovernanceCachePolicy;
+
+public class GovernanceCacheProperties extends PolicyProperties<GovernanceCachePolicy> {
+ public static final String MATCH_CACHE_KEY = "servicecomb.cache";
+
+ public GovernanceCacheProperties() {
+ super(MATCH_CACHE_KEY);
+ }
+
+ public GovernanceCacheProperties(String key) {
+ super(key);
+ }
+
+ @Override
+ public Class<GovernanceCachePolicy> getEntityClass() {
+ return GovernanceCachePolicy.class;
+ }
+}
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/TimeLimiterProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/TimeLimiterProperties.java
new file mode 100644
index 000000000..daca14f57
--- /dev/null
+++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/TimeLimiterProperties.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicecomb.governance.properties;
+
+
+import org.apache.servicecomb.governance.policy.TimeLimiterPolicy;
+
+public class TimeLimiterProperties extends PolicyProperties<TimeLimiterPolicy> {
+ public static final String MATCH_TIMELIMITER_KEY = "servicecomb.timeLimiter";
+
+ public TimeLimiterProperties() {
+ super(MATCH_TIMELIMITER_KEY);
+ }
+
+ public TimeLimiterProperties(String key) {
+ super(key);
+ }
+
+ @Override
+ public Class<TimeLimiterPolicy> getEntityClass() {
+ return TimeLimiterPolicy.class;
+ }
+}
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/service/GovernanceCache.java b/governance/src/main/java/org/apache/servicecomb/governance/service/GovernanceCache.java
new file mode 100644
index 000000000..35014272f
--- /dev/null
+++ b/governance/src/main/java/org/apache/servicecomb/governance/service/GovernanceCache.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.governance.service;
+
+import com.google.common.cache.Cache;
+
+import java.util.Objects;
+
+public interface GovernanceCache<K, V> {
+ static <K, V> GovernanceCache<K, V> of(Cache<K, V> cache) {
+ Objects.requireNonNull(cache, "Cache must not be null");
+ return new GovernanceCacheImpl<>(cache);
+ }
+
+ V getValueFromCache(K cacheKey);
+
+ void putValueIntoCache(K cacheKey, V value);
+}
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/service/GovernanceCacheImpl.java b/governance/src/main/java/org/apache/servicecomb/governance/service/GovernanceCacheImpl.java
new file mode 100644
index 000000000..a7dcfa5d4
--- /dev/null
+++ b/governance/src/main/java/org/apache/servicecomb/governance/service/GovernanceCacheImpl.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.governance.service;
+
+import com.google.common.cache.Cache;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GovernanceCacheImpl<K, V> implements GovernanceCache<K, V> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(GovernanceCacheImpl.class);
+
+ private final Cache<K, V> cache;
+
+ public GovernanceCacheImpl(Cache<K, V> cache) {
+ this.cache = cache;
+ }
+
+ public V getValueFromCache(K cacheKey) {
+ try {
+ return cache.getIfPresent(cacheKey);
+ } catch (Exception exception) {
+ LOG.warn("Failed to get a value from Cache", exception);
+ return null;
+ }
+ }
+
+ @Override
+ public void putValueIntoCache(K cacheKey, V value) {
+ try {
+ cache.put(cacheKey, value);
+ } catch (Exception exception) {
+ LOG.warn("Failed to put a value into Cache {}", exception);
+ }
+ }
+}
diff --git a/governance/src/test/java/org/apache/servicecomb/governance/GovernanceCacheHandlerTest.java b/governance/src/test/java/org/apache/servicecomb/governance/GovernanceCacheHandlerTest.java
new file mode 100644
index 000000000..3d1ee28cd
--- /dev/null
+++ b/governance/src/test/java/org/apache/servicecomb/governance/GovernanceCacheHandlerTest.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicecomb.governance;
+
+
+import org.apache.servicecomb.governance.handler.GovernanceCacheHandler;
+import org.apache.servicecomb.governance.marker.GovernanceRequest;
+import org.apache.servicecomb.governance.policy.GovernanceCachePolicy;
+import org.apache.servicecomb.governance.service.GovernanceCache;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ContextConfiguration;
+
+@SpringBootTest
+@ContextConfiguration(classes = {GovernanceConfiguration.class, MockConfiguration.class})
+public class GovernanceCacheHandlerTest {
+ private GovernanceCacheHandler<String, Object> governanceCacheHandler;
+
+ @Autowired
+ public void setInstanceIsolationHandler(@Autowired GovernanceCacheHandler<String, Object> governanceCacheHandler) {
+ this.governanceCacheHandler = governanceCacheHandler;
+ }
+
+ @Test
+ public void testMatchPriorityPolicy() {
+ GovernanceRequest request = new GovernanceRequest();
+ request.setUri("/governanceCache");
+ GovernanceCachePolicy policy = governanceCacheHandler.matchPolicy(request);
+ Assertions.assertEquals("demo-governanceCache", policy.getName());
+ GovernanceCache<String, Object> governanceCache = governanceCacheHandler.getActuator(request);
+ governanceCache.putValueIntoCache("governance", "Cache");
+ Object cache = governanceCache.getValueFromCache("governance");
+ Assertions.assertEquals("Cache", cache);
+ governanceCache.putValueIntoCache("response", null);
+ Object response = governanceCache.getValueFromCache("response");
+ Assertions.assertNull(response);
+ }
+}
diff --git a/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java b/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java
index 77902d848..d24329956 100644
--- a/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java
+++ b/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java
@@ -32,17 +32,21 @@ import org.apache.servicecomb.governance.policy.AbstractPolicy;
import org.apache.servicecomb.governance.policy.BulkheadPolicy;
import org.apache.servicecomb.governance.policy.CircuitBreakerPolicy;
import org.apache.servicecomb.governance.policy.FaultInjectionPolicy;
+import org.apache.servicecomb.governance.policy.GovernanceCachePolicy;
import org.apache.servicecomb.governance.policy.RateLimitingPolicy;
import org.apache.servicecomb.governance.policy.RetryPolicy;
+import org.apache.servicecomb.governance.policy.TimeLimiterPolicy;
import org.apache.servicecomb.governance.processor.injection.FaultInjectionConst;
import org.apache.servicecomb.governance.properties.BulkheadProperties;
import org.apache.servicecomb.governance.properties.CircuitBreakerProperties;
import org.apache.servicecomb.governance.properties.FaultInjectionProperties;
+import org.apache.servicecomb.governance.properties.GovernanceCacheProperties;
import org.apache.servicecomb.governance.properties.GovernanceProperties;
import org.apache.servicecomb.governance.properties.InstanceIsolationProperties;
import org.apache.servicecomb.governance.properties.MatchProperties;
import org.apache.servicecomb.governance.properties.RateLimitProperties;
import org.apache.servicecomb.governance.properties.RetryProperties;
+import org.apache.servicecomb.governance.properties.TimeLimiterProperties;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
@@ -65,6 +69,10 @@ public class GovernancePropertiesTest {
private CircuitBreakerProperties circuitBreakerProperties;
+ private TimeLimiterProperties timeLimiterProperties;
+
+ private GovernanceCacheProperties governanceCacheProperties;
+
private InstanceIsolationProperties instanceIsolationProperties;
private RateLimitProperties rateLimitProperties;
@@ -95,6 +103,16 @@ public class GovernancePropertiesTest {
this.circuitBreakerProperties = circuitBreakerProperties;
}
+ @Autowired
+ public void setTimeLimiterProperties(TimeLimiterProperties timeLimiterProperties) {
+ this.timeLimiterProperties = timeLimiterProperties;
+ }
+
+ @Autowired
+ public void setGovernanceCacheProperties(GovernanceCacheProperties governanceCacheProperties) {
+ this.governanceCacheProperties = governanceCacheProperties;
+ }
+
@Autowired
public void setRateLimitProperties(RateLimitProperties rateLimitProperties) {
this.rateLimitProperties = rateLimitProperties;
@@ -164,7 +182,7 @@ public class GovernancePropertiesTest {
@Test
public void test_all_bean_is_loaded() {
- Assertions.assertEquals(14, propertiesList.size());
+ Assertions.assertEquals(16, propertiesList.size());
}
@Test
@@ -292,6 +310,57 @@ public class GovernancePropertiesTest {
Assertions.assertEquals(3000, Duration.parse(policy.getMaxWaitDuration()).toMillis());
}
+ @Test
+ public void test_timelimiter_properties_successfully_loaded() {
+ Map<String, TimeLimiterPolicy> policies = timeLimiterProperties.getParsedEntity();
+ Assertions.assertEquals(2, policies.size());
+ TimeLimiterPolicy timeLimiterPolicy = policies.get("demo-timeLimiter-other");
+ Assertions.assertEquals(2000, Duration.parse(timeLimiterPolicy.getTimeoutDuration()).toMillis());
+ Assertions.assertEquals(false, timeLimiterPolicy.isCancelRunningFuture());
+ }
+
+ @Test
+ public void test_timelimiter_properties_bound() {
+ dynamicValues.put("servicecomb.timeLimiter.name1", "rules:\n"
+ + "timeoutDuration: 5000\n"
+ + "cancelRunningFuture: false");
+
+ GovernanceEventManager.post(new GovernanceConfigurationChangedEvent(new HashSet<>(dynamicValues.keySet())));
+
+ Map<String, TimeLimiterPolicy> policies = timeLimiterProperties.getParsedEntity();
+ Assertions.assertEquals(3, policies.size());
+ TimeLimiterPolicy policy = policies.get("name1");
+ Assertions.assertEquals(false, policy.isCancelRunningFuture());
+ Assertions.assertEquals(5000, Duration.parse(policy.getTimeoutDuration()).toMillis());
+ }
+
+ @Test
+ public void test_governanceCache_properties_successfully_loaded() {
+ Map<String, GovernanceCachePolicy> policies = governanceCacheProperties.getParsedEntity();
+ Assertions.assertEquals(2, policies.size());
+ GovernanceCachePolicy governanceCachePolicy = policies.get("demo-governanceCache-other");
+ Assertions.assertEquals(15, governanceCachePolicy.getConcurrencyLevel());
+ Assertions.assertEquals(50000, governanceCachePolicy.getMaximumSize());
+ Assertions.assertEquals(666666, Duration.parse(governanceCachePolicy.getTtl()).toMillis());
+ }
+
+ @Test
+ public void test_governanceCache_properties_bound() {
+ dynamicValues.put("servicecomb.cache.name1", "rules:\n"
+ + "ttl: 3000000\n"
+ + "maximumSize: 2000\n"
+ + "concurrencyLevel: 6");
+
+ GovernanceEventManager.post(new GovernanceConfigurationChangedEvent(new HashSet<>(dynamicValues.keySet())));
+
+ Map<String, GovernanceCachePolicy> policies = governanceCacheProperties.getParsedEntity();
+ Assertions.assertEquals(3, policies.size());
+ GovernanceCachePolicy policy = policies.get("name1");
+ Assertions.assertEquals(3000000, Duration.parse(policy.getTtl()).toMillis());
+ Assertions.assertEquals(2000, policy.getMaximumSize());
+ Assertions.assertEquals(6, policy.getConcurrencyLevel());
+ }
+
@Test
public void test_circuit_breaker_properties_successfully_loaded() {
Map<String, CircuitBreakerPolicy> policies = circuitBreakerProperties.getParsedEntity();
diff --git a/governance/src/test/java/org/apache/servicecomb/governance/TimeLimiterHandlerTest.java b/governance/src/test/java/org/apache/servicecomb/governance/TimeLimiterHandlerTest.java
new file mode 100644
index 000000000..5fd484f5e
--- /dev/null
+++ b/governance/src/test/java/org/apache/servicecomb/governance/TimeLimiterHandlerTest.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicecomb.governance;
+
+import java.time.Duration;
+
+import org.apache.servicecomb.governance.handler.TimeLimiterHandler;
+import org.apache.servicecomb.governance.marker.GovernanceRequest;
+import org.apache.servicecomb.governance.policy.TimeLimiterPolicy;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ContextConfiguration;
+
+import io.github.resilience4j.timelimiter.TimeLimiter;
+
+@SpringBootTest
+@ContextConfiguration(classes = {GovernanceConfiguration.class, MockConfiguration.class})
+public class TimeLimiterHandlerTest {
+ private TimeLimiterHandler timeLimiterHandler;
+
+ @Autowired
+ public void setInstanceIsolationHandler(TimeLimiterHandler timeLimiterHandler) {
+ this.timeLimiterHandler = timeLimiterHandler;
+ }
+
+ @Test
+ public void testMatchPriorityPolicy() {
+ GovernanceRequest request = new GovernanceRequest();
+ request.setUri("/timeLimiter");
+ TimeLimiterPolicy policy = timeLimiterHandler.matchPolicy(request);
+ Assertions.assertEquals("demo-timeLimiter", policy.getName());
+ TimeLimiter timeLimiter = timeLimiterHandler.getActuator(request);
+ Duration timeoutDuration = timeLimiter.getTimeLimiterConfig().getTimeoutDuration();
+ Assertions.assertEquals(2000, timeoutDuration.toMillis());
+ }
+}
diff --git a/governance/src/test/resources/application.yaml b/governance/src/test/resources/application.yaml
index 69c07171c..e6ba6c73b 100644
--- a/governance/src/test/resources/application.yaml
+++ b/governance/src/test/resources/application.yaml
@@ -17,6 +17,14 @@
servicecomb:
matchGroup:
+ demo-timeLimiter: |
+ matches:
+ - apiPath:
+ prefix: "/timeLimiter"
+ demo-governanceCache: |
+ matches:
+ - apiPath:
+ prefix: "/governanceCache"
demo-loadbalance-random: |
matches:
- serviceName: "loadrandom"
@@ -99,6 +107,22 @@ servicecomb:
demo-rateLimiting-servicename: |
rate: 1
identifier: test
+ timeLimiter:
+ demo-timeLimiter: |
+ timeoutDuration: 2000
+ cancelRunningFuture: true
+ demo-timeLimiter-other: |
+ timeoutDuration: 2000
+ cancelRunningFuture: false
+ cache:
+ demo-governanceCache: |
+ ttl: 36000000
+ maximumSize: 50000
+ concurrencyLevel: 10
+ demo-governanceCache-other: |
+ ttl: 666666
+ maximumSize: 50000
+ concurrencyLevel: 15
retry:
demo-retry: |
maxAttempts: 3