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 2018/06/20 08:44:42 UTC
[incubator-servicecomb-java-chassis] branch master updated: [SCB-506]服务治理相关的事件需要上报 (#678)
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/incubator-servicecomb-java-chassis.git
The following commit(s) were added to refs/heads/master by this push:
new 861e198 [SCB-506]服务治理相关的事件需要上报 (#678)
861e198 is described below
commit 861e198e6880deafe1092097ae1f935f7c1b9de7
Author: xuyiyun0929 <32...@users.noreply.github.com>
AuthorDate: Wed Jun 20 16:44:38 2018 +0800
[SCB-506]服务治理相关的事件需要上报 (#678)
* [SCB-506]服务治理相关的需要事件上报
* [SCB-506] Use ConcurrentHashMap instead of HashMap
* [SCB-506] Use ConcurrentHashMap instead of HashMap
* [SCB-506] Get CircutBreakerEvent via HystrixEventNotifier
* [SCB-506] Optimize for suggestions
* [SCB-506] Optimize for suggestions
* [SCB-506] Customize HystrixCommandGroupKey to avoid always split string.
* [SCB-506] Customize HystrixCommandGroupKey to avoid always split string.
* [SCB-506] Repair OOM problem and add a OOM test case
* [SCB-506] check getCommandGroup() if instance of CustomizeCommandGroupKey
---
.../foundation/common/event/AlarmEvent.java | 29 ++----
.../apache/servicecomb/bizkeeper/CommandKey.java | 4 +-
.../bizkeeper/CustomizeCommandGroupKey.java | 58 +++++++++++
.../bizkeeper/event/CircutBreakerEvent.java | 113 +++++++++++++++++++++
.../event/CircutBreakerEventNotifier.java | 61 +++++++++++
.../src/main/resources/hystrix-plugins.properties | 1 +
.../bizkeeper/TestBizkeeperCommand.java | 8 --
.../bizkeeper/TestCustomCommandGroupKey.java | 44 ++++++++
.../event/TestCircutBreakerEventNotifier.java | 79 ++++++++++++++
.../loadbalance/event/IsolationServerEvent.java | 87 ++++++++++++++++
.../filter/IsolationServerListFilter.java | 23 ++++-
.../filter/TestIsolationServerListFilter.java | 72 +++++++------
12 files changed, 516 insertions(+), 63 deletions(-)
diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/CommandKey.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/AlarmEvent.java
similarity index 52%
copy from handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/CommandKey.java
copy to foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/AlarmEvent.java
index a4e0aa4..1f100c1 100644
--- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/CommandKey.java
+++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/AlarmEvent.java
@@ -14,29 +14,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.servicecomb.foundation.common.event;
-package org.apache.servicecomb.bizkeeper;
+public class AlarmEvent {
-import org.apache.servicecomb.core.Invocation;
+ Type type;
-import com.netflix.hystrix.HystrixCommandGroupKey;
-import com.netflix.hystrix.HystrixCommandKey;
-
-/**
- * 创建对应的Key值
- *
- */
-public final class CommandKey {
- private CommandKey() {
+ public AlarmEvent(Type type) {
+ this.type = type;
}
- public static HystrixCommandGroupKey toHystrixCommandGroupKey(String type, Invocation invocation) {
- return HystrixCommandGroupKey.Factory
- .asKey(type + "." + invocation.getOperationMeta().getMicroserviceQualifiedName());
+ public Type getType() {
+ return this.type;
}
- public static HystrixCommandKey toHystrixCommandKey(String type, Invocation invocation) {
- return HystrixCommandKey.Factory
- .asKey(type + "." + invocation.getOperationMeta().getMicroserviceQualifiedName());
- }
+ public enum Type {
+ OPEN,
+ CLOSE
+ };
}
diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/CommandKey.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/CommandKey.java
index a4e0aa4..22a2cfc 100644
--- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/CommandKey.java
+++ b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/CommandKey.java
@@ -31,8 +31,8 @@ public final class CommandKey {
}
public static HystrixCommandGroupKey toHystrixCommandGroupKey(String type, Invocation invocation) {
- return HystrixCommandGroupKey.Factory
- .asKey(type + "." + invocation.getOperationMeta().getMicroserviceQualifiedName());
+ return CustomizeCommandGroupKey.asKey(type + "." + invocation.getOperationMeta().getMicroserviceQualifiedName(),
+ invocation);
}
public static HystrixCommandKey toHystrixCommandKey(String type, Invocation invocation) {
diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/CustomizeCommandGroupKey.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/CustomizeCommandGroupKey.java
new file mode 100644
index 0000000..c80e926
--- /dev/null
+++ b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/CustomizeCommandGroupKey.java
@@ -0,0 +1,58 @@
+/*
+ * 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.bizkeeper;
+
+import org.apache.servicecomb.core.Invocation;
+
+import com.netflix.hystrix.HystrixCommandGroupKey;
+import com.netflix.hystrix.HystrixKey;
+import com.netflix.hystrix.util.InternMap;
+
+/**
+ * ͨ������CommandGroupKey��Ŀ����Я��Invocation���־�̬��Ϣ������CircutBreakerEvent��ȡ��
+ */
+public class CustomizeCommandGroupKey extends HystrixKey.HystrixKeyDefault implements HystrixCommandGroupKey {
+
+ private Invocation instance;
+
+ public CustomizeCommandGroupKey(String key) {
+ super(key);
+ }
+
+ private static final InternMap<String, CustomizeCommandGroupKey> intern = new InternMap<String, CustomizeCommandGroupKey>(
+ new InternMap.ValueConstructor<String, CustomizeCommandGroupKey>() {
+ @Override
+ public CustomizeCommandGroupKey create(String key) {
+ return new CustomizeCommandGroupKey(key);
+ }
+ });
+
+ public static HystrixCommandGroupKey asKey(String key, Invocation invocation) {
+ CustomizeCommandGroupKey result = intern.interned(key);
+ result.setInvocation(invocation);
+ return result;
+ }
+
+ public void setInvocation(Invocation invocation) {
+ this.instance = invocation;
+ }
+
+ public Invocation getInstance() {
+ return instance;
+ }
+}
diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/event/CircutBreakerEvent.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/event/CircutBreakerEvent.java
new file mode 100644
index 0000000..c9f7a8e
--- /dev/null
+++ b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/event/CircutBreakerEvent.java
@@ -0,0 +1,113 @@
+/*
+ * 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.bizkeeper.event;
+
+
+import org.apache.servicecomb.bizkeeper.CustomizeCommandGroupKey;
+import org.apache.servicecomb.foundation.common.event.AlarmEvent;
+
+import com.netflix.hystrix.HystrixCommandKey;
+import com.netflix.hystrix.HystrixCommandMetrics;
+
+public class CircutBreakerEvent extends AlarmEvent {
+
+ private String role;
+
+ private String microservice;
+
+ private String schema;
+
+ private String operation;
+
+ //当前总请求数
+ private long currentTotalRequest;
+
+ //当前请求出错计数
+ private long currentErrorCount;
+
+ //当前请求出错百分比
+ private long currentErrorPercentage;
+
+ private int requestVolumeThreshold;
+
+ private int sleepWindowInMilliseconds;
+
+ private int errorThresholdPercentage;
+
+ public CircutBreakerEvent(HystrixCommandKey commandKey, Type type) {
+ super(type);
+ HystrixCommandMetrics hystrixCommandMetrics = HystrixCommandMetrics.getInstance(commandKey);
+ if (hystrixCommandMetrics != null) {
+ if (hystrixCommandMetrics.getCommandGroup() instanceof CustomizeCommandGroupKey) {
+ CustomizeCommandGroupKey customCommandGroupKey =
+ (CustomizeCommandGroupKey) hystrixCommandMetrics.getCommandGroup();
+ this.microservice = customCommandGroupKey.getInstance().getMicroserviceName();
+ this.role = customCommandGroupKey.getInstance().getInvocationType().name();
+ this.schema = customCommandGroupKey.getInstance().getSchemaId();
+ this.operation = customCommandGroupKey.getInstance().getOperationName();
+ }
+ this.currentTotalRequest = hystrixCommandMetrics.getHealthCounts().getTotalRequests();
+ this.currentErrorPercentage = hystrixCommandMetrics.getHealthCounts().getErrorCount();
+ this.currentErrorCount = hystrixCommandMetrics.getHealthCounts().getErrorPercentage();
+ this.requestVolumeThreshold = hystrixCommandMetrics.getProperties().circuitBreakerRequestVolumeThreshold().get();
+ this.sleepWindowInMilliseconds =
+ hystrixCommandMetrics.getProperties().circuitBreakerSleepWindowInMilliseconds().get();
+ this.errorThresholdPercentage =
+ hystrixCommandMetrics.getProperties().circuitBreakerErrorThresholdPercentage().get();
+ }
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public String getMicroservice() {
+ return microservice;
+ }
+
+ public String getSchema() {
+ return schema;
+ }
+
+ public String getOperation() {
+ return operation;
+ }
+
+ public long getCurrentTotalRequest() {
+ return currentTotalRequest;
+ }
+
+ public long getCurrentErrorCount() {
+ return currentErrorCount;
+ }
+
+ public long getCurrentErrorPercentage() {
+ return currentErrorPercentage;
+ }
+
+ public int getRequestVolumeThreshold() {
+ return requestVolumeThreshold;
+ }
+
+ public int getSleepWindowInMilliseconds() {
+ return sleepWindowInMilliseconds;
+ }
+
+ public int getErrorThresholdPercentage() {
+ return errorThresholdPercentage;
+ }
+}
diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/event/CircutBreakerEventNotifier.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/event/CircutBreakerEventNotifier.java
new file mode 100644
index 0000000..3b47b5f
--- /dev/null
+++ b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/event/CircutBreakerEventNotifier.java
@@ -0,0 +1,61 @@
+/*
+ * 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.bizkeeper.event;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.servicecomb.foundation.common.event.EventManager;
+import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx;
+import org.apache.servicecomb.foundation.common.event.AlarmEvent.Type;
+
+import com.google.common.eventbus.EventBus;
+import com.netflix.hystrix.HystrixCommandKey;
+import com.netflix.hystrix.HystrixEventType;
+import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
+
+public class CircutBreakerEventNotifier extends HystrixEventNotifier {
+
+ /**
+ * 使用circuitFlag来记录被熔断的接口
+ */
+ private ConcurrentHashMapEx<String, AtomicBoolean> circuitFlag = new ConcurrentHashMapEx<>();
+
+ EventBus eventBus = EventManager.getEventBus();
+
+ @Override
+ public void markEvent(HystrixEventType eventType, HystrixCommandKey key) {
+ String keyName = key.name();
+ AtomicBoolean flag = circuitFlag.computeIfAbsent(keyName, k -> new AtomicBoolean());
+ switch (eventType) {
+ case SHORT_CIRCUITED:
+ if (flag.compareAndSet(false, true)) {
+ eventBus.post(new CircutBreakerEvent(key, Type.OPEN));
+ }
+ break;
+
+ case SUCCESS:
+ if (flag.compareAndSet(true, false)) {
+ eventBus.post(new CircutBreakerEvent(key, Type.CLOSE));
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
diff --git a/handlers/handler-bizkeeper/src/main/resources/hystrix-plugins.properties b/handlers/handler-bizkeeper/src/main/resources/hystrix-plugins.properties
new file mode 100644
index 0000000..ba987ff
--- /dev/null
+++ b/handlers/handler-bizkeeper/src/main/resources/hystrix-plugins.properties
@@ -0,0 +1 @@
+hystrix.plugin.HystrixEventNotifier.implementation=org.apache.servicecomb.bizkeeper.event.CircutBreakerEventNotifier
\ No newline at end of file
diff --git a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperCommand.java b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperCommand.java
index be3e6be..9629d32 100644
--- a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperCommand.java
+++ b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperCommand.java
@@ -39,7 +39,6 @@ public class TestBizkeeperCommand {
Invocation invocation = Mockito.mock(Invocation.class);
Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class));
Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1");
-
HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter()
.withRequestCacheEnabled(true)
.withRequestLogEnabled(false);
@@ -72,7 +71,6 @@ public class TestBizkeeperCommand {
Invocation invocation = Mockito.mock(Invocation.class);
Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class));
Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1");
-
HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter()
.withRequestCacheEnabled(true)
.withRequestLogEnabled(false);
@@ -93,7 +91,6 @@ public class TestBizkeeperCommand {
Invocation invocation = Mockito.mock(Invocation.class);
Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class));
Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1");
-
HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter()
.withRequestCacheEnabled(true)
.withRequestLogEnabled(false);
@@ -114,7 +111,6 @@ public class TestBizkeeperCommand {
Invocation invocation = Mockito.mock(Invocation.class);
Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class));
Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1");
-
HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter()
.withRequestCacheEnabled(true)
.withRequestLogEnabled(false);
@@ -136,7 +132,6 @@ public class TestBizkeeperCommand {
Invocation invocation = Mockito.mock(Invocation.class);
Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class));
Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1");
-
HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter()
.withRequestCacheEnabled(true)
.withRequestLogEnabled(false);
@@ -169,7 +164,6 @@ public class TestBizkeeperCommand {
Invocation invocation = Mockito.mock(Invocation.class);
Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class));
Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1");
-
HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter()
.withRequestCacheEnabled(true)
.withRequestLogEnabled(false);
@@ -190,7 +184,6 @@ public class TestBizkeeperCommand {
Invocation invocation = Mockito.mock(Invocation.class);
Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class));
Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1");
-
HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter()
.withRequestCacheEnabled(true)
.withRequestLogEnabled(false);
@@ -211,7 +204,6 @@ public class TestBizkeeperCommand {
Invocation invocation = Mockito.mock(Invocation.class);
Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class));
Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1");
-
HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter()
.withRequestCacheEnabled(true)
.withRequestLogEnabled(false);
diff --git a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestCustomCommandGroupKey.java b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestCustomCommandGroupKey.java
new file mode 100644
index 0000000..9bcf64e
--- /dev/null
+++ b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestCustomCommandGroupKey.java
@@ -0,0 +1,44 @@
+/*
+ * 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.bizkeeper;
+
+import org.apache.servicecomb.core.Invocation;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class TestCustomCommandGroupKey {
+ @Test
+ public void testToHystrixCommandGroupKey() {
+ Invocation invocation = Mockito.mock(Invocation.class);
+ CustomizeCommandGroupKey customizeCommandGroupKey =
+ (CustomizeCommandGroupKey) CustomizeCommandGroupKey.asKey("key", invocation);
+ Assert.assertEquals(invocation, customizeCommandGroupKey.getInstance());
+ }
+
+ @Test
+ public void testOOM() {
+ Invocation invocation1 = Mockito.mock(Invocation.class);
+ Invocation invocation2 = Mockito.mock(Invocation.class);
+ CustomizeCommandGroupKey customizeCommandGroupKey1 =
+ (CustomizeCommandGroupKey) CustomizeCommandGroupKey.asKey("key", invocation1);
+ CustomizeCommandGroupKey customizeCommandGroupKey2 =
+ (CustomizeCommandGroupKey) CustomizeCommandGroupKey.asKey("key", invocation2);
+ Assert.assertEquals(customizeCommandGroupKey1, customizeCommandGroupKey2);
+ }
+}
diff --git a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/event/TestCircutBreakerEventNotifier.java b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/event/TestCircutBreakerEventNotifier.java
new file mode 100644
index 0000000..3f58ca7
--- /dev/null
+++ b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/event/TestCircutBreakerEventNotifier.java
@@ -0,0 +1,79 @@
+/*
+ * 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.bizkeeper.event;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.servicecomb.foundation.common.event.AlarmEvent;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import com.google.common.eventbus.Subscribe;
+import com.netflix.hystrix.HystrixCommandKey;
+import com.netflix.hystrix.HystrixCommandMetrics;
+import com.netflix.hystrix.HystrixEventType;
+
+import mockit.Expectations;
+
+public class TestCircutBreakerEventNotifier {
+ private List<AlarmEvent> taskList = null;
+
+ CircutBreakerEventNotifier circutBreakerEventNotifier;
+
+ HystrixCommandKey commandKey = null;
+
+ Object receiveEvent = null;
+
+ @Before
+ public void setUp() throws Exception {
+ taskList = new ArrayList<>();
+ circutBreakerEventNotifier = new CircutBreakerEventNotifier();
+ commandKey = Mockito.mock(HystrixCommandKey.class);
+ receiveEvent = new Object() {
+ @Subscribe
+ public void onEvent(AlarmEvent circutBreakerEvent) {
+ taskList.add(circutBreakerEvent);
+ }
+ };
+ circutBreakerEventNotifier.eventBus.register(receiveEvent);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ circutBreakerEventNotifier.eventBus.unregister(receiveEvent);
+ }
+
+ @Test
+ public void testMarkEvent() {
+ Mockito.when(commandKey.name()).thenReturn("Consumer.springmvc.springmvcHello.sayHi");
+ new Expectations(HystrixCommandMetrics.class) {
+ {
+ HystrixCommandMetrics.getInstance(commandKey);
+ result = null;
+ }
+ };
+ circutBreakerEventNotifier.markEvent(HystrixEventType.SHORT_CIRCUITED, commandKey);
+ Assert.assertEquals(1, taskList.size());
+ circutBreakerEventNotifier.markEvent(HystrixEventType.SUCCESS, commandKey);
+ Assert.assertEquals(2, taskList.size());
+ }
+}
diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/event/IsolationServerEvent.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/event/IsolationServerEvent.java
new file mode 100644
index 0000000..93218c9
--- /dev/null
+++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/event/IsolationServerEvent.java
@@ -0,0 +1,87 @@
+/*
+ * 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.loadbalance.event;
+
+import org.apache.servicecomb.foundation.common.event.AlarmEvent;
+
+public class IsolationServerEvent extends AlarmEvent {
+
+ private String microserviceName;
+
+ //当前实例总请求数
+ private long currentTotalRequest;
+
+ //当前实例连续出错次数
+ private int currentCountinuousFailureCount;
+
+ //当前实例出错百分比
+ private double currentErrorPercentage;
+
+ private long enableRequestThreshold;
+
+ private int continuousFailureThreshold;
+
+ private int errorThresholdPercentage;
+
+ private long singleTestTime;
+
+ public IsolationServerEvent(String microserviceName, long totalRequest, int currentCountinuousFailureCount,
+ double currentErrorPercentage, int continuousFailureThreshold,
+ int errorThresholdPercentage, long enableRequestThreshold, long singleTestTime, Type type) {
+ super(type);
+ this.microserviceName = microserviceName;
+ this.currentTotalRequest = totalRequest;
+ this.currentCountinuousFailureCount = currentCountinuousFailureCount;
+ this.currentErrorPercentage = currentErrorPercentage;
+ this.enableRequestThreshold = enableRequestThreshold;
+ this.continuousFailureThreshold = continuousFailureThreshold;
+ this.errorThresholdPercentage = errorThresholdPercentage;
+ this.singleTestTime = singleTestTime;
+ }
+
+ public String getMicroserviceName() {
+ return microserviceName;
+ }
+
+ public long getCurrentTotalRequest() {
+ return currentTotalRequest;
+ }
+
+ public int getCurrentCountinuousFailureCount() {
+ return currentCountinuousFailureCount;
+ }
+
+ public double getCurrentErrorPercentage() {
+ return currentErrorPercentage;
+ }
+
+ public long getEnableRequestThreshold() {
+ return enableRequestThreshold;
+ }
+
+ public int getContinuousFailureThreshold() {
+ return continuousFailureThreshold;
+ }
+
+ public int getErrorThresholdPercentage() {
+ return errorThresholdPercentage;
+ }
+
+ public long getSingleTestTime() {
+ return singleTestTime;
+ }
+}
diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/IsolationServerListFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/IsolationServerListFilter.java
index 5d263e0..91724d9 100644
--- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/IsolationServerListFilter.java
+++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/IsolationServerListFilter.java
@@ -20,12 +20,16 @@ package org.apache.servicecomb.loadbalance.filter;
import java.util.ArrayList;
import java.util.List;
+import org.apache.servicecomb.foundation.common.event.AlarmEvent.Type;
+import org.apache.servicecomb.foundation.common.event.EventManager;
import org.apache.servicecomb.loadbalance.Configuration;
import org.apache.servicecomb.loadbalance.CseServer;
import org.apache.servicecomb.loadbalance.ServerListFilterExt;
+import org.apache.servicecomb.loadbalance.event.IsolationServerEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.eventbus.EventBus;
import com.netflix.loadbalancer.LoadBalancerStats;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerStats;
@@ -48,6 +52,8 @@ public final class IsolationServerListFilter implements ServerListFilterExt {
private LoadBalancerStats stats;
+ public EventBus eventBus = EventManager.getEventBus();
+
public void setLoadBalancerStats(LoadBalancerStats stats) {
this.stats = stats;
}
@@ -91,19 +97,22 @@ public final class IsolationServerListFilter implements ServerListFilterExt {
ServerStats serverStats = stats.getSingleServerStat(server);
long totalRequest = serverStats.getTotalRequestsCount();
long failureRequest = serverStats.getSuccessiveConnectionFailureCount();
-
+ int currentCountinuousFailureCount = 0;
+ double currentErrorThresholdPercentage = 0;
if (totalRequest < enableRequestThreshold) {
return true;
}
if (continuousFailureThreshold > 0) {
// continuousFailureThreshold has higher priority to decide the result
- if (((CseServer) server).getCountinuousFailureCount() < continuousFailureThreshold) {
+ currentCountinuousFailureCount = ((CseServer) server).getCountinuousFailureCount();
+ if (currentCountinuousFailureCount < continuousFailureThreshold) {
return true;
}
} else {
// if continuousFailureThreshold, then check error percentage
- if ((failureRequest / (double) totalRequest) * PERCENT < errorThresholdPercentage) {
+ currentErrorThresholdPercentage = (failureRequest / (double) totalRequest) * PERCENT;
+ if (currentErrorThresholdPercentage < errorThresholdPercentage) {
return true;
}
}
@@ -112,10 +121,18 @@ public final class IsolationServerListFilter implements ServerListFilterExt {
LOGGER.info("The Service {}'s instance {} has been break, will give a single test opportunity.",
microserviceName,
server);
+ eventBus.post(new IsolationServerEvent(microserviceName, totalRequest, currentCountinuousFailureCount,
+ currentErrorThresholdPercentage,
+ continuousFailureThreshold, errorThresholdPercentage, enableRequestThreshold,
+ singleTestTime, Type.CLOSE));
return true;
}
LOGGER.warn("The Service {}'s instance {} has been break!", microserviceName, server);
+ eventBus.post(new IsolationServerEvent(microserviceName, totalRequest, currentCountinuousFailureCount,
+ currentErrorThresholdPercentage,
+ continuousFailureThreshold, errorThresholdPercentage, enableRequestThreshold,
+ singleTestTime, Type.OPEN));
return false;
}
}
diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/TestIsolationServerListFilter.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/TestIsolationServerListFilter.java
index e7a25ec..be767f7 100644
--- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/TestIsolationServerListFilter.java
+++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/TestIsolationServerListFilter.java
@@ -23,6 +23,8 @@ import java.util.List;
import org.apache.commons.configuration.AbstractConfiguration;
import org.apache.servicecomb.config.ConfigUtil;
import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.foundation.common.event.AlarmEvent;
+import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
import org.apache.servicecomb.loadbalance.CseServer;
import org.junit.After;
import org.junit.AfterClass;
@@ -32,19 +34,21 @@ import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;
-import com.netflix.config.ConfigurationManager;
+import com.google.common.eventbus.Subscribe;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.loadbalancer.LoadBalancerStats;
import com.netflix.loadbalancer.Server;
-import mockit.Deencapsulation;
-
public class TestIsolationServerListFilter {
- IsolationServerListFilter IsolationServerListFilter = null;
+ IsolationServerListFilter isolationServerListFilter = null;
LoadBalancerStats loadBalancerStats = null;
+ private List<AlarmEvent> taskList = null;
+
+ Object receiveEvent = null;
+
@BeforeClass
public static void initConfig() throws Exception {
ConfigUtil.installDynamicConfig();
@@ -52,29 +56,32 @@ public class TestIsolationServerListFilter {
@AfterClass
public static void classTeardown() {
- Deencapsulation.setField(ConfigurationManager.class, "instance", null);
- Deencapsulation.setField(ConfigurationManager.class, "customConfigurationInstalled", false);
- Deencapsulation.setField(DynamicPropertyFactory.class, "config", null);
+ ArchaiusUtils.resetConfig();
}
@Before
public void setUp() throws Exception {
- IsolationServerListFilter = new IsolationServerListFilter();
+ isolationServerListFilter = new IsolationServerListFilter();
loadBalancerStats = new LoadBalancerStats("loadBalancer");
-
- AbstractConfiguration configuration =
- (AbstractConfiguration) DynamicPropertyFactory.getBackingConfigurationSource();
- configuration.clearProperty("cse.loadbalance.isolation.enabled");
- configuration.addProperty("cse.loadbalance.isolation.enabled",
+ ArchaiusUtils.setProperty("cse.loadbalance.isolation.enabled",
"true");
- configuration.clearProperty("cse.loadbalance.isolation.enableRequestThreshold");
- configuration.addProperty("cse.loadbalance.isolation.enableRequestThreshold",
+ ArchaiusUtils.setProperty("cse.loadbalance.isolation.enableRequestThreshold",
"3");
+
+ taskList = new ArrayList<>();
+ receiveEvent = new Object() {
+ @Subscribe
+ public void onEvent(AlarmEvent isolationServerEvent) {
+ taskList.add(isolationServerEvent);
+ }
+ };
+ isolationServerListFilter.eventBus.register(receiveEvent);
}
@After
public void tearDown() throws Exception {
- IsolationServerListFilter = null;
+ isolationServerListFilter.eventBus.unregister(receiveEvent);
+ isolationServerListFilter = null;
loadBalancerStats = null;
AbstractConfiguration configuration =
@@ -84,16 +91,16 @@ public class TestIsolationServerListFilter {
@Test
public void testSetLoadBalancerStats() {
- IsolationServerListFilter.setLoadBalancerStats(loadBalancerStats);
- Assert.assertNotNull(IsolationServerListFilter.getLoadBalancerStats());
- Assert.assertEquals(loadBalancerStats, IsolationServerListFilter.getLoadBalancerStats());
+ isolationServerListFilter.setLoadBalancerStats(loadBalancerStats);
+ Assert.assertNotNull(isolationServerListFilter.getLoadBalancerStats());
+ Assert.assertEquals(loadBalancerStats, isolationServerListFilter.getLoadBalancerStats());
}
@Test
public void testSetMicroserviceName() {
- IsolationServerListFilter.setMicroserviceName("microserviceName");
- Assert.assertNotNull(IsolationServerListFilter.getMicroserviceName());
- Assert.assertEquals("microserviceName", IsolationServerListFilter.getMicroserviceName());
+ isolationServerListFilter.setMicroserviceName("microserviceName");
+ Assert.assertNotNull(isolationServerListFilter.getMicroserviceName());
+ Assert.assertEquals("microserviceName", isolationServerListFilter.getMicroserviceName());
}
@Test
@@ -105,16 +112,16 @@ public class TestIsolationServerListFilter {
List<Server> serverList = new ArrayList<>();
serverList.add(testServer);
- IsolationServerListFilter.setLoadBalancerStats(loadBalancerStats);
- IsolationServerListFilter.setInvocation(invocation);
- List<Server> returnedServerList = IsolationServerListFilter.getFilteredListOfServers(serverList);
+ isolationServerListFilter.setLoadBalancerStats(loadBalancerStats);
+ isolationServerListFilter.setInvocation(invocation);
+ List<Server> returnedServerList = isolationServerListFilter.getFilteredListOfServers(serverList);
Assert.assertEquals(returnedServerList.size(), 1);
loadBalancerStats.incrementNumRequests(testServer);
loadBalancerStats.incrementNumRequests(testServer);
loadBalancerStats.incrementNumRequests(testServer);
loadBalancerStats.incrementSuccessiveConnectionFailureCount(testServer);
- returnedServerList = IsolationServerListFilter.getFilteredListOfServers(serverList);
+ returnedServerList = isolationServerListFilter.getFilteredListOfServers(serverList);
Assert.assertEquals(returnedServerList.size(), 0);
}
@@ -135,10 +142,11 @@ public class TestIsolationServerListFilter {
List<Server> serverList = new ArrayList<>();
serverList.add(testServer);
- IsolationServerListFilter.setLoadBalancerStats(loadBalancerStats);
- IsolationServerListFilter.setInvocation(invocation);
- List<Server> returnedServerList = IsolationServerListFilter.getFilteredListOfServers(serverList);
+ isolationServerListFilter.setLoadBalancerStats(loadBalancerStats);
+ isolationServerListFilter.setInvocation(invocation);
+ List<Server> returnedServerList = isolationServerListFilter.getFilteredListOfServers(serverList);
Assert.assertEquals(0, returnedServerList.size());
+ Assert.assertEquals(1, taskList.size());
}
@Test
@@ -158,9 +166,9 @@ public class TestIsolationServerListFilter {
List<Server> serverList = new ArrayList<>();
serverList.add(testServer);
- IsolationServerListFilter.setLoadBalancerStats(loadBalancerStats);
- IsolationServerListFilter.setInvocation(invocation);
- List<Server> returnedServerList = IsolationServerListFilter.getFilteredListOfServers(serverList);
+ isolationServerListFilter.setLoadBalancerStats(loadBalancerStats);
+ isolationServerListFilter.setInvocation(invocation);
+ List<Server> returnedServerList = isolationServerListFilter.getFilteredListOfServers(serverList);
Assert.assertEquals(1, returnedServerList.size());
}
}