diff --git a/sermant-plugins/sermant-router/dubbo-router-service/src/test/java/com/huaweicloud/sermant/router/dubbo/handler/TagRouteHandlerTest.java b/sermant-plugins/sermant-router/dubbo-router-service/src/test/java/com/huaweicloud/sermant/router/dubbo/handler/TagRouteHandlerTest.java index 5efc11bc98..612b6b3a3c 100644 --- a/sermant-plugins/sermant-router/dubbo-router-service/src/test/java/com/huaweicloud/sermant/router/dubbo/handler/TagRouteHandlerTest.java +++ b/sermant-plugins/sermant-router/dubbo-router-service/src/test/java/com/huaweicloud/sermant/router/dubbo/handler/TagRouteHandlerTest.java @@ -16,6 +16,8 @@ package com.huaweicloud.sermant.router.dubbo.handler; +import com.huaweicloud.sermant.core.config.ConfigManager; +import com.huaweicloud.sermant.core.event.config.EventConfig; import com.huaweicloud.sermant.router.common.constants.RouterConstant; import com.huaweicloud.sermant.router.config.cache.ConfigCache; import com.huaweicloud.sermant.router.dubbo.ApacheInvoker; @@ -24,15 +26,19 @@ import com.huaweicloud.sermant.router.dubbo.service.AbstractDirectoryServiceTest; import org.apache.dubbo.rpc.Invocation; +import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; -import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.ArrayList; import java.util.Map; +import java.util.Collections; + /** * TagRouteHandler单元测试 @@ -43,14 +49,30 @@ public class TagRouteHandlerTest { private static TagRouteHandler tagRouteHandler; + private static EventConfig config; + + private static MockedStatic mockConfigManager; + /** * UT执行前进行mock */ @BeforeClass public static void before() { + config = new EventConfig(); + config.setEnable(false); + mockConfigManager = Mockito.mockStatic(ConfigManager.class); + mockConfigManager.when(() -> ConfigManager.getConfig(EventConfig.class)).thenReturn(config); tagRouteHandler = new TagRouteHandler(); } + /** + * UT执行后释放资源 + */ + @AfterClass + public static void after(){ + mockConfigManager.close(); + } + /** * 测试getGetTargetInstances方法 */ diff --git a/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/event/PolicyEvent.java b/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/event/PolicyEvent.java new file mode 100644 index 0000000000..f6203cf014 --- /dev/null +++ b/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/event/PolicyEvent.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * Licensed 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 com.huaweicloud.sermant.router.common.event; + +/** + * Policy事件包含三件: + * 1 相同tag规则匹配生效: 全部可用实例数小于全部实例最小可用阈值,则同TAG优先 + * 2 相同tag规则匹配生效: + * 未设置全部实例最小可用阈值,超过同TAG比例阈值,则同TAG优先; + * 设置了全部实例最小可用阈值,但其小于全部TAG可用实例,超过同TAG比例阈值,则同TAG优先 + * 3. 相同tag规则匹配不生效 + * + * @author robotLJW + * @since 2023-04-03 + * + */ +public enum PolicyEvent { + /** + * 符合相同Tag规则匹配:全部可用实例数小于全部实例最小可用阈值,则同TAG优先 + */ + SAME_TAG_MATCH_LESS_MIN_ALL_INSTANCES("According to the policy in the rule, same tag rule match that less" + + " than the minimum available threshold for all instances"), + + /** + * 符合相同Tag规则匹配:超过同TAG比例阈值,则同TAG优先 + */ + SAME_TAG_MATCH_EXCEEDED_TRIGGER_THRESHOLD("According to the policy in the rule, same tag rule match that" + + " exceeded trigger threshold"), + + /** + * 相同Tag规则匹配没匹配上 + */ + SAME_TAG_MISMATCH("According to the policy in the rule, same tag rule mismatch"); + + /** + * 事件描述 + */ + private String desc; + + PolicyEvent(String desc) { + this.desc = desc; + } + + public String getDesc() { + return this.desc; + } +} diff --git a/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/event/RouterEventCollector.java b/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/event/RouterEventCollector.java index 2e6d51bbd8..9fbfeb13d8 100644 --- a/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/event/RouterEventCollector.java +++ b/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/event/RouterEventCollector.java @@ -85,4 +85,44 @@ public void collectGlobalRouteRuleEvent(String rule) { RouterEventDefinition.ROUTER_RULE_TAKE_EFFECT.getEventType(), new EventInfo(RouterEventDefinition.ROUTER_RULE_TAKE_EFFECT.getName(), eventDescription))); } + + /** + * 采集选取下游serviceName匹配事件 + * + * @param tagMsg tags信息 + * @param serviceName service名 + * @param reason 原因 + */ + public void collectSameTagMatchedEvent(String tagMsg, String serviceName, String reason){ + if (!eventConfig.isEnable()) { + return; + } + String eventDescription = "The matching with the tag ("+tagMsg+") rule takes effect when request service is " + + serviceName +" (reason: " + reason +")"; + offerEvent(new Event(RouterEventDefinition.SAME_TAG_RULE_MATCH_TAKE_EFFECT.getScope(), + RouterEventDefinition.SAME_TAG_RULE_MATCH_TAKE_EFFECT.getEventLevel(), + RouterEventDefinition.SAME_TAG_RULE_MATCH_TAKE_EFFECT.getEventType(), + new EventInfo(RouterEventDefinition.SAME_TAG_RULE_MATCH_TAKE_EFFECT.getName(), eventDescription))); + } + + /** + * 采集选取下游serviceName不匹配事件 + * + * @param tagMsg tags信息 + * @param serviceName service名 + * @param reason 原因 + */ + public void collectSameTagMisMatchedEvent(String tagMsg, String serviceName, String reason){ + if (!eventConfig.isEnable()) { + return; + } + String eventDescription = "The matching with the tag ("+tagMsg+") rule did not take effect when request service is " + + serviceName +" (reason: " + reason +")"; + offerEvent(new Event(RouterEventDefinition.SAME_TAG_RULE_MISMATCH_TAKE_EFFECT.getScope(), + RouterEventDefinition.SAME_TAG_RULE_MISMATCH_TAKE_EFFECT.getEventLevel(), + RouterEventDefinition.SAME_TAG_RULE_MISMATCH_TAKE_EFFECT.getEventType(), + new EventInfo(RouterEventDefinition.SAME_TAG_RULE_MISMATCH_TAKE_EFFECT.getName(), eventDescription))); + } + + } diff --git a/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/event/RouterEventDefinition.java b/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/event/RouterEventDefinition.java index eb271a74d0..beb2c903ba 100644 --- a/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/event/RouterEventDefinition.java +++ b/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/event/RouterEventDefinition.java @@ -30,7 +30,18 @@ public enum RouterEventDefinition { * 路由插件规则生效事件 */ - ROUTER_RULE_TAKE_EFFECT("ROUTER_RULE_TAKE_EFFECT", EventType.GOVERNANCE, EventLevel.NORMAL); + ROUTER_RULE_TAKE_EFFECT("ROUTER_RULE_TAKE_EFFECT", EventType.GOVERNANCE, EventLevel.NORMAL), + + /** + * 同TAG优先规则匹配生效 + */ + SAME_TAG_RULE_MATCH_TAKE_EFFECT( "SAME_TAG_RULE_MATCH_TAKE_EFFECT", EventType.GOVERNANCE, EventLevel.NORMAL), + + /** + * 同TAG优先规则匹配失效 + */ + SAME_TAG_RULE_MISMATCH_TAKE_EFFECT( "SAME_TAG_RULE_MISMATCH_TAKE_EFFECT", EventType.GOVERNANCE, + EventLevel.NORMAL); private final String name; diff --git a/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/utils/PolicyEventUtils.java b/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/utils/PolicyEventUtils.java new file mode 100644 index 0000000000..105098bf94 --- /dev/null +++ b/sermant-plugins/sermant-router/router-common/src/main/java/com/huaweicloud/sermant/router/common/utils/PolicyEventUtils.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * Licensed 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 com.huaweicloud.sermant.router.common.utils; + +import com.huaweicloud.sermant.router.common.event.PolicyEvent; +import com.huaweicloud.sermant.router.common.event.RouterEventCollector; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * Policy事件工具类 + * + * @author robotLJW + * @since 2023-04-06 + */ +public class PolicyEventUtils { + + private static final ConcurrentHashMap MAP = new ConcurrentHashMap<>(); + + private PolicyEventUtils() { + } + + /** + * + * @param newState 新匹配状态 + * @param tagMsg tag信息 + * @param serviceName 服务名 + */ + public static void notifySameTagMatchedEvent(PolicyEvent newState, String tagMsg, String serviceName) { + PolicyEvent previousState = MAP.get(serviceName); + if (!newState.equals(previousState)) { + MAP.put(serviceName, newState); + RouterEventCollector.getInstance().collectSameTagMatchedEvent(tagMsg, serviceName, newState.getDesc()); + } + } + + /** + * + * @param newState 新匹配状态 + * @param tagMsg tag信息 + * @param serviceName 服务名 + */ + public static void notifySameTagMisMatchedEvent(PolicyEvent newState, String tagMsg, String serviceName) { + PolicyEvent previousState = MAP.get(serviceName); + if (!newState.equals(previousState)) { + MAP.put(serviceName, newState); + RouterEventCollector.getInstance().collectSameTagMisMatchedEvent(tagMsg, serviceName, newState.getDesc()); + } + } + +} diff --git a/sermant-plugins/sermant-router/router-config-common/src/main/java/com/huaweicloud/sermant/router/config/strategy/AbstractRuleStrategy.java b/sermant-plugins/sermant-router/router-config-common/src/main/java/com/huaweicloud/sermant/router/config/strategy/AbstractRuleStrategy.java index 66c56cb0c3..691ef74731 100644 --- a/sermant-plugins/sermant-router/router-config-common/src/main/java/com/huaweicloud/sermant/router/config/strategy/AbstractRuleStrategy.java +++ b/sermant-plugins/sermant-router/router-config-common/src/main/java/com/huaweicloud/sermant/router/config/strategy/AbstractRuleStrategy.java @@ -17,7 +17,9 @@ package com.huaweicloud.sermant.router.config.strategy; import com.huaweicloud.sermant.core.common.LoggerFactory; +import com.huaweicloud.sermant.router.common.event.PolicyEvent; import com.huaweicloud.sermant.router.common.utils.CollectionUtils; +import com.huaweicloud.sermant.router.common.utils.PolicyEventUtils; import com.huaweicloud.sermant.router.config.entity.Match; import com.huaweicloud.sermant.router.config.entity.Policy; import com.huaweicloud.sermant.router.config.entity.Route; @@ -96,14 +98,30 @@ public List getMatchInstances(String serviceName, List instances, Rule rul } Policy policy = match.getPolicy(); - // 1.全部可用实例数小于全部实例最小可用阈值,则同AZ优先 - // 2.未设置全部实例最小可用阈值,未超过同AZ比例阈值,则同AZ优先 - // 3.设置了全部实例最小可用阈值,但其小于全部AZ可用实例,未超过同AZ比例阈值,则同AZ优先 - if (policy == null || policy.getMinAllInstances() > instances.size() - || instances.size() * policy.getTriggerThreshold() < matchInstances.size()) { + // 未定义policy规则 + if (policy == null) { + return matchInstances; + } + + // 情况一:全部可用实例数小于全部实例最小可用阈值,则同TAG优先 + if (policy.getMinAllInstances() > instances.size()) { + PolicyEventUtils.notifySameTagMatchedEvent(PolicyEvent.SAME_TAG_MATCH_LESS_MIN_ALL_INSTANCES, + match.getTags().toString(), serviceName); + return matchInstances; + } + + // 情况二:未设置全部实例最小可用阈值,超过同TAG比例阈值,则同TAG优先 + // 情况三:设置了全部实例最小可用阈值,但其小于全部TAG可用实例,超过同TAG比例阈值,则同TAG优先 + if (instances.size() * policy.getTriggerThreshold() < matchInstances.size()) { + PolicyEventUtils.notifySameTagMatchedEvent(PolicyEvent.SAME_TAG_MATCH_EXCEEDED_TRIGGER_THRESHOLD, + match.getTags().toString(), serviceName); return matchInstances; } LOGGER.warning("not matched, return all instances"); + + // 情况四:未匹配上 + PolicyEventUtils.notifySameTagMisMatchedEvent(PolicyEvent.SAME_TAG_MISMATCH, match.getTags().toString(), + serviceName); return instances; } diff --git a/sermant-plugins/sermant-router/spring-router-service/src/test/java/com/huaweicloud/sermant/router/spring/handler/TagRouteHandlerTest.java b/sermant-plugins/sermant-router/spring-router-service/src/test/java/com/huaweicloud/sermant/router/spring/handler/TagRouteHandlerTest.java index 814c18e12f..3143183f7b 100644 --- a/sermant-plugins/sermant-router/spring-router-service/src/test/java/com/huaweicloud/sermant/router/spring/handler/TagRouteHandlerTest.java +++ b/sermant-plugins/sermant-router/spring-router-service/src/test/java/com/huaweicloud/sermant/router/spring/handler/TagRouteHandlerTest.java @@ -16,6 +16,8 @@ package com.huaweicloud.sermant.router.spring.handler; +import com.huaweicloud.sermant.core.config.ConfigManager; +import com.huaweicloud.sermant.core.event.config.EventConfig; import com.huaweicloud.sermant.router.common.constants.RouterConstant; import com.huaweicloud.sermant.router.common.request.RequestData; import com.huaweicloud.sermant.router.config.cache.ConfigCache; @@ -23,9 +25,12 @@ import com.huaweicloud.sermant.router.spring.TestDefaultServiceInstance; import com.huaweicloud.sermant.router.spring.cache.AppCache; +import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.springframework.cloud.client.ServiceInstance; import java.util.ArrayList; @@ -43,14 +48,29 @@ public class TagRouteHandlerTest { private static TagRouteHandler tagRouteHandler; + private static EventConfig config; + + private static MockedStatic mockConfigManager; + /** * UT执行前进行mock */ @BeforeClass public static void before() { + config = new EventConfig(); + config.setEnable(false); + mockConfigManager = Mockito.mockStatic(ConfigManager.class); + mockConfigManager.when(() -> ConfigManager.getConfig(EventConfig.class)).thenReturn(config); tagRouteHandler = new TagRouteHandler(); } + /** + * UT执行后释放资源 + */ + @AfterClass + public static void after(){ + mockConfigManager.close(); + } /** * 测试getTargetInstancesByRules方法 */