[ https://issues.apache.org/jira/browse/SCB-506?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16509292#comment-16509292 ]
ASF GitHub Bot commented on SCB-506: ------------------------------------ xuyiyun0929 closed pull request #678: [SCB-506]服务治理相关的需要事件上报 URL: https://github.com/apache/incubator-servicecomb-java-chassis/pull/678 This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/AlarmEvent.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/AlarmEvent.java new file mode 100644 index 000000000..1f100c148 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/AlarmEvent.java @@ -0,0 +1,35 @@ +/* + * 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.foundation.common.event; + +public class AlarmEvent { + + Type type; + + public AlarmEvent(Type type) { + this.type = type; + } + + public Type getType() { + return this.type; + } + + 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 a4e0aa428..90d3672e5 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,7 @@ private CommandKey() { } public static HystrixCommandGroupKey toHystrixCommandGroupKey(String type, Invocation invocation) { - return HystrixCommandGroupKey.Factory - .asKey(type + "." + invocation.getOperationMeta().getMicroserviceQualifiedName()); + return CustomizeCommandGroupKey.asKey(type, 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 000000000..cdb5b6f2e --- /dev/null +++ b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/CustomizeCommandGroupKey.java @@ -0,0 +1,73 @@ +/* + * 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; + +public class CustomizeCommandGroupKey extends HystrixKey.HystrixKeyDefault implements HystrixCommandGroupKey { + + private String invocationType; + + private String microserviceName; + + private String schema; + + private String operation; + + public CustomizeCommandGroupKey(Invocation invocation) { + super(invocation.getInvocationType().name() + "." + invocation.getOperationMeta().getMicroserviceQualifiedName()); + this.invocationType = invocation.getInvocationType().name(); + this.microserviceName = invocation.getMicroserviceName(); + this.schema = invocation.getSchemaId(); + this.operation = invocation.getOperationName(); + } + + private static final InternMap<Invocation, CustomizeCommandGroupKey> intern = + new InternMap<Invocation, CustomizeCommandGroupKey>( + new InternMap.ValueConstructor<Invocation, CustomizeCommandGroupKey>() { + @Override + public CustomizeCommandGroupKey create(Invocation invocation) { + return new CustomizeCommandGroupKey(invocation); + } + }); + + + public static HystrixCommandGroupKey asKey(String type, Invocation invocation) { + return intern.interned(invocation); + } + + public String getInvocationType() { + return invocationType; + } + + public String getMicroserviceName() { + return microserviceName; + } + + public String getOperation() { + return operation; + } + + public String getSchema() { + return schema; + } +} 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 000000000..8045a5f35 --- /dev/null +++ b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/event/CircutBreakerEvent.java @@ -0,0 +1,112 @@ +/* + * 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) { + CustomizeCommandGroupKey customizeCommandGroupKey = + (CustomizeCommandGroupKey) hystrixCommandMetrics.getCommandGroup(); + this.microservice = customizeCommandGroupKey.getMicroserviceName(); + this.role = customizeCommandGroupKey.getInvocationType(); + this.schema = customizeCommandGroupKey.getSchema(); + this.operation = customizeCommandGroupKey.getOperation(); + 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 000000000..3b47b5f20 --- /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 000000000..ba987ff21 --- /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 be3e6be59..c75294ba6 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 @@ -19,6 +19,7 @@ import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.swagger.invocation.InvocationType; import org.apache.servicecomb.swagger.invocation.Response; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; import org.junit.Assert; @@ -39,7 +40,7 @@ public void testGetCacheKeyProvider() { Invocation invocation = Mockito.mock(Invocation.class); Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - + Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.PRODUCER); HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() .withRequestCacheEnabled(true) .withRequestLogEnabled(false); @@ -72,7 +73,7 @@ public void testResumeWithFallbackProvider() { Invocation invocation = Mockito.mock(Invocation.class); Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - + Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.PRODUCER); HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() .withRequestCacheEnabled(true) .withRequestLogEnabled(false); @@ -93,7 +94,7 @@ public void testConstructProvider() { Invocation invocation = Mockito.mock(Invocation.class); Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - + Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.PRODUCER); HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() .withRequestCacheEnabled(true) .withRequestLogEnabled(false); @@ -114,7 +115,7 @@ public void testGetCacheKeyWithContextInitializedProvider() { Invocation invocation = Mockito.mock(Invocation.class); Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - + Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.PRODUCER); HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() .withRequestCacheEnabled(true) .withRequestLogEnabled(false); @@ -136,7 +137,7 @@ public void testGetCacheKeyConsumer() { Invocation invocation = Mockito.mock(Invocation.class); Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - + Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.CONSUMER); HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() .withRequestCacheEnabled(true) .withRequestLogEnabled(false); @@ -169,7 +170,7 @@ public void testResumeWithFallbackConsumer() { Invocation invocation = Mockito.mock(Invocation.class); Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - + Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.CONSUMER); HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() .withRequestCacheEnabled(true) .withRequestLogEnabled(false); @@ -190,7 +191,7 @@ public void testConstructConsumer() { Invocation invocation = Mockito.mock(Invocation.class); Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - + Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.CONSUMER); HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() .withRequestCacheEnabled(true) .withRequestLogEnabled(false); @@ -211,7 +212,7 @@ public void testGetCacheKeyWithContextInitializedConsumer() { Invocation invocation = Mockito.mock(Invocation.class); Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - + Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.CONSUMER); HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() .withRequestCacheEnabled(true) .withRequestLogEnabled(false); diff --git a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperHandler.java b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperHandler.java index 4c0cb644a..2a9de6c6a 100644 --- a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperHandler.java +++ b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperHandler.java @@ -87,6 +87,7 @@ public void testHandle() { Mockito.when(invocation.getMicroserviceName()).thenReturn("test1"); Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); + Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.CONSUMER); validAssert = true; bizkeeperHandler.handle(invocation, asyncResp); @@ -157,6 +158,7 @@ public void testHandleInError() throws Exception { Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()) .thenReturn("testHandleInError"); + Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.CONSUMER); FallbackPolicy policy = Mockito.mock(FallbackPolicy.class); Mockito.when(policy.name()).thenReturn("throwException"); Mockito.when(policy.getFallbackResponse(Mockito.any(Invocation.class))).thenThrow(new RuntimeException()); @@ -181,6 +183,7 @@ public void testHandlNextException() throws Exception { Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()) .thenReturn("testHandlNextException"); + Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.CONSUMER); Mockito.doThrow(new Exception("testHandlNextException")).when(invocation).next(Mockito.any(AsyncResponse.class)); bizkeeperHandler.handle(invocation, f -> { Assert.assertTrue(f.isFailed()); @@ -193,6 +196,7 @@ public void testHandleSuccess() throws Exception { Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()) .thenReturn("testHandleSuccess"); + Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.CONSUMER); Mockito.doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) { diff --git a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestCommandKey.java b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestCommandKey.java index 29c03caa9..841eca843 100644 --- a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestCommandKey.java +++ b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestCommandKey.java @@ -19,6 +19,7 @@ import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.swagger.invocation.InvocationType; import org.junit.Assert; import org.junit.Test; import org.mockito.Mockito; @@ -38,6 +39,7 @@ public void testToHystrixCommandGroupKey() { Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); + Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.CONSUMER); Assert.assertNotNull(invocation); HystrixCommandGroupKey hystrixCommandGroupKey = CommandKey.toHystrixCommandGroupKey("groupname", invocation); Assert.assertNotNull(hystrixCommandGroupKey); diff --git a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestConsumerBizkeeperHandler.java b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestConsumerBizkeeperHandler.java index b50a5d0e8..39ccf294e 100644 --- a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestConsumerBizkeeperHandler.java +++ b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestConsumerBizkeeperHandler.java @@ -19,6 +19,7 @@ import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.swagger.invocation.InvocationType; import org.junit.Assert; import org.junit.Test; import org.mockito.Mockito; @@ -39,6 +40,7 @@ public void testCreateBizkeeperCommand() { Invocation invocation = Mockito.mock(Invocation.class); Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); + Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.CONSUMER); CommandKey.toHystrixCommandGroupKey("groupname", invocation); CommandKey.toHystrixCommandKey("groupname", invocation); 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 000000000..507b760d1 --- /dev/null +++ b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestCustomCommandGroupKey.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.bizkeeper; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.swagger.invocation.InvocationType; +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); + Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); + Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test2"); + Mockito.when(invocation.getMicroserviceName()).thenReturn("microserviceName"); + Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.CONSUMER); + Mockito.when(invocation.getSchemaId()).thenReturn("schemaId"); + Mockito.when(invocation.getOperationName()).thenReturn("operationName"); + CustomizeCommandGroupKey customizeCommandGroupKey = + (CustomizeCommandGroupKey) CustomizeCommandGroupKey.asKey("type", invocation); + Assert.assertEquals("CONSUMER", customizeCommandGroupKey.getInvocationType()); + Assert.assertEquals("microserviceName", customizeCommandGroupKey.getMicroserviceName()); + Assert.assertEquals("schemaId", customizeCommandGroupKey.getSchema()); + Assert.assertEquals("operationName", customizeCommandGroupKey.getOperation()); + } +} diff --git a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestProviderBizkeeperHandler.java b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestProviderBizkeeperHandler.java index 467993aad..78c1e0aa0 100644 --- a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestProviderBizkeeperHandler.java +++ b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestProviderBizkeeperHandler.java @@ -19,6 +19,7 @@ import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.swagger.invocation.InvocationType; import org.junit.Assert; import org.junit.Test; import org.mockito.Mockito; @@ -39,6 +40,7 @@ public void testCreateBizkeeperCommand() { Invocation invocation = Mockito.mock(Invocation.class); Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); + Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.CONSUMER); CommandKey.toHystrixCommandGroupKey("groupname", invocation); CommandKey.toHystrixCommandKey("groupname", invocation); 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 000000000..3f58ca75c --- /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 000000000..93218c967 --- /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 5d263e059..91724d9fd 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 @@ 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 @@ private LoadBalancerStats stats; + public EventBus eventBus = EventManager.getEventBus(); + public void setLoadBalancerStats(LoadBalancerStats stats) { this.stats = stats; } @@ -91,19 +97,22 @@ private boolean allowVisit(Server server) { 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 @@ private boolean allowVisit(Server server) { 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 e7a25ec34..be767f7a7 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 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.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 static void initConfig() throws Exception { @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 void tearDown() throws Exception { @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 void testGetFilteredListOfServers() { 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 void testGetFilteredListOfServersOnContinuousFailureReachesThreshold() { 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 void testGetFilteredListOfServersOnContinuousFailureIsBelowThreshold() { 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()); } } ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org > 服务治理相关的需要事件上报 > ------------- > > Key: SCB-506 > URL: https://issues.apache.org/jira/browse/SCB-506 > Project: Apache ServiceComb > Issue Type: Task > Components: Java-Chassis > Reporter: xuyiyun > Assignee: xuyiyun > Priority: Major > Fix For: Java-chassis-1.0.0 > > > 如果发生服务降级 实例隔离 熔断等操作,业务监控系统需要能获取到对应的通知,方便集成 -- This message was sent by Atlassian JIRA (v7.6.3#76005)