diff --git a/polaris-common/polaris-client/src/main/java/com/tencent/polaris/client/flow/BaseFlow.java b/polaris-common/polaris-client/src/main/java/com/tencent/polaris/client/flow/BaseFlow.java index 656e560ed..a174db295 100644 --- a/polaris-common/polaris-client/src/main/java/com/tencent/polaris/client/flow/BaseFlow.java +++ b/polaris-common/polaris-client/src/main/java/com/tencent/polaris/client/flow/BaseFlow.java @@ -33,29 +33,21 @@ import com.tencent.polaris.api.plugin.route.RouteInfo; import com.tencent.polaris.api.plugin.route.RouteResult; import com.tencent.polaris.api.plugin.route.ServiceRouter; -import com.tencent.polaris.api.pojo.DefaultServiceEventKeysProvider; -import com.tencent.polaris.api.pojo.Instance; -import com.tencent.polaris.api.pojo.ServiceEventKey; +import com.tencent.polaris.api.pojo.*; import com.tencent.polaris.api.pojo.ServiceEventKey.EventType; -import com.tencent.polaris.api.pojo.ServiceEventKeysProvider; -import com.tencent.polaris.api.pojo.ServiceInfo; -import com.tencent.polaris.api.pojo.ServiceInstances; -import com.tencent.polaris.api.pojo.ServiceInstancesWrap; -import com.tencent.polaris.api.pojo.ServiceKey; -import com.tencent.polaris.api.pojo.ServiceRule; -import com.tencent.polaris.api.pojo.Services; import com.tencent.polaris.api.rpc.Criteria; import com.tencent.polaris.api.rpc.RequestBaseEntity; import com.tencent.polaris.api.utils.CollectionUtils; import com.tencent.polaris.client.util.Utils; import com.tencent.polaris.logging.LoggerFactory; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import org.slf4j.Logger; + +import java.util.*; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import org.slf4j.Logger; + +import static com.tencent.polaris.api.plugin.route.RouterConstants.ROUTER_FAULT_TOLERANCE_ENABLE; /** * 同步调用流程 @@ -71,16 +63,16 @@ public class BaseFlow { /** * 通用获取单个服务实例的方法,用于SDK内部调用 * - * @param extensions 插件上下文 - * @param serviceKey 服务信息 + * @param extensions 插件上下文 + * @param serviceKey 服务信息 * @param coreRouterNames 核心路由插件链 - * @param lbPolicy 负载均衡策略 - * @param protocol 协议信息 - * @param hashKey 一致性hash的key + * @param lbPolicy 负载均衡策略 + * @param protocol 协议信息 + * @param hashKey 一致性hash的key * @return 过滤后的实例 */ public static Instance commonGetOneInstance(Extensions extensions, ServiceKey serviceKey, - List coreRouterNames, String lbPolicy, String protocol, String hashKey) { + List coreRouterNames, String lbPolicy, String protocol, String hashKey) { ServiceEventKey svcEventKey = new ServiceEventKey(serviceKey, EventType.INSTANCE); LOG.debug("[ConnectionManager]start to discover service {}", svcEventKey); DefaultServiceEventKeysProvider provider = new DefaultServiceEventKeysProvider(); @@ -123,14 +115,14 @@ public static Instance commonGetOneInstance(Extensions extensions, ServiceKey se /** * 处理服务路由 * - * @param routeInfo 路由信息 - * @param dstInstances 目标实例列表 + * @param routeInfo 路由信息 + * @param dstInstances 目标实例列表 * @param routerChainGroup 插件链 * @return 过滤后的实例 * @throws PolarisException 异常 */ public static ServiceInstances processServiceRouters(RouteInfo routeInfo, ServiceInstances dstInstances, - RouterChainGroup routerChainGroup) throws PolarisException { + RouterChainGroup routerChainGroup) throws PolarisException { if (null == dstInstances || CollectionUtils.isEmpty(dstInstances.getInstances())) { return dstInstances; } @@ -141,10 +133,19 @@ public static ServiceInstances processServiceRouters(RouteInfo routeInfo, Servic if (processRouterChain(routerChainGroup.getBeforeRouters(), routeInfo, serviceInstancesWrap)) { processed = true; } + Map destSvcMetadata = Optional.ofNullable(serviceInstancesWrap.getMetadata()).orElse(Collections.emptyMap()); + List faultToleranceServiceInstances = new ArrayList<>(); + if (Boolean.parseBoolean(destSvcMetadata.get(ROUTER_FAULT_TOLERANCE_ENABLE))) { + faultToleranceServiceInstances = new ArrayList<>(dstInstances.getInstances()); + } //再走业务路由 if (processRouterChain(routerChainGroup.getCoreRouters(), routeInfo, serviceInstancesWrap)) { processed = true; } + if (CollectionUtils.isEmpty(serviceInstancesWrap.getInstances()) + && Boolean.parseBoolean(destSvcMetadata.get(ROUTER_FAULT_TOLERANCE_ENABLE))) { + serviceInstancesWrap.setInstances(faultToleranceServiceInstances); + } //最后走后置路由 if (processRouterChain(routerChainGroup.getAfterRouters(), routeInfo, serviceInstancesWrap)) { processed = true; @@ -156,7 +157,7 @@ public static ServiceInstances processServiceRouters(RouteInfo routeInfo, Servic } private static boolean processRouterChain(List routers, - RouteInfo routeInfo, ServiceInstancesWrap serviceInstances) throws PolarisException { + RouteInfo routeInfo, ServiceInstancesWrap serviceInstances) throws PolarisException { if (CollectionUtils.isEmpty(routers)) { return false; } @@ -190,15 +191,15 @@ private static boolean processRouterChain(List routers, /** * 同步拉取资源数据 * - * @param extensions 插件集合 + * @param extensions 插件集合 * @param internalRequest 是否内部请求 - * @param paramProvider 参数提供器 - * @param controlParam 控制参数 + * @param paramProvider 参数提供器 + * @param controlParam 控制参数 * @return 多资源应答 * @throws PolarisException 获取异常 */ public static ResourcesResponse syncGetResources(Extensions extensions, boolean internalRequest, - ServiceEventKeysProvider paramProvider, FlowControlParam controlParam) + ServiceEventKeysProvider paramProvider, FlowControlParam controlParam) throws PolarisException { if (CollectionUtils.isEmpty(paramProvider.getSvcEventKeys()) && null == paramProvider.getSvcEventKey()) { @@ -245,7 +246,7 @@ public static ResourcesResponse syncGetResources(Extensions extensions, boolean } private static boolean readResourcesFromLocalCache(ServiceEventKeysProvider paramProvider, - Extensions extensions, ResourcesResponse resourcesResponse) { + Extensions extensions, ResourcesResponse resourcesResponse) { LocalRegistry localRegistry = extensions.getLocalRegistry(); if (null != paramProvider.getSvcEventKey()) { if (loadLocalResources(paramProvider.getSvcEventKey(), resourcesResponse, localRegistry)) { @@ -263,7 +264,7 @@ private static boolean readResourcesFromLocalCache(ServiceEventKeysProvider para } private static boolean loadLocalResources(ServiceEventKey svcEventKey, ResourcesResponse resourcesResponse, - LocalRegistry localRegistry) { + LocalRegistry localRegistry) { ResourceFilter filter = new ResourceFilter(svcEventKey, false, true); if (svcEventKey.getEventType() == EventType.INSTANCE) { ServiceInstances instances = localRegistry.getInstances(filter); @@ -293,7 +294,7 @@ private static boolean loadLocalResources(ServiceEventKey svcEventKey, Resources } public static Instance processLoadBalance(LoadBalancer loadBalancer, Criteria criteria, - ServiceInstances dstInstances) throws PolarisException { + ServiceInstances dstInstances) throws PolarisException { Instance instance = loadBalancer.chooseInstance(criteria, dstInstances); if (null == instance) { throw new PolarisException(ErrorCode.INSTANCE_NOT_FOUND, @@ -306,12 +307,12 @@ public static Instance processLoadBalance(LoadBalancer loadBalancer, Criteria cr /** * 构建流程控制参数 * - * @param entity 请求对象 - * @param config 配置对象 + * @param entity 请求对象 + * @param config 配置对象 * @param controlParam 控制参数 */ public static void buildFlowControlParam(RequestBaseEntity entity, Configuration config, - FlowControlParam controlParam) { + FlowControlParam controlParam) { long timeoutMs = entity.getTimeoutMs(); if (timeoutMs == 0) { timeoutMs = config.getGlobal().getAPI().getTimeout(); diff --git a/polaris-common/polaris-config-default/src/main/resources/conf/default-config.yml b/polaris-common/polaris-config-default/src/main/resources/conf/default-config.yml index 32b4aa3a1..b262a00b4 100644 --- a/polaris-common/polaris-config-default/src/main/resources/conf/default-config.yml +++ b/polaris-common/polaris-config-default/src/main/resources/conf/default-config.yml @@ -142,7 +142,7 @@ consumer: #描述: 缓存插件名 type: inmemory #描述: 是否启用服务数据缓存 - serviceExpireEnable: true + serviceExpireEnable: false #描述: 服务过期淘汰时间 serviceExpireTime: 24h #描述: 服务定期同步刷新周期 diff --git a/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/constant/MetadataConstants.java b/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/constant/MetadataConstants.java new file mode 100644 index 000000000..b88849250 --- /dev/null +++ b/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/constant/MetadataConstants.java @@ -0,0 +1,46 @@ +/* + * Tencent is pleased to support the open source community by making Polaris available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.metadata.core.constant; + +/** + * Metadata constant for Polaris. + * + * @author Haotian Zhang + */ +public class MetadataConstants { + + /** + * local service namespace. + */ + public static final String LOCAL_NAMESPACE = "LOCAL_NAMESPACE"; + + /** + * local service name. + */ + public static final String LOCAL_SERVICE = "LOCAL_SERVICE"; + + /** + * local host ip. + */ + public static final String LOCAL_IP = "LOCAL_IP"; + + /** + * local host port. + */ + public static final String LOCAL_PORT = "LOCAL_PORT"; +} diff --git a/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/constant/TsfMetadataConstants.java b/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/constant/TsfMetadataConstants.java new file mode 100644 index 000000000..ba7dbeb86 --- /dev/null +++ b/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/constant/TsfMetadataConstants.java @@ -0,0 +1,73 @@ +/* + * Tencent is pleased to support the open source community by making Polaris available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.metadata.core.constant; + +/** + * Metadata constant for TSF. + * + * @author Haotian Zhang + */ +public final class TsfMetadataConstants { + /** + * tsf application id. + */ + public static String TSF_APPLICATION_ID = "TSF_APPLICATION_ID"; + + /** + * tsf program version. + */ + public static String TSF_PROG_VERSION = "TSF_PROG_VERSION"; + + /** + * tsf group id. + */ + public static String TSF_GROUP_ID = "TSF_GROUP_ID"; + + /** + * tsf namespace id. + */ + public static String TSF_NAMESPACE_ID = "TSF_NAMESPACE_ID"; + + /** + * tsf instance id. + */ + public static String TSF_INSTNACE_ID = "TSF_INSTNACE_ID"; + + /** + * tsf region. + */ + public static String TSF_REGION = "TSF_REGION"; + + /** + * tsf zone. + */ + public static String TSF_ZONE = "TSF_ZONE"; + + /** + * tsf SDK version. + */ + public static String TSF_SDK_VERSION = "TSF_SDK_VERSION"; + + /** + * tsf tags. + */ + public static String TSF_TAGS = "TSF_TAGS"; + + private TsfMetadataConstants() { + } +} diff --git a/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/manager/CalleeMetadataContainerGroup.java b/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/manager/CalleeMetadataContainerGroup.java new file mode 100644 index 000000000..4bc2cb166 --- /dev/null +++ b/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/manager/CalleeMetadataContainerGroup.java @@ -0,0 +1,59 @@ +/* + * Tencent is pleased to support the open source community by making Polaris available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.metadata.core.manager; + +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.impl.MessageMetadataContainerImpl; +import com.tencent.polaris.metadata.core.impl.MetadataContainerImpl; + +import static com.tencent.polaris.metadata.core.manager.MetadataContext.DEFAULT_TRANSITIVE_PREFIX; + +public class CalleeMetadataContainerGroup implements MetadataContainerGroup { + + private final MetadataContainer messageMetadataContainer; + + private final static MetadataContainer applicationMetadataContainer = new MetadataContainerImpl(DEFAULT_TRANSITIVE_PREFIX); + + private final MetadataContainer customMetadataContainer; + + public CalleeMetadataContainerGroup(String transitivePrefix) { + assert null != transitivePrefix; + this.messageMetadataContainer = new MessageMetadataContainerImpl(transitivePrefix); + this.customMetadataContainer = new MetadataContainerImpl(transitivePrefix); + } + + @Override + public MetadataContainer getMessageMetadataContainer() { + return messageMetadataContainer; + } + + @Override + public MetadataContainer getApplicationMetadataContainer() { + return applicationMetadataContainer; + } + + public static MetadataContainer getStaticApplicationMetadataContainer() { + return applicationMetadataContainer; + } + + @Override + public MetadataContainer getCustomMetadataContainer() { + return customMetadataContainer; + } + +} diff --git a/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/manager/CallerMetadataContainerGroup.java b/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/manager/CallerMetadataContainerGroup.java new file mode 100644 index 000000000..a1373733d --- /dev/null +++ b/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/manager/CallerMetadataContainerGroup.java @@ -0,0 +1,54 @@ +/* + * Tencent is pleased to support the open source community by making Polaris available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.metadata.core.manager; + +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.impl.MessageMetadataContainerImpl; +import com.tencent.polaris.metadata.core.impl.MetadataContainerImpl; + +public class CallerMetadataContainerGroup implements MetadataContainerGroup { + + private final MetadataContainer messageMetadataContainer; + + private final MetadataContainer applicationMetadataContainer; + + private final MetadataContainer customMetadataContainer; + + public CallerMetadataContainerGroup(String transitivePrefix) { + assert null != transitivePrefix; + this.messageMetadataContainer = new MessageMetadataContainerImpl(transitivePrefix); + this.applicationMetadataContainer = new MetadataContainerImpl(transitivePrefix); + this.customMetadataContainer = new MetadataContainerImpl(transitivePrefix); + } + + @Override + public MetadataContainer getMessageMetadataContainer() { + return messageMetadataContainer; + } + + @Override + public MetadataContainer getApplicationMetadataContainer() { + return applicationMetadataContainer; + } + + @Override + public MetadataContainer getCustomMetadataContainer() { + return customMetadataContainer; + } + +} diff --git a/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/manager/MetadataContainerGroup.java b/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/manager/MetadataContainerGroup.java index 76e5d6ed5..10c53ff76 100644 --- a/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/manager/MetadataContainerGroup.java +++ b/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/manager/MetadataContainerGroup.java @@ -18,34 +18,12 @@ package com.tencent.polaris.metadata.core.manager; import com.tencent.polaris.metadata.core.MetadataContainer; -import com.tencent.polaris.metadata.core.impl.MessageMetadataContainerImpl; -import com.tencent.polaris.metadata.core.impl.MetadataContainerImpl; -public class MetadataContainerGroup { +public interface MetadataContainerGroup { - private final MetadataContainer messageMetadataContainer; + MetadataContainer getMessageMetadataContainer(); - private final MetadataContainer applicationMetadataContainer; - - private final MetadataContainer customMetadataContainer; - - public MetadataContainerGroup(String transitivePrefix) { - assert null != transitivePrefix; - this.messageMetadataContainer = new MessageMetadataContainerImpl(transitivePrefix); - this.applicationMetadataContainer = new MetadataContainerImpl(transitivePrefix); - this.customMetadataContainer = new MetadataContainerImpl(transitivePrefix); - } - - public MetadataContainer getMessageMetadataContainer() { - return messageMetadataContainer; - } - - public MetadataContainer getApplicationMetadataContainer() { - return applicationMetadataContainer; - } - - public MetadataContainer getCustomMetadataContainer() { - return customMetadataContainer; - } + MetadataContainer getApplicationMetadataContainer(); + MetadataContainer getCustomMetadataContainer(); } diff --git a/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/manager/MetadataContext.java b/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/manager/MetadataContext.java index 9f5ed523d..db0f83aec 100644 --- a/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/manager/MetadataContext.java +++ b/polaris-common/polaris-metadata/src/main/java/com/tencent/polaris/metadata/core/manager/MetadataContext.java @@ -40,8 +40,8 @@ public MetadataContext(String transitivePrefix) { transitivePrefix = ""; } this.transitivePrefix = transitivePrefix; - callerMetadataContainerGroup = new MetadataContainerGroup(transitivePrefix); - calleeMetadataContainerGroup = new MetadataContainerGroup(transitivePrefix); + callerMetadataContainerGroup = new CallerMetadataContainerGroup(transitivePrefix); + calleeMetadataContainerGroup = new CalleeMetadataContainerGroup(transitivePrefix); } /** @@ -71,8 +71,15 @@ public T getMetadataContainer(MetadataType metadat } } + public MetadataContainerGroup getMetadataContainerGroup(boolean caller) { + if (caller) { + return callerMetadataContainerGroup; + } else { + return calleeMetadataContainerGroup; + } + } + public String getTransitivePrefix() { return transitivePrefix; } - } diff --git a/polaris-common/polaris-model/pom.xml b/polaris-common/polaris-model/pom.xml index ea79ab3f0..18a9c5bf2 100644 --- a/polaris-common/polaris-model/pom.xml +++ b/polaris-common/polaris-model/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> polaris-common com.tencent.polaris @@ -25,6 +25,11 @@ polaris-protobuf ${project.version} + + com.tencent.polaris + polaris-metadata + ${project.version} + com.tencent.polaris polaris-logging diff --git a/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/DefaultInstance.java b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/DefaultInstance.java index 5e3ccc871..58e83dccd 100644 --- a/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/DefaultInstance.java +++ b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/DefaultInstance.java @@ -18,6 +18,7 @@ package com.tencent.polaris.api.pojo; import com.tencent.polaris.api.utils.StringUtils; + import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -55,6 +56,8 @@ public class DefaultInstance extends DefaultBaseInstance implements Instance { private String logicSet; + private Map serviceMetadata = new HashMap<>(); + @Override public String getRevision() { return revision; @@ -185,6 +188,14 @@ public void setLogicSet(String logicSet) { this.logicSet = logicSet; } + public Map getServiceMetadata() { + return serviceMetadata; + } + + public void setServiceMetadata(Map serviceMetadata) { + this.serviceMetadata = serviceMetadata; + } + @Override public CircuitBreakerStatus getCircuitBreakerStatus() { return circuitBreakerStatuses.get(StatusDimension.EMPTY_DIMENSION); @@ -248,6 +259,7 @@ public String toString() { ", priority=" + priority + ", weight=" + weight + ", logicSet='" + logicSet + '\'' + + ", serviceMetadata=" + serviceMetadata + '}'; } } diff --git a/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/DefaultServiceInstances.java b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/DefaultServiceInstances.java index 0f66917c3..3f4530de8 100644 --- a/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/DefaultServiceInstances.java +++ b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/DefaultServiceInstances.java @@ -19,11 +19,8 @@ import com.tencent.polaris.api.utils.CollectionUtils; import com.tencent.polaris.client.pojo.Node; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; + +import java.util.*; public class DefaultServiceInstances implements ServiceInstances { @@ -35,6 +32,8 @@ public class DefaultServiceInstances implements ServiceInstances { private final Map nodeMap; + private final Map metadata; + private final int totalWeight; private final int hashCode; @@ -42,6 +41,10 @@ public class DefaultServiceInstances implements ServiceInstances { private final String revision; public DefaultServiceInstances(ServiceKey serviceKey, List instances) { + this(serviceKey, instances, null); + } + + public DefaultServiceInstances(ServiceKey serviceKey, List instances, Map metadata) { this.serviceKey = serviceKey; this.instances = Collections.unmodifiableList(instances); this.totalWeight = getTotalWeight(instances); @@ -53,6 +56,10 @@ public DefaultServiceInstances(ServiceKey serviceKey, List instances) idMap.put(instance.getId(), instance); nodeMap.put(new Node(instance.getHost(), instance.getPort()), instance); } + this.metadata = new HashMap<>(); + if (CollectionUtils.isNotEmpty(metadata)) { + this.metadata.putAll(metadata); + } } private int getTotalWeight(List instances) { @@ -102,7 +109,7 @@ public Instance getInstance(String id) { @Override public Map getMetadata() { - return null; + return metadata; } @Override diff --git a/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/HttpElement.java b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/HttpElement.java new file mode 100644 index 000000000..08fb92061 --- /dev/null +++ b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/HttpElement.java @@ -0,0 +1,53 @@ +/* + * Tencent is pleased to support the open source community by making Polaris available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.api.pojo; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class HttpElement { + + + public final class HttpMethod { + + public static final String GET = "GET"; + public static final String HEAD = "HEAD"; + public static final String POST = "POST"; + public static final String PUT = "PUT"; + public static final String PATCH = "PATCH"; + public static final String DELETE = "DELETE"; + public static final String OPTIONS = "OPTIONS"; + public static final String TRACE = "TRACE"; + } + + public static final Set HTTP_METHOD_SET = + new HashSet<>(Arrays.asList(HttpMethod.GET, HttpMethod.HEAD, HttpMethod.POST, HttpMethod.PUT, + HttpMethod.PATCH, HttpMethod.DELETE, HttpMethod.OPTIONS, HttpMethod.TRACE)); + + public final class MediaType { + + public static final String APPLICATION_FORM_URLENCODED = "application/x-www-form-urlencoded;charset=UTF-8"; + public static final String APPLICATION_XHTML_XML = "application/xhtml+xml"; + public static final String APPLICATION_XML = "application/xml;charset=UTF-8"; + public static final String APPLICATION_JSON = "application/json;charset=UTF-8"; + public static final String MULTIPART_FORM_DATA = "multipart/form-data;charset=UTF-8"; + public static final String TEXT_HTML = "text/html;charset=UTF-8"; + public static final String TEXT_PLAIN = "text/plain;charset=UTF-8"; + } +} diff --git a/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/Instance.java b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/Instance.java index ce6e3bc55..fccb0f542 100644 --- a/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/Instance.java +++ b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/Instance.java @@ -18,6 +18,7 @@ package com.tencent.polaris.api.pojo; import java.util.Collection; +import java.util.HashMap; import java.util.Map; /** @@ -82,6 +83,10 @@ public interface Instance extends BaseInstance, Comparable { String getLogicSet(); + default Map getServiceMetadata() { + return new HashMap<>(); + } + static Instance createDefaultInstance(String instId, String namespace, String service, String host, int port) { DefaultInstance defaultInstance = new DefaultInstance(); defaultInstance.setHealthy(true); diff --git a/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/TrieNode.java b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/TrieNode.java new file mode 100644 index 000000000..9bfd41c09 --- /dev/null +++ b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/pojo/TrieNode.java @@ -0,0 +1,73 @@ +/* + * Tencent is pleased to support the open source community by making Polaris available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.api.pojo; + +import java.util.HashMap; +import java.util.Map; + +public class TrieNode { + private final Map> children; + private final String path; + + // 只有叶子节点才有 + private T nodeInfo; + + // 增加非法字符,确保不会和前端传入的参数相同 + public static final String POLARIS_WILDCARD = "#polaris_wildcard#"; + + public static final String SIMPLE_VALID_INFO = "#TSF#"; + + public static final String ROOT_PATH = ""; + + // root 构造器 + public TrieNode(String path) { + this.path = path; + this.children = new HashMap<>(); + } + + public TrieNode getSubNode(String nodeKey) { + if (children.containsKey(nodeKey)) { + return children.get(nodeKey); + } else if (children.containsKey(POLARIS_WILDCARD)) { + return children.get(POLARIS_WILDCARD); + } + + return null; + } + + // only for build trie + public TrieNode getOrCreateSubNode(String path) { + if (path.startsWith("{") && path.endsWith("}")) { + path = POLARIS_WILDCARD; + } + + if (!children.containsKey(path)) { + children.putIfAbsent(path, new TrieNode(path)); + } + + return children.get(path); + } + + public T getNodeInfo() { + return nodeInfo; + } + + public void setNodeInfo(T nodeInfo) { + this.nodeInfo = nodeInfo; + } +} \ No newline at end of file diff --git a/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/utils/ApiTrieUtil.java b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/utils/ApiTrieUtil.java new file mode 100644 index 000000000..ac2cecb84 --- /dev/null +++ b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/utils/ApiTrieUtil.java @@ -0,0 +1,110 @@ +/* + * Tencent is pleased to support the open source community by making Polaris available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.api.utils; + +import com.tencent.polaris.api.pojo.HttpElement; +import com.tencent.polaris.api.pojo.TrieNode; + +public class ApiTrieUtil { + + /** + * @param apiPath + * @return TrieNode + */ + public static TrieNode buildSimpleTrieNode(String apiPath) { + if (StringUtils.isEmpty(apiPath)) { + return null; + } + return buildSimpleTrieNode(new String[]{apiPath}); + } + + public static TrieNode buildSimpleTrieNode(String[] apiPathInfoList) { + if (apiPathInfoList.length == 0) { + return null; + } + + TrieNode root = new TrieNode<>(TrieNode.ROOT_PATH); + for (String apiPathInfo : apiPathInfoList) { + int flag = apiPathInfo.lastIndexOf("-"); + String method = null; + String path = apiPathInfo; + if (flag != -1) { + method = apiPathInfo.substring(flag + 1); + path = apiPathInfo; + if (HttpElement.HTTP_METHOD_SET.contains(method)) { + path = apiPathInfo.substring(0, flag); + } else { + method = null; + } + } + + // 因为前端的改动(最初的 tagValue 只有 path,某次前端组件改动后变成了 path-method,非客户提的),有兼容性问题, + // 临时简化处理,不处理 method,前面逻辑保留是为了取出正确的 path + String[] apiPaths = path.split("/"); + + // 跳过第一个为空的str + TrieNode node = root; + for (int i = 1; i < apiPaths.length; i++) { + node = node.getOrCreateSubNode(apiPaths[i]); + + // 叶子节点,需要 info + if (i == apiPaths.length - 1) { + node.setNodeInfo(TrieNode.SIMPLE_VALID_INFO + "method:" + method); + } + } + } + return root; + } + + public static boolean checkSimple(TrieNode root, String apiPathInfo) { + if (root == null) { + return false; + } + int flag = apiPathInfo.lastIndexOf("-"); + String method = apiPathInfo.substring(flag + 1); + String path = apiPathInfo; + if (HttpElement.HTTP_METHOD_SET.contains(method)) { + path = apiPathInfo.substring(0, flag); + } else { + method = null; + } + // 因为前端的改动(最初的 tagValue 只有 path,某次前端组件改动后变成了 path-method,非客户提的),有兼容性问题, + // 临时简化处理,不处理 method,前面逻辑保留是为了取出正确的 path + method = null; + String[] apiPaths = path.split("/"); + + TrieNode node = root; + for (int i = 1; i < apiPaths.length; i++) { + if (node == null) { + return false; + } + node = node.getSubNode(apiPaths[i]); + // 叶子节点 + if (i == apiPaths.length - 1) { + if (node == null) { + return false; + } else { + return StringUtils.equals(TrieNode.SIMPLE_VALID_INFO + "method:" + method, node.getNodeInfo()); + } + } + } + + return false; + } + +} diff --git a/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/utils/RuleUtils.java b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/utils/RuleUtils.java index bebb5a8d0..ee9760d55 100644 --- a/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/utils/RuleUtils.java +++ b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/utils/RuleUtils.java @@ -18,7 +18,9 @@ package com.tencent.polaris.api.utils; +import com.tencent.polaris.api.pojo.TrieNode; import com.tencent.polaris.logging.LoggerFactory; +import com.tencent.polaris.metadata.core.manager.MetadataContainerGroup; import com.tencent.polaris.specification.api.v1.model.ModelProto.MatchString; import com.tencent.polaris.specification.api.v1.model.ModelProto.MatchString.MatchStringType; import org.slf4j.Logger; @@ -34,6 +36,8 @@ public class RuleUtils { public static final String MATCH_ALL = "*"; + public static final String CALLEE_APPLICATION_METADATA_PREFIX = "$caller_metadata."; + private static final Function DEFAULT_REGEX_PATTERN = new Function() { @Override public Pattern apply(String s) { @@ -70,15 +74,15 @@ public static boolean matchStringValue(MatchString matchString, String actualVal Function regexToPattern) { MatchStringType matchType = matchString.getType(); String matchValue = matchString.getValue().getValue(); - return matchStringValue(matchType, actualValue, matchValue, regexToPattern); + return matchStringValue(matchType, actualValue, matchValue, regexToPattern, false, null); } public static boolean matchStringValue(MatchStringType matchType, String actualValue, String matchValue) { - return matchStringValue(matchType, actualValue, matchValue, DEFAULT_REGEX_PATTERN); + return matchStringValue(matchType, actualValue, matchValue, DEFAULT_REGEX_PATTERN, false, null); } private static boolean matchStringValue(MatchStringType matchType, String actualValue, String matchValue, - Function regexToPattern) { + Function regexToPattern, boolean useTrieNode, Function> trieNodeFunction) { actualValue = StringUtils.defaultString(actualValue); matchValue = StringUtils.defaultString(matchValue); if (RuleUtils.isMatchAllValue(matchValue)) { @@ -86,6 +90,9 @@ private static boolean matchStringValue(MatchStringType matchType, String actual } switch (matchType) { case EXACT: { + if (useTrieNode && trieNodeFunction != null) { + return ApiTrieUtil.checkSimple(trieNodeFunction.apply(matchValue), actualValue); + } return StringUtils.equals(actualValue, matchValue); } case REGEX: { @@ -94,13 +101,22 @@ private static boolean matchStringValue(MatchStringType matchType, String actual return pattern.matcher(actualValue).find(); } case NOT_EQUALS: { + if (useTrieNode && trieNodeFunction != null) { + return !ApiTrieUtil.checkSimple(trieNodeFunction.apply(matchValue), actualValue); + } return !StringUtils.equals(actualValue, matchValue); } case IN: { String[] tokens = matchValue.split(","); for (String token : tokens) { - if (StringUtils.equals(token, actualValue)) { - return true; + if (useTrieNode && trieNodeFunction != null) { + if (ApiTrieUtil.checkSimple(trieNodeFunction.apply(matchValue), actualValue)) { + return true; + } + } else { + if (StringUtils.equals(token, actualValue)) { + return true; + } } } return false; @@ -108,8 +124,14 @@ private static boolean matchStringValue(MatchStringType matchType, String actual case NOT_IN: { String[] tokens = matchValue.split(","); for (String token : tokens) { - if (StringUtils.equals(token, actualValue)) { - return false; + if (useTrieNode && trieNodeFunction != null) { + if (ApiTrieUtil.checkSimple(trieNodeFunction.apply(matchValue), actualValue)) { + return false; + } + } else { + if (StringUtils.equals(token, actualValue)) { + return false; + } } } return true; @@ -146,6 +168,14 @@ public static boolean matchMetadata(Map ruleMeta, Map ruleMeta, Map destMeta, boolean isMatchSource, Map multiEnvRouterParamMap, Map variables) { + return matchMetadata(ruleMeta, destMeta, null, isMatchSource, multiEnvRouterParamMap, variables, null); + } + + // 匹配metadata + public static boolean matchMetadata(Map ruleMeta, Map destMeta, + MetadataContainerGroup metadataContainerGroup, boolean isMatchSource, + Map multiEnvRouterParamMap, Map variables, + Function> trieNodeFunction) { // 如果规则metadata为空, 返回成功 if (MapUtils.isEmpty(ruleMeta)) { return true; @@ -154,7 +184,7 @@ public static boolean matchMetadata(Map ruleMeta, Map ruleMeta, Map ruleMeta, Map multiEnvRouterParamMap, - Map variables) { + Map variables, + boolean useTrieNode, Function> trieNodeFunction) { if (RuleUtils.MATCH_ALL.equals(destMetaValue)) { return true; } return matchValueByValueType(isMatchSource, ruleMetaKey, ruleMetaValue, destMetaValue, - multiEnvRouterParamMap, variables); + multiEnvRouterParamMap, variables, useTrieNode, trieNodeFunction); } private static boolean matchValueByValueType(boolean isMatchSource, String ruleMetaKey, MatchString ruleMetaValue, String destMetaValue, Map multiEnvRouterParamMap, - Map variables) { + Map variables, + boolean useTrieNode, Function> trieNodeFunction) { boolean allMetaMatched = true; switch (ruleMetaValue.getValueType()) { @@ -257,7 +313,7 @@ private static boolean matchValueByValueType(boolean isMatchSource, String ruleM break; default: allMetaMatched = matchStringValue(ruleMetaValue.getType(), destMetaValue, - ruleMetaValue.getValue().getValue()); + ruleMetaValue.getValue().getValue(), DEFAULT_REGEX_PATTERN, useTrieNode, trieNodeFunction); } return allMetaMatched; diff --git a/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/cache/CacheConstants.java b/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/cache/CacheConstants.java new file mode 100644 index 000000000..3ef04e6c1 --- /dev/null +++ b/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/cache/CacheConstants.java @@ -0,0 +1,28 @@ +/* + * Tencent is pleased to support the open source community by making Polaris available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.api.plugin.cache; + +/** + * Constant for Cache. + * + * @author Haotian Zhang + */ +public interface CacheConstants { + + int API_ID = 433; +} diff --git a/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/registry/CacheHandler.java b/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/registry/CacheHandler.java index 38e816c25..547d66edf 100644 --- a/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/registry/CacheHandler.java +++ b/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/registry/CacheHandler.java @@ -17,6 +17,7 @@ package com.tencent.polaris.api.plugin.registry; +import com.tencent.polaris.api.plugin.cache.FlowCache; import com.tencent.polaris.api.pojo.RegistryCacheValue; import com.tencent.polaris.api.pojo.ServiceEventKey.EventType; @@ -63,12 +64,13 @@ enum CachedStatus { /** * 将服务端原始消息转换为缓存对象 * - * @param oldValue 旧值 - * @param newValue 新原始消息 + * @param oldValue 旧值 + * @param newValue 新原始消息 * @param isCacheLoaded 是否从本地缓存加载 + * @param flowCache 缓存 * @return 新缓存值 */ - RegistryCacheValue messageToCacheValue(RegistryCacheValue oldValue, Object newValue, boolean isCacheLoaded); + RegistryCacheValue messageToCacheValue(RegistryCacheValue oldValue, Object newValue, boolean isCacheLoaded, FlowCache flowCache); } diff --git a/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/route/RouteInfo.java b/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/route/RouteInfo.java index 567b21417..034a565af 100644 --- a/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/route/RouteInfo.java +++ b/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/route/RouteInfo.java @@ -17,23 +17,15 @@ package com.tencent.polaris.api.plugin.route; import com.tencent.polaris.api.config.provider.ServiceConfig; -import com.tencent.polaris.api.pojo.RouteArgument; -import com.tencent.polaris.api.pojo.ServiceInfo; -import com.tencent.polaris.api.pojo.ServiceMetadata; -import com.tencent.polaris.api.pojo.ServiceRule; -import com.tencent.polaris.api.pojo.SourceService; -import com.tencent.polaris.api.pojo.StatusDimension; +import com.tencent.polaris.api.pojo.*; import com.tencent.polaris.api.pojo.StatusDimension.Level; import com.tencent.polaris.api.rpc.MetadataFailoverType; import com.tencent.polaris.api.rpc.RuleBasedRouterFailoverType; import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.metadata.core.manager.MetadataContainerGroup; import com.tencent.polaris.specification.api.v1.model.ModelProto.MatchString; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; + +import java.util.*; import java.util.function.Function; /** @@ -71,6 +63,8 @@ public class RouteInfo { //各个路由插件依赖的 metadata 参数 private final Map> routerMetadata = new HashMap<>(); + private MetadataContainerGroup metadataContainerGroup; + private Function> externalParameterSupplier = s -> Optional.empty(); /** @@ -85,15 +79,15 @@ public class RouteInfo { /** * 构造器 * - * @param sourceService 源服务 + * @param sourceService 源服务 * @param sourceRouteRule 源规则 - * @param destService 目标服务 - * @param destRouteRule 目标规则 - * @param method 接口名 - * @param serviceConfig 配置的当前服务名 + * @param destService 目标服务 + * @param destRouteRule 目标规则 + * @param method 接口名 + * @param serviceConfig 配置的当前服务名 */ public RouteInfo(SourceService sourceService, ServiceRule sourceRouteRule, - ServiceMetadata destService, ServiceRule destRouteRule, String method, ServiceConfig serviceConfig) { + ServiceMetadata destService, ServiceRule destRouteRule, String method, ServiceConfig serviceConfig) { if (isEmptyService(sourceService) && !isEmptyService(serviceConfig)) { this.sourceService = new SourceService(); this.sourceService.setNamespace(serviceConfig.getNamespace()); @@ -127,11 +121,11 @@ public RouteInfo(SourceService sourceService, ServiceRule sourceRouteRule, * 构造器 * * @param sourceService 源服务 - * @param destService 目标服务 - * @param method 接口名 + * @param destService 目标服务 + * @param method 接口名 */ public RouteInfo(SourceService sourceService, ServiceMetadata destService, String method, - ServiceConfig serviceConfig) { + ServiceConfig serviceConfig) { this(sourceService, null, destService, null, method, serviceConfig); } @@ -296,4 +290,11 @@ private static boolean isEmptyService(ServiceConfig serviceConfig) { return StringUtils.isBlank(serviceConfig.getNamespace()) && StringUtils.isBlank(serviceConfig.getName()); } + public MetadataContainerGroup getMetadataContainerGroup() { + return metadataContainerGroup; + } + + public void setMetadataContainerGroup(MetadataContainerGroup metadataContainerGroup) { + this.metadataContainerGroup = metadataContainerGroup; + } } diff --git a/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/route/RouterConstants.java b/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/route/RouterConstants.java index bdb8e1d0b..1670a2d49 100644 --- a/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/route/RouterConstants.java +++ b/polaris-plugins/polaris-plugin-api/src/main/java/com/tencent/polaris/api/plugin/route/RouterConstants.java @@ -25,4 +25,7 @@ public interface RouterConstants { //金丝雀路由 String CANARY_KEY = "canary"; + + // 服务路由容错 + String ROUTER_FAULT_TOLERANCE_ENABLE = "internal-enable-router-faulttolerance"; } diff --git a/polaris-plugins/polaris-plugins-connector/connector-composite/src/main/java/com/tencent/polaris/plugins/connector/composite/CompositeServiceUpdateTask.java b/polaris-plugins/polaris-plugins-connector/connector-composite/src/main/java/com/tencent/polaris/plugins/connector/composite/CompositeServiceUpdateTask.java index 0e2c3c6f7..8cf4b970e 100644 --- a/polaris-plugins/polaris-plugins-connector/connector-composite/src/main/java/com/tencent/polaris/plugins/connector/composite/CompositeServiceUpdateTask.java +++ b/polaris-plugins/polaris-plugins-connector/connector-composite/src/main/java/com/tencent/polaris/plugins/connector/composite/CompositeServiceUpdateTask.java @@ -68,8 +68,6 @@ public class CompositeServiceUpdateTask extends ServiceUpdateTask { private final InstanceListMeta instanceListMeta = new InstanceListMeta(); - private boolean isAsync = false; - private String mainConnectorType = SERVER_CONNECTOR_GRPC; private boolean ifMainConnectorTypeSet = false; @@ -82,13 +80,11 @@ public CompositeServiceUpdateTask(ServiceEventHandler handler, DestroyableServer for (DestroyableServerConnector sc : compositeConnector.getServerConnectors()) { if (SERVER_CONNECTOR_GRPC.equals(sc.getName()) && sc.isDiscoveryEnable()) { subServiceUpdateTaskMap.put(SERVER_CONNECTOR_GRPC, new GrpcServiceUpdateTask(serviceEventHandler, sc)); - isAsync = true; mainConnectorType = SERVER_CONNECTOR_GRPC; ifMainConnectorTypeSet = true; } if (SERVER_CONNECTOR_CONSUL.equals(sc.getName()) && sc.isDiscoveryEnable()) { subServiceUpdateTaskMap.put(SERVER_CONNECTOR_CONSUL, new ConsulServiceUpdateTask(serviceEventHandler, sc)); - isAsync = true; if (!ifMainConnectorTypeSet) { mainConnectorType = sc.getName(); ifMainConnectorTypeSet = true; @@ -97,18 +93,31 @@ public CompositeServiceUpdateTask(ServiceEventHandler handler, DestroyableServer } } + @Override + public boolean needUpdate() { + boolean compositeNeedUpdate = super.needUpdate(); + boolean subNeedUpdate = false; + for (ServiceUpdateTask serviceUpdateTask : subServiceUpdateTaskMap.values()) { + subNeedUpdate = subNeedUpdate || serviceUpdateTask.needUpdate(); + } + return compositeNeedUpdate && subNeedUpdate; + } + @Override public void execute() { + boolean isServiceUpdateTaskExecuted = false; for (ServiceUpdateTask serviceUpdateTask : subServiceUpdateTaskMap.values()) { if ((serviceUpdateTask.getTaskType() == ServiceUpdateTaskConstant.Type.FIRST && serviceUpdateTask.getTaskStatus() == Status.READY) || serviceUpdateTask.needUpdate()) { + isServiceUpdateTaskExecuted = true; serviceUpdateTask.setStatus(ServiceUpdateTaskConstant.Status.READY, ServiceUpdateTaskConstant.Status.RUNNING); serviceUpdateTask.execute(this); } } - if (isAsync && ifMainConnectorTypeSet + // TODO 全部规则实现完后改成StringUtils.equals(mainConnectorType, SERVER_CONNECTOR_CONSUL) + if (ifMainConnectorTypeSet && isServiceUpdateTaskExecuted && (StringUtils.equals(mainConnectorType, SERVER_CONNECTOR_GRPC) - || (serviceEventKey.getEventType().equals(EventType.INSTANCE) || serviceEventKey.getEventType().equals(EventType.SERVICE)))) { + || (serviceEventKey.getEventType().equals(EventType.INSTANCE) || serviceEventKey.getEventType().equals(EventType.SERVICE) || serviceEventKey.getEventType().equals(EventType.ROUTING)))) { return; } boolean svcDeleted = this.notifyServerEvent( diff --git a/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/ConsulAPIConnector.java b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/ConsulAPIConnector.java index 38811071f..e514b6ff3 100644 --- a/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/ConsulAPIConnector.java +++ b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/ConsulAPIConnector.java @@ -48,6 +48,7 @@ import com.tencent.polaris.plugins.connector.consul.service.ConsulService; import com.tencent.polaris.plugins.connector.consul.service.InstanceService; import com.tencent.polaris.plugins.connector.consul.service.ServiceService; +import com.tencent.polaris.plugins.connector.consul.service.router.RouterRuleService; import org.slf4j.Logger; import java.util.*; @@ -221,6 +222,7 @@ private void initActually(InitContext ctx, ServerConnectorConfig connectorConfig // init consul service consulServiceMap.put(ServiceEventKey.EventType.INSTANCE, new InstanceService(consulClient, consulRawClient, consulContext, "consul-instance", mapper)); consulServiceMap.put(ServiceEventKey.EventType.SERVICE, new ServiceService(consulClient, consulRawClient, consulContext, "consul-service", mapper)); + consulServiceMap.put(ServiceEventKey.EventType.ROUTING, new RouterRuleService(consulClient, consulRawClient, consulContext, "consul-router-rule", mapper)); initialized = true; } diff --git a/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/InstanceService.java b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/InstanceService.java index c970ce892..68d806f18 100644 --- a/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/InstanceService.java +++ b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/InstanceService.java @@ -63,7 +63,7 @@ public class InstanceService extends ConsulService { private static final Logger LOG = LoggerFactory.getLogger(InstanceService.class); - private final Map serviceConsulIndex = new ConcurrentHashMap<>(); + private final Map serviceConsulIndexMap = new ConcurrentHashMap<>(); public InstanceService(ConsulClient consulClient, ConsulRawClient consulRawClient, ConsulContext consulContext, String threadName, ObjectMapper mapper) { @@ -81,15 +81,15 @@ public void sendRequest(ServiceUpdateTask serviceUpdateTask) { UrlParameters tagParams = StringUtils.isNotBlank(tag) ? new SingleUrlParameters("tag", tag) : null; UrlParameters passingParams = onlyPassing ? new SingleUrlParameters("passing") : null; UrlParameters nsTypeParam = new SingleUrlParameters("nsType", "DEF_AND_GLOBAL"); - Long index = getServersConsulIndex(serviceId); + Long currentIndex = getServersConsulIndex(serviceId); int code = ServerCodes.DATA_NO_CHANGE; - QueryParams queryParams = new QueryParams(consulContext.getWaitTime(), index); + QueryParams queryParams = new QueryParams(consulContext.getWaitTime(), currentIndex); try { - LOG.debug("Begin Get service instances of {} sync", serviceId); + LOG.debug("Begin get service instances of {} sync", serviceId); HttpResponse rawResponse = consulRawClient.makeGetRequest("/v1/health/service/" + serviceId, tagParams, passingParams, tokenParam, nsTypeParam, queryParams); if (rawResponse != null) { - if (!index.equals(rawResponse.getConsulIndex())) { + if (!currentIndex.equals(rawResponse.getConsulIndex())) { code = ServerCodes.EXECUTE_SUCCESS; } LOG.debug("raw response: " + rawResponse.getContent() + " ; onlyPassing: " + onlyPassing); @@ -153,7 +153,7 @@ public void sendRequest(ServiceUpdateTask serviceUpdateTask) { boolean svcDeleted = serviceUpdateTask.notifyServerEvent(serverEvent); // 即使无服务,也要更新 index if (rawResponse.getConsulIndex() != null) { - setServersConsulIndex(serviceId, index, rawResponse.getConsulIndex()); + setServersConsulIndex(serviceId, currentIndex, rawResponse.getConsulIndex()); } if (!svcDeleted) { serviceUpdateTask.addUpdateTaskSet(); @@ -176,7 +176,7 @@ public void sendRequest(ServiceUpdateTask serviceUpdateTask) { } private Long getServersConsulIndex(String serviceId) { - Long index = serviceConsulIndex.get(serviceId); + Long index = serviceConsulIndexMap.get(serviceId); if (index != null) { return index; } @@ -185,7 +185,7 @@ private Long getServersConsulIndex(String serviceId) { } private void setServersConsulIndex(String serviceId, Long lastIndex, Long newIndex) { - LOG.debug("serviceId: " + serviceId, "; lastIndex: " + lastIndex + "; newIndex: " + newIndex); - serviceConsulIndex.put(serviceId, newIndex); + LOG.debug("serviceId: {}; lastIndex: {}; newIndex: {}", serviceId, lastIndex, newIndex); + serviceConsulIndexMap.put(serviceId, newIndex); } } diff --git a/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/common/TagCondition.java b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/common/TagCondition.java new file mode 100644 index 000000000..d6dc5ffec --- /dev/null +++ b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/common/TagCondition.java @@ -0,0 +1,120 @@ +/* + * Tencent is pleased to support the open source community by making Polaris available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.plugins.connector.consul.service.common; + +import java.io.Serializable; +import java.util.Objects; + +/** + * TSF标签规则实体 + * + * @author vanqfjiang + */ +public class TagCondition implements Serializable { + + private static final long serialVersionUID = -4620595359940020010L; + + /** + * 标签ID + */ + private String tagId; + /** + * 标签类型 + * 定义在TagConstant.TYPE + */ + private String tagType; + /** + * 标签名 + * 系统类型的标签名定义在TagConstant.SYSTEM_FIELD + */ + private String tagField; + /** + * 标签运算符 + * 定义在TagConstant.OPERATOR + */ + private String tagOperator; + /** + * 标签的被运算对象值 + */ + private String tagValue; + + + @Override + public String toString() { + return "TagCondition{" + + "tagId=" + tagId + + ", tagType='" + tagType + '\'' + + ", tagField='" + tagField + '\'' + + ", tagOperator='" + tagOperator + '\'' + + ", tagValue='" + tagValue + '\'' + + '}'; + } + + /** + * name by equals2 is avoid override hashCode + * + * @param other + * @return true if equals other + */ + public boolean equals2(TagCondition other) { + return Objects.equals(this.tagType, other.tagType) + && Objects.equals(this.tagField, other.tagField) + && Objects.equals(this.tagOperator, other.tagOperator) + && Objects.equals(this.tagValue, other.tagValue); + } + + public String getTagId() { + return tagId; + } + + public void setTagId(String tagId) { + this.tagId = tagId; + } + + public String getTagType() { + return tagType; + } + + public void setTagType(String tagType) { + this.tagType = tagType; + } + + public String getTagField() { + return tagField; + } + + public void setTagField(String tagField) { + this.tagField = tagField; + } + + public String getTagOperator() { + return tagOperator; + } + + public void setTagOperator(String tagOperator) { + this.tagOperator = tagOperator; + } + + public String getTagValue() { + return tagValue; + } + + public void setTagValue(String tagValue) { + this.tagValue = tagValue; + } +} diff --git a/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/common/TagConditionUtil.java b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/common/TagConditionUtil.java new file mode 100644 index 000000000..db9747a7b --- /dev/null +++ b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/common/TagConditionUtil.java @@ -0,0 +1,69 @@ +/* + * Tencent is pleased to support the open source community by making Polaris available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.plugins.connector.consul.service.common; + +import com.tencent.polaris.api.utils.RuleUtils; +import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.constant.TsfMetadataConstants; +import com.tencent.polaris.specification.api.v1.model.ModelProto; + +public class TagConditionUtil { + + public static ModelProto.MatchString.MatchStringType parseMatchStringType(TagCondition tagCondition) { + String tagOperator = tagCondition.getTagOperator(); + if (StringUtils.equals(tagOperator, TagConstant.OPERATOR.EQUAL)) { + // 匹配关系 等于 + return ModelProto.MatchString.MatchStringType.EXACT; + } else if (StringUtils.equals(tagOperator, TagConstant.OPERATOR.NOT_EQUAL)) { + // 匹配关系 不等于 + return ModelProto.MatchString.MatchStringType.NOT_EQUALS; + } else if (StringUtils.equals(tagOperator, TagConstant.OPERATOR.IN)) { + return ModelProto.MatchString.MatchStringType.IN; + } else if (StringUtils.equals(tagOperator, TagConstant.OPERATOR.NOT_IN)) { + return ModelProto.MatchString.MatchStringType.NOT_IN; + } else if (StringUtils.equals(tagOperator, TagConstant.OPERATOR.REGEX)) { + return ModelProto.MatchString.MatchStringType.REGEX; + } else { + return ModelProto.MatchString.MatchStringType.REGEX; + } + } + + public static String parseMetadataKey(String originalKey) { + if (StringUtils.equals(originalKey, TagConstant.SYSTEM_FIELD.SOURCE_APPLICATION_ID)) { + // 系统标签 应用ID + return RuleUtils.CALLEE_APPLICATION_METADATA_PREFIX + TsfMetadataConstants.TSF_APPLICATION_ID; + } else if (StringUtils.equals(originalKey, TagConstant.SYSTEM_FIELD.SOURCE_GROUP_ID)) { + // 系统标签 部署组ID + return RuleUtils.CALLEE_APPLICATION_METADATA_PREFIX + TsfMetadataConstants.TSF_GROUP_ID; + } else if (StringUtils.equals(originalKey, TagConstant.SYSTEM_FIELD.SOURCE_CONNECTION_IP)) { + // 系统标签 发起方本地IP + return MessageMetadataContainer.LABEL_KEY_CALLER_IP; + } else if (StringUtils.equals(originalKey, TagConstant.SYSTEM_FIELD.SOURCE_APPLICATION_VERSION)) { + // 系统标签 包版本 + return RuleUtils.CALLEE_APPLICATION_METADATA_PREFIX + TsfMetadataConstants.TSF_PROG_VERSION; + } else if (StringUtils.equals(originalKey, TagConstant.SYSTEM_FIELD.DESTINATION_INTERFACE)) { + // 系统标签 被调用方API + return MessageMetadataContainer.LABEL_KEY_PATH; + } else if (StringUtils.equals(originalKey, TagConstant.SYSTEM_FIELD.REQUEST_HTTP_METHOD)) { + // 系统标签 HTTP METHOD + return MessageMetadataContainer.LABEL_KEY_METHOD; + } + return originalKey; + } +} diff --git a/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/common/TagConstant.java b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/common/TagConstant.java new file mode 100644 index 000000000..78d604376 --- /dev/null +++ b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/common/TagConstant.java @@ -0,0 +1,160 @@ +/* + * Tencent is pleased to support the open source community by making Polaris available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.plugins.connector.consul.service.common; + +/** + * TSF 标签常量 + * + * @author hongweizhu + */ +public class TagConstant { + + /** + * 标签类型 + * + * @author hongweizhu + */ + public static class TYPE { + /** + * 系统标签 + */ + public static final String SYSTEM = "S"; + /** + * 用户自定义标签 + */ + public static final String CUSTOM = "U"; + } + + /** + * 规则之间运算表达式的逻辑关系 + * + * @author juanyinyang + */ + public static class TagRuleRelation { + /** + * 与 + */ + public static final String AND = "AND"; + /** + * 或 + */ + public static final String OR = "OR"; + } + + /** + * 操作符 + * + * @author hongweizhu + */ + public static class OPERATOR { + /** + * 包含 + */ + public static final String IN = "IN"; + /** + * 不包含 + */ + public static final String NOT_IN = "NOT_IN"; + /** + * 等于 + */ + public static final String EQUAL = "EQUAL"; + /** + * 不等于 + */ + public static final String NOT_EQUAL = "NOT_EQUAL"; + /** + * 正则 + */ + public static final String REGEX = "REGEX"; + } + + /** + * 系统标签名 + * + * @author vanqfjiang + */ + public static class SYSTEM_FIELD { + /** + * 请求发起方的应用 ID + */ + public static final String SOURCE_APPLICATION_ID = "source.application.id"; + /** + * 请求发起方的应用版本号 + */ + public static final String SOURCE_APPLICATION_VERSION = "source.application.version"; + /** + * 请求发起方的实例 ID + */ + public static final String SOURCE_INSTANCE_ID = "source.instance.id"; + /** + * 请求发起方的部署组 ID + */ + public static final String SOURCE_GROUP_ID = "source.group.id"; + /** + * 请求发起方 IP + */ + public static final String SOURCE_CONNECTION_IP = "source.connection.ip"; + /** + * 请求发起方的服务名 + */ + public static final String SOURCE_SERVICE_NAME = "source.service.name"; + + /** + * 请求发起方的 Namespace/serviceName + */ + public static final String SOURCE_NAMESPACE_SERVICE_NAME = "source.namespace.service.name"; + + /** + * 请求发起方的服务 token,鉴权模块使用 + */ + public static final String SOURCE_SERVICE_TOKEN = "source.service.token"; + /** + * 请求发起方被它的上游调用的接口(如果有) + */ + public static final String SOURCE_INTERFACE = "source.interface"; + /** + * 请求接收方的服务名 + */ + public static final String DESTINATION_SERVICE_NAME = "destination.service.name"; + /** + * 请求接收方被调用的接口 + */ + public static final String DESTINATION_INTERFACE = "destination.interface"; + + /** + * 请求接收方的应用 + */ + public static final String DESTINATION_APPLICATION_ID = "destination.application.id"; + /** + * 请求接收方被调用的接口 + */ + public static final String DESTINATION_APPLICATION_VERSION = "destination.application.version"; + + /** + * 请求接收方的部署组 ID + */ + public static final String DESTINATION_GROUP_ID = "destination.group.id"; + + /** + * 请求所使用的 HTTP 方法 + */ + public static final String REQUEST_HTTP_METHOD = "request.http.method"; + + } +} diff --git a/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/router/RouterRuleService.java b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/router/RouterRuleService.java new file mode 100644 index 000000000..03b5aa267 --- /dev/null +++ b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/router/RouterRuleService.java @@ -0,0 +1,324 @@ +/* + * Tencent is pleased to support the open source community by making Polaris available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.plugins.connector.consul.service.router; + +import com.ecwid.consul.SingleUrlParameters; +import com.ecwid.consul.UrlParameters; +import com.ecwid.consul.json.GsonFactory; +import com.ecwid.consul.transport.HttpResponse; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.ConsulRawClient; +import com.ecwid.consul.v1.QueryParams; +import com.ecwid.consul.v1.kv.model.GetValue; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Lists; +import com.google.gson.reflect.TypeToken; +import com.google.protobuf.BoolValue; +import com.google.protobuf.StringValue; +import com.google.protobuf.UInt32Value; +import com.tencent.polaris.api.exception.ErrorCode; +import com.tencent.polaris.api.exception.PolarisException; +import com.tencent.polaris.api.exception.ServerCodes; +import com.tencent.polaris.api.exception.ServerErrorResponseException; +import com.tencent.polaris.api.plugin.server.ServerEvent; +import com.tencent.polaris.api.utils.CollectionUtils; +import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.logging.LoggerFactory; +import com.tencent.polaris.plugins.connector.common.ServiceUpdateTask; +import com.tencent.polaris.plugins.connector.consul.ConsulContext; +import com.tencent.polaris.plugins.connector.consul.service.ConsulService; +import com.tencent.polaris.plugins.connector.consul.service.common.TagConstant; +import com.tencent.polaris.plugins.connector.consul.service.router.entity.*; +import com.tencent.polaris.specification.api.v1.model.ModelProto; +import com.tencent.polaris.specification.api.v1.service.manage.ResponseProto; +import com.tencent.polaris.specification.api.v1.service.manage.ServiceProto; +import com.tencent.polaris.specification.api.v1.traffic.manage.RoutingProto; +import org.slf4j.Logger; +import org.yaml.snakeyaml.Yaml; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +import static com.tencent.polaris.api.config.plugin.DefaultPlugins.SERVER_CONNECTOR_CONSUL; +import static com.tencent.polaris.api.plugin.route.RouterConstants.ROUTER_FAULT_TOLERANCE_ENABLE; +import static com.tencent.polaris.plugins.connector.consul.service.common.TagConditionUtil.parseMatchStringType; +import static com.tencent.polaris.plugins.connector.consul.service.common.TagConditionUtil.parseMetadataKey; + +/** + * @author Haotian Zhang + */ +public class RouterRuleService extends ConsulService { + + private static final Logger LOG = LoggerFactory.getLogger(RouterRuleService.class); + + private final Map routerRuleConsulIndexMap = new ConcurrentHashMap<>(); + + public RouterRuleService(ConsulClient consulClient, ConsulRawClient consulRawClient, ConsulContext consulContext, + String threadName, ObjectMapper mapper) { + super(consulClient, consulRawClient, consulContext, threadName, mapper); + } + + @Override + public void sendRequest(ServiceUpdateTask serviceUpdateTask) { + String namespace = serviceUpdateTask.getServiceEventKey().getNamespace(); + String service = serviceUpdateTask.getServiceEventKey().getService(); + String routeRuleKey = String.format("/v1/kv/route/%s/%s/data", namespace, service); + UrlParameters nsTypeParam = new SingleUrlParameters("nsType", "DEF_AND_GLOBAL"); + UrlParameters tokenParam = new SingleUrlParameters("token", consulContext.getAclToken()); + UrlParameters recurseParam = new SingleUrlParameters("recurse"); + RouterRuleKey routerRuleKey = new RouterRuleKey(); + routerRuleKey.setNamespace(namespace); + routerRuleKey.setService(service); + Long currentIndex = getRouterRuleConsulIndex(routerRuleKey); + QueryParams queryParams = new QueryParams(consulContext.getWaitTime(), currentIndex); + int code = ServerCodes.DATA_NO_CHANGE; + try { + LOG.debug("Begin get router rules of {} sync", routerRuleKey); + HttpResponse rawResponse = consulRawClient.makeGetRequest(routeRuleKey, recurseParam, tokenParam, + nsTypeParam, queryParams); + if (rawResponse != null) { + if (LOG.isDebugEnabled()) { + String responseStr = "RawResponse{" + + "statusCode=" + rawResponse.getStatusCode() + + ", statusMessage='" + rawResponse.getStatusMessage() + '\'' + + ", content='" + rawResponse.getContent() + '\'' + + ", consulIndex=" + rawResponse.getConsulIndex() + '\'' + + ", consulKnownLeader=" + rawResponse.isConsulKnownLeader() + '\'' + + ", consulLastContact=" + rawResponse.getConsulLastContact() + + '}'; + LOG.debug("tsf route rule, consul kv namespace, response: {}", responseStr); + } + + Long newIndex = rawResponse.getConsulIndex(); + // create service. + ServiceProto.Service.Builder newServiceBuilder = ServiceProto.Service.newBuilder(); + newServiceBuilder.setNamespace(StringValue.of(namespace)); + newServiceBuilder.setName(StringValue.of(service)); + newServiceBuilder.setRevision(StringValue.of(String.valueOf(newIndex))); + // create routing. + RoutingProto.Routing.Builder newRoutingBuilder = RoutingProto.Routing.newBuilder(); + newRoutingBuilder.setNamespace(StringValue.of(namespace)); + newRoutingBuilder.setService(StringValue.of(service)); + newRoutingBuilder.setRevision(StringValue.of(String.valueOf(newIndex))); + // create discover response. + ResponseProto.DiscoverResponse.Builder newDiscoverResponseBuilder = ResponseProto.DiscoverResponse.newBuilder(); + newDiscoverResponseBuilder.setService(newServiceBuilder); + // 重写index + List routes = new ArrayList<>(); + if (Objects.nonNull(newIndex)) { + if (!Objects.equals(currentIndex, newIndex)) { + code = ServerCodes.EXECUTE_SUCCESS; + if (rawResponse.getStatusCode() == 200) { + if (rawResponse.getContent() != null) { + LOG.info("new route rule: {}", rawResponse.getContent()); + routes = parseResponse(rawResponse, namespace, service); + } + } else if (rawResponse.getStatusCode() == 404) { + LOG.info("empty route rule: {}", rawResponse.getContent()); + } + } else { + LOG.debug("[TSF Route Rule] Consul data is not changed"); + } + } else { + LOG.warn("[TSF Route Rule] Consul data is abnormal. {}", rawResponse); + } + if (CollectionUtils.isNotEmpty(routes)) { + newRoutingBuilder.addAllInbounds(routes); + } + newDiscoverResponseBuilder.setRouting(newRoutingBuilder); + newDiscoverResponseBuilder.setCode(UInt32Value.of(code)); + ServerEvent serverEvent = new ServerEvent(serviceUpdateTask.getServiceEventKey(), newDiscoverResponseBuilder.build(), null, SERVER_CONNECTOR_CONSUL); + boolean svcDeleted = serviceUpdateTask.notifyServerEvent(serverEvent); + if (newIndex != null) { + setRouterRuleConsulIndex(routerRuleKey, currentIndex, newIndex); + } + if (!svcDeleted) { + serviceUpdateTask.addUpdateTaskSet(); + } + } + } catch (Throwable e) { + LOG.error("[TSF Route Rule] tsf route rule load error. Will sleep for {} ms. Key path:{}", + consulContext.getConsulErrorSleep(), routeRuleKey, e); + try { + Thread.sleep(consulContext.getConsulErrorSleep()); + } catch (Exception e1) { + LOG.error("error in sleep, msg: {}", e1.getMessage()); + } + PolarisException error = ServerErrorResponseException.build(ErrorCode.NETWORK_ERROR.getCode(), + "Get routing sync failed."); + ServerEvent serverEvent = new ServerEvent(serviceUpdateTask.getServiceEventKey(), null, error, SERVER_CONNECTOR_CONSUL); + serviceUpdateTask.notifyServerEvent(serverEvent); + } + } + + private List parseResponse(final HttpResponse response, String namespace, String service) { + List valueList = GsonFactory.getGson().fromJson(response.getContent(), + new TypeToken>() { + }.getType()); + // yaml -> json -> list + Yaml yaml = new Yaml(); + ObjectMapper mapper = new ObjectMapper(); + // 配置 ObjectMapper在反序列化时,忽略目标对象没有的属性 + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + List routeRuleGroupList = Lists.newArrayList(); + valueList.forEach(value -> { + try { + String routeJsonString = mapper + .writeValueAsString(yaml.load(value.getDecodedValue())); + List tempList = mapper.readValue(routeJsonString, + new TypeReference>() { + }); + if (!CollectionUtils.isEmpty(tempList)) { + routeRuleGroupList.add(tempList.get(0)); + } + } catch (Exception ex) { + LOG.error("tsf route rule load error.", ex); + throw new PolarisException(ErrorCode.INVALID_RESPONSE, "tsf route rule load error", ex); + } + }); + + // list -> List + List routes = Lists.newArrayList(); + for (RouteRuleGroup routeRuleGroup : routeRuleGroupList) { + for (RouteRule routeRule : routeRuleGroup.getRuleList()) { + RoutingProto.Route.Builder routeBuilder = RoutingProto.Route.newBuilder(); + routeBuilder.putExtendInfo(ROUTER_FAULT_TOLERANCE_ENABLE, String.valueOf(routeRuleGroup.getFallbackStatus())); + // parse sources + List sources = Lists.newArrayList(); + RoutingProto.Source.Builder sourceBuilder = RoutingProto.Source.newBuilder(); + sourceBuilder.setNamespace(StringValue.of("*")); + sourceBuilder.setService(StringValue.of("*")); + if (CollectionUtils.isNotEmpty(routeRule.getTagList())) { + for (RouteTag routeTag : routeRule.getTagList()) { + if (StringUtils.equals(routeTag.getTagField(), TagConstant.SYSTEM_FIELD.SOURCE_SERVICE_NAME)) { + sourceBuilder.setService(StringValue.of(routeTag.getTagValue())); + } else if (StringUtils.equals(routeTag.getTagField(), TagConstant.SYSTEM_FIELD.SOURCE_NAMESPACE_SERVICE_NAME)) { + String[] split = routeTag.getTagValue().split("/"); + if (split.length == 2) { + sourceBuilder.setNamespace(StringValue.of(split[0])); + sourceBuilder.setService(StringValue.of(split[1])); + } + } else { + ModelProto.MatchString.Builder matchStringBuilder = ModelProto.MatchString.newBuilder(); + matchStringBuilder.setType(parseMatchStringType(routeTag)); + matchStringBuilder.setValue(StringValue.of(routeTag.getTagValue())); + matchStringBuilder.setValueType(ModelProto.MatchString.ValueType.TEXT); + String metadataKey = routeTag.getTagField(); + sourceBuilder.putMetadata(parseMetadataKey(metadataKey), matchStringBuilder.build()); + } + } + } + sources.add(sourceBuilder.build()); + // parse destinations + List destinations = Lists.newArrayList(); + for (RouteDest routeDest : routeRule.getDestList()) { + RoutingProto.Destination.Builder destBuilder = RoutingProto.Destination.newBuilder(); + destBuilder.setNamespace(StringValue.of(namespace)); + destBuilder.setService(StringValue.of(service)); + destBuilder.setPriority(UInt32Value.of(0)); + destBuilder.setIsolate(BoolValue.of(false)); + destBuilder.setWeight(UInt32Value.of(routeDest.getDestWeight())); + destBuilder.setName(StringValue.of(routeDest.getDestId())); + for (RouteDestItem routeDestItem : routeDest.getDestItemList()) { + ModelProto.MatchString.Builder matchStringBuilder = ModelProto.MatchString.newBuilder(); + matchStringBuilder.setType(ModelProto.MatchString.MatchStringType.EXACT); + matchStringBuilder.setValue(StringValue.of(routeDestItem.getDestItemValue())); + matchStringBuilder.setValueType(ModelProto.MatchString.ValueType.TEXT); + destBuilder.putMetadata(routeDestItem.getDestItemField(), matchStringBuilder.build()); + } + destinations.add(destBuilder.build()); + } + routeBuilder.addAllSources(sources); + routeBuilder.addAllDestinations(destinations); + routes.add(routeBuilder.build()); + } + } + return routes; + } + + private Long getRouterRuleConsulIndex(RouterRuleKey routerRuleKey) { + Long index = routerRuleConsulIndexMap.get(routerRuleKey); + if (index != null) { + return index; + } + setRouterRuleConsulIndex(routerRuleKey, null, -1L); + return -1L; + } + + private void setRouterRuleConsulIndex(RouterRuleKey routerRuleKey, Long lastIndex, Long newIndex) { + LOG.debug("RouterRuleKey: {}; lastIndex: {}; newIndex: {}", routerRuleKey, lastIndex, newIndex); + routerRuleConsulIndexMap.put(routerRuleKey, newIndex); + } + + static class RouterRuleKey { + private String namespace = ""; + private String service = ""; + private Boolean fetchGroup = true; + + public String getNamespace() { + return namespace; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + public String getService() { + return service; + } + + public void setService(String service) { + this.service = service; + } + + public Boolean getFetchGroup() { + return fetchGroup; + } + + public void setFetchGroup(Boolean fetchGroup) { + this.fetchGroup = fetchGroup; + } + + @Override + public boolean equals(Object object) { + if (this == object) return true; + if (object == null || getClass() != object.getClass()) return false; + RouterRuleKey that = (RouterRuleKey) object; + return Objects.equals(getNamespace(), that.getNamespace()) && Objects.equals(getService(), that.getService()) && Objects.equals(getFetchGroup(), that.getFetchGroup()); + } + + @Override + public int hashCode() { + return Objects.hash(getNamespace(), getService(), getFetchGroup()); + } + + @Override + public String toString() { + return "RouterRuleKey{" + + "namespace='" + namespace + '\'' + + ", serviceName='" + service + '\'' + + ", fetchGroup=" + fetchGroup + + '}'; + } + } +} diff --git a/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/router/entity/RouteDest.java b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/router/entity/RouteDest.java new file mode 100644 index 000000000..bc6186060 --- /dev/null +++ b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/router/entity/RouteDest.java @@ -0,0 +1,108 @@ +/* + * Tencent is pleased to support the open source community by making Polaris available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.plugins.connector.consul.service.router.entity; + +import java.io.Serializable; +import java.util.List; + +/** + * TSF 路由规则目标实体 + * + * @author jingerzhang + */ + +public class RouteDest implements Serializable { + + /** + * serialVersionUID + */ + private static final long serialVersionUID = 984582541720418394L; + + /** + * 空构造函数 + */ + public RouteDest() { + } + + /** + * 路由规则项路由目标Id + */ + + private String destId; + + /** + * 路由目标权重 + */ + private Integer destWeight; + + /** + * 路由目标匹配条件列表 + *

+ * 忽略到数据库表字段的映射 + */ + + private List destItemList; + + /** + * 路由目标所属路由规则项Id + */ + private String routeRuleId; + + public String getDestId() { + return destId; + } + + public void setDestId(String destId) { + this.destId = destId; + } + + public Integer getDestWeight() { + return destWeight; + } + + public void setDestWeight(Integer destWeight) { + this.destWeight = destWeight; + } + + public List getDestItemList() { + return destItemList; + } + + public void setDestItemList(List destItemList) { + this.destItemList = destItemList; + } + + public String getRouteRuleId() { + return routeRuleId; + } + + public void setRouteRuleId(String routeRuleId) { + this.routeRuleId = routeRuleId; + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("RouteDest{"); + sb.append("destId='").append(destId).append('\''); + sb.append(", destWeight=").append(destWeight); + sb.append(", destItemList=").append(destItemList); + sb.append(", routeRuleId='").append(routeRuleId).append('\''); + sb.append('}'); + return sb.toString(); + } +} diff --git a/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/router/entity/RouteDestItem.java b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/router/entity/RouteDestItem.java new file mode 100644 index 000000000..966882885 --- /dev/null +++ b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/router/entity/RouteDestItem.java @@ -0,0 +1,102 @@ +/* + * Tencent is pleased to support the open source community by making Polaris available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.plugins.connector.consul.service.router.entity; + +import java.io.Serializable; + +/** + * TSF 路由规则路由目标匹配项实体 + * + * @author jingerzhang + */ +public class RouteDestItem implements Serializable { + + /** + * serialVersionUID + */ + private static final long serialVersionUID = -2276599402100262473L; + + /** + * 空构造函数 + */ + public RouteDestItem() { + } + + /** + * 路由规则路由目标匹配项ID + */ + private String routeDestItemId; + + /** + * 所属路由规则路由目标ID + */ + private String routeDestId; + + /** + * 路由规则目标字段名称 + */ + private String destItemField; + + /** + * 路由规则目标字段取值 + */ + private String destItemValue; + + public String getDestItemField() { + return destItemField; + } + + public void setDestItemField(String destItemField) { + this.destItemField = destItemField; + } + + public String getDestItemValue() { + return destItemValue; + } + + public void setDestItemValue(String destItemValue) { + this.destItemValue = destItemValue; + } + + public String getRouteDestItemId() { + return routeDestItemId; + } + + public void setRouteDestItemId(String routeDestItemId) { + this.routeDestItemId = routeDestItemId; + } + + public String getRouteDestId() { + return routeDestId; + } + + public void setRouteDestId(String routeDestId) { + this.routeDestId = routeDestId; + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("RouteDestItem{"); + sb.append("routeDestItemId='").append(routeDestItemId).append('\''); + sb.append(", routeDestId='").append(routeDestId).append('\''); + sb.append(", destItemField='").append(destItemField).append('\''); + sb.append(", destItemValue='").append(destItemValue).append('\''); + sb.append('}'); + return sb.toString(); + } +} diff --git a/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/router/entity/RouteRule.java b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/router/entity/RouteRule.java new file mode 100644 index 000000000..1c0a4e67c --- /dev/null +++ b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/router/entity/RouteRule.java @@ -0,0 +1,103 @@ +/* + * Tencent is pleased to support the open source community by making Polaris available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.plugins.connector.consul.service.router.entity; + +import java.io.Serializable; +import java.util.List; + +/** + * TSF 路由规则项实体 + * + * @author jingerzhang + */ +public class RouteRule implements Serializable { + + /** + * serialVersionUID + */ + private static final long serialVersionUID = -1886125299472426511L; + + /** + * 空构造函数 + */ + public RouteRule() { + } + + /** + * 路由规则项ID + */ + private String routeRuleId; + + /** + * 路由规则项所属路由规则ID + */ + private String routeId; + + /** + * 路由规则项包含的匹配条件列表 + */ + private List tagList; + + /** + * 路由规则项包含的目的列表 + */ + private List destList; + + public String getRouteRuleId() { + return routeRuleId; + } + + public void setRouteRuleId(String routeRuleId) { + this.routeRuleId = routeRuleId; + } + + public String getRouteId() { + return routeId; + } + + public void setRouteId(String routeId) { + this.routeId = routeId; + } + + public List getTagList() { + return tagList; + } + + public void setTagList(List tagList) { + this.tagList = tagList; + } + + public List getDestList() { + return destList; + } + + public void setDestList(List destList) { + this.destList = destList; + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("RouteRule{"); + sb.append("routeRuleId='").append(routeRuleId).append('\''); + sb.append(", routeId='").append(routeId).append('\''); + sb.append(", tagList=").append(tagList); + sb.append(", destList=").append(destList); + sb.append('}'); + return sb.toString(); + } +} diff --git a/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/router/entity/RouteRuleGroup.java b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/router/entity/RouteRuleGroup.java new file mode 100644 index 000000000..8e8873fb5 --- /dev/null +++ b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/router/entity/RouteRuleGroup.java @@ -0,0 +1,159 @@ +/* + * Tencent is pleased to support the open source community by making Polaris available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.plugins.connector.consul.service.router.entity; + +import java.io.Serializable; +import java.util.List; + +/** + * TSF 路由规则实体 + * + * @author jingerzhang + */ +public class RouteRuleGroup implements Serializable { + + /** + * serialVersionUID + */ + private static final long serialVersionUID = -3066353351857943148L; + + /** + * 空构造函数 + */ + public RouteRuleGroup() { + } + + /** + * 路由规则主键,全局唯一,前缀route + */ + private String routeId; + + /** + * 路由规则名称 + */ + private String routeName; + + /** + * 路由规则描述 + */ + private String routeDesc; + + /** + * 路由规则微服务ID + */ + private String microserviceId; + + /** + * TAG 路由规则详情 + */ + private List ruleList; + + /** + * microserviceId 微服务所属命名空间id + */ + private String namespaceId; + + /** + * microserviceId 微服务 服务名称 + */ + private String microserviceName; + + /** + * 是否开启路由规则保护策略 + */ + private Boolean fallbackStatus; + + public String getRouteId() { + return routeId; + } + + public void setRouteId(String routeId) { + this.routeId = routeId; + } + + public String getRouteName() { + return routeName; + } + + public void setRouteName(String routeName) { + this.routeName = routeName; + } + + public String getRouteDesc() { + return routeDesc; + } + + public void setRouteDesc(String routeDesc) { + this.routeDesc = routeDesc; + } + + public String getMicroserviceId() { + return microserviceId; + } + + public void setMicroserviceId(String microserviceId) { + this.microserviceId = microserviceId; + } + + public List getRuleList() { + return ruleList; + } + + public void setRuleList(List ruleList) { + this.ruleList = ruleList; + } + + public String getNamespaceId() { + return namespaceId; + } + + public void setNamespaceId(String namespaceId) { + this.namespaceId = namespaceId; + } + + public String getMicroserviceName() { + return microserviceName; + } + + public void setMicroserviceName(String microserviceName) { + this.microserviceName = microserviceName; + } + + public Boolean getFallbackStatus() { + return fallbackStatus; + } + + public void setFallbackStatus(Boolean fallbackStatus) { + this.fallbackStatus = fallbackStatus; + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("RouteRuleGroup{"); + sb.append("routeId='").append(routeId).append('\''); + sb.append(", routeName='").append(routeName).append('\''); + sb.append(", routeDesc='").append(routeDesc).append('\''); + sb.append(", microserviceId='").append(microserviceId).append('\''); + sb.append(", ruleList=").append(ruleList); + sb.append(", namespaceId='").append(namespaceId).append('\''); + sb.append(", microserviceName='").append(microserviceName).append('\''); + sb.append(", fallbackStatus=").append(fallbackStatus); + sb.append('}'); + return sb.toString(); + } +} diff --git a/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/router/entity/RouteTag.java b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/router/entity/RouteTag.java new file mode 100644 index 000000000..87a3b5c94 --- /dev/null +++ b/polaris-plugins/polaris-plugins-connector/connector-consul/src/main/java/com/tencent/polaris/plugins/connector/consul/service/router/entity/RouteTag.java @@ -0,0 +1,61 @@ +/* + * Tencent is pleased to support the open source community by making Polaris available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.polaris.plugins.connector.consul.service.router.entity; + + +import com.tencent.polaris.plugins.connector.consul.service.common.TagCondition; + +/** + * TSF 路由规则项匹配条件实体 + * + * @author jingerzhang + */ +public class RouteTag extends TagCondition { + + /** + * serialVersionUID + */ + private static final long serialVersionUID = 2327676288471562419L; + + /** + * 空构造函数 + */ + public RouteTag() { + } + + /** + * 匹配项所述路由规则项Id + */ + private String routeRuleId; + + public String getRouteRuleId() { + return routeRuleId; + } + + public void setRouteRuleId(String routeRuleId) { + this.routeRuleId = routeRuleId; + } + + + @Override + public String toString() { + return "RouteTag{" + + "routeRuleId='" + routeRuleId + '\'' + + "} " + super.toString(); + } +} diff --git a/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/CircuitBreakCacheHandler.java b/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/CircuitBreakCacheHandler.java index 277ed819a..ade86d1d3 100644 --- a/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/CircuitBreakCacheHandler.java +++ b/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/CircuitBreakCacheHandler.java @@ -17,6 +17,7 @@ package com.tencent.polaris.plugins.connector.grpc.codec; +import com.tencent.polaris.api.plugin.cache.FlowCache; import com.tencent.polaris.api.plugin.registry.AbstractCacheHandler; import com.tencent.polaris.api.pojo.RegistryCacheValue; import com.tencent.polaris.api.pojo.ServiceEventKey.EventType; @@ -41,7 +42,7 @@ protected String getRevision(DiscoverResponse discoverResponse) { } @Override - public RegistryCacheValue messageToCacheValue(RegistryCacheValue oldValue, Object newValue, boolean isCacheLoaded) { + public RegistryCacheValue messageToCacheValue(RegistryCacheValue oldValue, Object newValue, boolean isCacheLoaded, FlowCache flowCache) { DiscoverResponse discoverResponse = (DiscoverResponse) newValue; CircuitBreaker circuitBreaker = discoverResponse.getCircuitBreaker(); String revision = ""; diff --git a/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/FaultDetectCacheHandler.java b/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/FaultDetectCacheHandler.java index f38b83e6e..13ad87c1b 100644 --- a/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/FaultDetectCacheHandler.java +++ b/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/FaultDetectCacheHandler.java @@ -17,6 +17,7 @@ package com.tencent.polaris.plugins.connector.grpc.codec; +import com.tencent.polaris.api.plugin.cache.FlowCache; import com.tencent.polaris.api.plugin.registry.AbstractCacheHandler; import com.tencent.polaris.api.pojo.RegistryCacheValue; import com.tencent.polaris.api.pojo.ServiceEventKey.EventType; @@ -41,7 +42,7 @@ public EventType getTargetEventType() { } @Override - public RegistryCacheValue messageToCacheValue(RegistryCacheValue oldValue, Object newValue, boolean isCacheLoaded) { + public RegistryCacheValue messageToCacheValue(RegistryCacheValue oldValue, Object newValue, boolean isCacheLoaded, FlowCache flowCache) { DiscoverResponse discoverResponse = (DiscoverResponse) newValue; FaultDetector faultDetector = discoverResponse.getFaultDetector(); String revision = ""; diff --git a/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/LaneRuleCacheHandler.java b/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/LaneRuleCacheHandler.java index 178afd961..6c9e0095c 100644 --- a/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/LaneRuleCacheHandler.java +++ b/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/LaneRuleCacheHandler.java @@ -17,15 +17,13 @@ package com.tencent.polaris.plugins.connector.grpc.codec; +import com.tencent.polaris.api.plugin.cache.FlowCache; import com.tencent.polaris.api.plugin.registry.AbstractCacheHandler; import com.tencent.polaris.api.pojo.RegistryCacheValue; import com.tencent.polaris.api.pojo.ServiceEventKey; import com.tencent.polaris.client.pojo.ServiceRuleByProto; import com.tencent.polaris.specification.api.v1.service.manage.ResponseProto; import com.tencent.polaris.specification.api.v1.service.manage.ServiceProto; -import com.tencent.polaris.specification.api.v1.traffic.manage.LaneProto; - -import java.util.List; public class LaneRuleCacheHandler extends AbstractCacheHandler { @Override @@ -40,7 +38,7 @@ public ServiceEventKey.EventType getTargetEventType() { } @Override - public RegistryCacheValue messageToCacheValue(RegistryCacheValue oldValue, Object newValue, boolean isCacheLoaded) { + public RegistryCacheValue messageToCacheValue(RegistryCacheValue oldValue, Object newValue, boolean isCacheLoaded, FlowCache flowCache) { ResponseProto.DiscoverResponse discoverResponse = (ResponseProto.DiscoverResponse) newValue; String revision = discoverResponse.getService().getRevision().getValue(); return new ServiceRuleByProto(discoverResponse, revision, isCacheLoaded, getTargetEventType()); diff --git a/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/RoutingCacheHandler.java b/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/RoutingCacheHandler.java index 04cf5683f..1a0fef5c1 100644 --- a/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/RoutingCacheHandler.java +++ b/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/RoutingCacheHandler.java @@ -17,13 +17,21 @@ package com.tencent.polaris.plugins.connector.grpc.codec; +import com.tencent.polaris.api.plugin.cache.FlowCache; import com.tencent.polaris.api.plugin.registry.AbstractCacheHandler; import com.tencent.polaris.api.pojo.RegistryCacheValue; import com.tencent.polaris.api.pojo.ServiceEventKey.EventType; +import com.tencent.polaris.api.utils.ApiTrieUtil; import com.tencent.polaris.client.pojo.ServiceRuleByProto; +import com.tencent.polaris.specification.api.v1.model.ModelProto; import com.tencent.polaris.specification.api.v1.service.manage.ResponseProto.DiscoverResponse; +import com.tencent.polaris.specification.api.v1.traffic.manage.RoutingProto; import com.tencent.polaris.specification.api.v1.traffic.manage.RoutingProto.Routing; +import java.util.List; + +import static com.tencent.polaris.api.plugin.cache.CacheConstants.API_ID; + public class RoutingCacheHandler extends AbstractCacheHandler { @Override @@ -32,12 +40,35 @@ public EventType getTargetEventType() { } @Override - public RegistryCacheValue messageToCacheValue(RegistryCacheValue oldValue, Object newValue, boolean isCacheLoaded) { + public RegistryCacheValue messageToCacheValue(RegistryCacheValue oldValue, Object newValue, boolean isCacheLoaded, FlowCache flowCache) { DiscoverResponse discoverResponse = (DiscoverResponse) newValue; Routing routing = discoverResponse.getRouting(); String revision = ""; if (null != routing) { revision = routing.getRevision().getValue(); + // 缓存 inbounds 中的 api 树 + List InboundsList = routing.getInboundsList(); + for (RoutingProto.Route route : InboundsList) { + List sources = route.getSourcesList(); + for (RoutingProto.Source source : sources) { + if (source.containsMetadata("$path")) { + ModelProto.MatchString matchString = source.getMetadataOrDefault("$path", ModelProto.MatchString.getDefaultInstance()); + if (matchString.getType() != ModelProto.MatchString.MatchStringType.REGEX) { + if (matchString.getType() == ModelProto.MatchString.MatchStringType.EXACT || matchString.getType() == ModelProto.MatchString.MatchStringType.NOT_EQUALS) { + flowCache.loadPluginCacheObject(API_ID, matchString.getValue().getValue(), + path -> ApiTrieUtil.buildSimpleTrieNode((String) path)); + } else if (matchString.getType() == ModelProto.MatchString.MatchStringType.IN || matchString.getType() == ModelProto.MatchString.MatchStringType.NOT_IN) { + String[] apis = matchString.getValue().getValue().split(","); + for (String api : apis) { + flowCache.loadPluginCacheObject(API_ID, api, + path -> ApiTrieUtil.buildSimpleTrieNode((String) path)); + } + } + } + } + } + } + } return new ServiceRuleByProto(routing, revision, isCacheLoaded, getTargetEventType()); } diff --git a/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/ServiceInstancesCacheHandler.java b/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/ServiceInstancesCacheHandler.java index 239958333..45a46ce4d 100644 --- a/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/ServiceInstancesCacheHandler.java +++ b/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/ServiceInstancesCacheHandler.java @@ -17,6 +17,7 @@ package com.tencent.polaris.plugins.connector.grpc.codec; +import com.tencent.polaris.api.plugin.cache.FlowCache; import com.tencent.polaris.api.plugin.registry.AbstractCacheHandler; import com.tencent.polaris.api.pojo.RegistryCacheValue; import com.tencent.polaris.api.pojo.ServiceEventKey.EventType; @@ -36,7 +37,7 @@ protected String getRevision(DiscoverResponse discoverResponse) { } @Override - public RegistryCacheValue messageToCacheValue(RegistryCacheValue oldValue, Object newValue, boolean isCacheLoaded) { + public RegistryCacheValue messageToCacheValue(RegistryCacheValue oldValue, Object newValue, boolean isCacheLoaded, FlowCache flowCache) { DiscoverResponse discoverResponse = (DiscoverResponse) newValue; ServiceInstancesByProto oldServiceInstances = null; if (null != oldValue) { diff --git a/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/ServicesCacheHandler.java b/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/ServicesCacheHandler.java index e5cbe9a45..43ca033e5 100644 --- a/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/ServicesCacheHandler.java +++ b/polaris-plugins/polaris-plugins-connector/connector-polaris-grpc/src/main/java/com/tencent/polaris/plugins/connector/grpc/codec/ServicesCacheHandler.java @@ -17,6 +17,7 @@ package com.tencent.polaris.plugins.connector.grpc.codec; +import com.tencent.polaris.api.plugin.cache.FlowCache; import com.tencent.polaris.api.plugin.registry.AbstractCacheHandler; import com.tencent.polaris.api.pojo.RegistryCacheValue; import com.tencent.polaris.api.pojo.ServiceEventKey.EventType; @@ -37,7 +38,7 @@ protected String getRevision(DiscoverResponse discoverResponse) { } @Override - public RegistryCacheValue messageToCacheValue(RegistryCacheValue oldValue, Object newValue, boolean isCacheLoaded) { + public RegistryCacheValue messageToCacheValue(RegistryCacheValue oldValue, Object newValue, boolean isCacheLoaded, FlowCache flowCache) { DiscoverResponse discoverResponse = (DiscoverResponse) newValue; return new ServicesByProto(discoverResponse, isCacheLoaded); } diff --git a/polaris-plugins/polaris-plugins-registry/registry-memory/src/main/java/com/tencent/polaris/plugins/registry/memory/CacheObject.java b/polaris-plugins/polaris-plugins-registry/registry-memory/src/main/java/com/tencent/polaris/plugins/registry/memory/CacheObject.java index 1cde82a77..20436a988 100644 --- a/polaris-plugins/polaris-plugins-registry/registry-memory/src/main/java/com/tencent/polaris/plugins/registry/memory/CacheObject.java +++ b/polaris-plugins/polaris-plugins-registry/registry-memory/src/main/java/com/tencent/polaris/plugins/registry/memory/CacheObject.java @@ -102,7 +102,7 @@ public CacheObject(CacheHandler cacheHandler, ServiceEventKey svcEventKey, InMem long nowMs = System.currentTimeMillis(); createTime = nowMs; setLastAccessTimeMs(nowMs); - RegistryCacheValue registryCacheValue = cacheHandler.messageToCacheValue(null, initValue, true); + RegistryCacheValue registryCacheValue = cacheHandler.messageToCacheValue(null, initValue, true, registry.getFlowCache()); value.set(registryCacheValue); } @@ -214,7 +214,7 @@ public boolean onEventUpdate(ServerEvent event) { if (cachedStatus == CachedStatus.CacheChanged || cachedStatus == CachedStatus.CacheNotExists) { LOG.info("OnServiceUpdate: cache {} is pending to update", svcEventKey); this.registry.saveMessageToFile(serviceEventKey, (Message) message); - RegistryCacheValue newCachedValue = cacheHandler.messageToCacheValue(cachedValue, message, false); + RegistryCacheValue newCachedValue = cacheHandler.messageToCacheValue(cachedValue, message, false, registry.getFlowCache()); if (setValue(newCachedValue, event.getPolarisRevision()) && cachedStatus == CachedStatus.CacheChanged) { for (ResourceEventListener listener : resourceEventListeners) { listener.onResourceUpdated(svcEventKey, cachedValue, newCachedValue); diff --git a/polaris-plugins/polaris-plugins-registry/registry-memory/src/main/java/com/tencent/polaris/plugins/registry/memory/InMemoryRegistry.java b/polaris-plugins/polaris-plugins-registry/registry-memory/src/main/java/com/tencent/polaris/plugins/registry/memory/InMemoryRegistry.java index 7d0fca09d..03af4dd78 100644 --- a/polaris-plugins/polaris-plugins-registry/registry-memory/src/main/java/com/tencent/polaris/plugins/registry/memory/InMemoryRegistry.java +++ b/polaris-plugins/polaris-plugins-registry/registry-memory/src/main/java/com/tencent/polaris/plugins/registry/memory/InMemoryRegistry.java @@ -26,17 +26,12 @@ import com.tencent.polaris.api.exception.PolarisException; import com.tencent.polaris.api.plugin.Plugin; import com.tencent.polaris.api.plugin.PluginType; +import com.tencent.polaris.api.plugin.cache.FlowCache; import com.tencent.polaris.api.plugin.common.InitContext; import com.tencent.polaris.api.plugin.common.PluginTypes; import com.tencent.polaris.api.plugin.compose.Extensions; import com.tencent.polaris.api.plugin.compose.ServerServiceInfo; -import com.tencent.polaris.api.plugin.registry.CacheHandler; -import com.tencent.polaris.api.plugin.registry.EventCompleteNotifier; -import com.tencent.polaris.api.plugin.registry.InstanceProperty; -import com.tencent.polaris.api.plugin.registry.LocalRegistry; -import com.tencent.polaris.api.plugin.registry.ResourceEventListener; -import com.tencent.polaris.api.plugin.registry.ResourceFilter; -import com.tencent.polaris.api.plugin.registry.ServiceUpdateRequest; +import com.tencent.polaris.api.plugin.registry.*; import com.tencent.polaris.api.plugin.server.ServerConnector; import com.tencent.polaris.api.plugin.server.ServerEvent; import com.tencent.polaris.api.plugin.server.ServiceEventHandler; @@ -44,19 +39,8 @@ import com.tencent.polaris.api.plugin.stat.DefaultCircuitBreakResult; import com.tencent.polaris.api.plugin.stat.StatInfo; import com.tencent.polaris.api.plugin.stat.StatReporter; -import com.tencent.polaris.api.pojo.CircuitBreakerStatus; -import com.tencent.polaris.api.pojo.DefaultServiceEventKeysProvider; -import com.tencent.polaris.api.pojo.DetectResult; -import com.tencent.polaris.api.pojo.Instance; -import com.tencent.polaris.api.pojo.InstanceLocalValue; -import com.tencent.polaris.api.pojo.RegistryCacheValue; -import com.tencent.polaris.api.pojo.ServiceEventKey; +import com.tencent.polaris.api.pojo.*; import com.tencent.polaris.api.pojo.ServiceEventKey.EventType; -import com.tencent.polaris.api.pojo.ServiceInstances; -import com.tencent.polaris.api.pojo.ServiceKey; -import com.tencent.polaris.api.pojo.ServiceRule; -import com.tencent.polaris.api.pojo.Services; -import com.tencent.polaris.api.pojo.StatusDimension; import com.tencent.polaris.api.utils.CollectionUtils; import com.tencent.polaris.api.utils.MapUtils; import com.tencent.polaris.api.utils.StringUtils; @@ -75,23 +59,9 @@ import org.slf4j.Logger; import java.io.IOException; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Objects; -import java.util.ServiceLoader; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.function.Function; +import java.util.concurrent.*; /** * 本地缓存,保存服务端返回的实例信息. @@ -158,6 +128,11 @@ public class InMemoryRegistry extends Destroyable implements LocalRegistry { */ private boolean persistEnable; + /** + * 缓存是否超时淘汰 + */ + private boolean serviceExpireEnable; + /** * 缓存淘汰时间 */ @@ -168,6 +143,8 @@ public class InMemoryRegistry extends Destroyable implements LocalRegistry { */ private boolean hasDiscoverCluster = false; + private FlowCache flowCache; + private Collection statPlugins; @Override @@ -249,6 +226,15 @@ private ServerConnector getConnector() { return connector; } + /** + * 获取flow cache + * + * @return flow cache + */ + public FlowCache getFlowCache() { + return flowCache; + } + /** * 加载资源 * @@ -487,6 +473,7 @@ public void init(InitContext ctx) throws PolarisException { } NamedThreadFactory namedThreadFactory = new NamedThreadFactory(getName()); serviceExpireTimeMs = ctx.getConfig().getConsumer().getLocalCache().getServiceExpireTime(); + serviceExpireEnable = ctx.getConfig().getConsumer().getLocalCache().isServiceExpireEnable(); persistExecutor = Executors.newSingleThreadExecutor(namedThreadFactory); expireExecutor = Executors.newSingleThreadScheduledExecutor(namedThreadFactory); if (hasDiscoverCluster) { @@ -499,11 +486,14 @@ public void init(InitContext ctx) throws PolarisException { @Override public void postContextInit(Extensions extensions) throws PolarisException { - expireExecutor.scheduleAtFixedRate(new ExpireTask(), 0, serviceExpireTimeMs, TimeUnit.MILLISECONDS); + if (serviceExpireEnable) { + expireExecutor.scheduleAtFixedRate(new ExpireTask(), 0, serviceExpireTimeMs, TimeUnit.MILLISECONDS); + } if (null != serverServicesDiscoverExecutor) { serverServicesDiscoverExecutor.execute(new WarmupDiscoverServiceTask(extensions)); } statPlugins = extensions.getPlugins().getPlugins(PluginTypes.STAT_REPORTER.getBaseType()); + flowCache = extensions.getFlowCache(); } /** diff --git a/polaris-plugins/polaris-plugins-registry/registry-memory/src/main/java/com/tencent/polaris/plugins/registry/memory/MessagePersistHandler.java b/polaris-plugins/polaris-plugins-registry/registry-memory/src/main/java/com/tencent/polaris/plugins/registry/memory/MessagePersistHandler.java index 79665926e..11f7f3450 100644 --- a/polaris-plugins/polaris-plugins-registry/registry-memory/src/main/java/com/tencent/polaris/plugins/registry/memory/MessagePersistHandler.java +++ b/polaris-plugins/polaris-plugins-registry/registry-memory/src/main/java/com/tencent/polaris/plugins/registry/memory/MessagePersistHandler.java @@ -31,14 +31,7 @@ import org.slf4j.Logger; import org.yaml.snakeyaml.Yaml; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.RandomAccessFile; -import java.io.UnsupportedEncodingException; +import java.io.*; import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.channels.FileChannel; @@ -225,8 +218,14 @@ private void doWriteTmpFile(File persistTmpFile, Message message) throws IOExcep String jsonStr = printer.usingTypeRegistry(registry).print(message); JsonNode jsonNodeTree = new ObjectMapper().readTree(jsonStr); String jsonAsYaml = new YAMLMapper().writeValueAsString(jsonNodeTree); + if (LOG.isDebugEnabled()) { + LOG.debug("start write file {} with content: {}.", persistTmpFile.getAbsolutePath(), jsonAsYaml); + } outputFile.write(jsonAsYaml.getBytes(StandardCharsets.UTF_8)); outputFile.flush(); + if (LOG.isDebugEnabled()) { + LOG.debug("write file {} with content: {} finished.", persistTmpFile.getAbsolutePath(), jsonAsYaml); + } } } @@ -282,7 +281,7 @@ public Long apply(ServiceEventKey serviceEventKey, Long aLong) { /** * 遍历缓存目录并加载之前缓存的服务信息 * - * @param eventKey 消息对象 + * @param eventKey 消息对象 * @param builderSupplier * @return 服务标识-消息对象的集合 */ diff --git a/polaris-plugins/polaris-plugins-router/router-metadata/src/main/java/com/tencent/polaris/plugins/router/metadata/MetadataRouter.java b/polaris-plugins/polaris-plugins-router/router-metadata/src/main/java/com/tencent/polaris/plugins/router/metadata/MetadataRouter.java index 4df32c9ff..a9aade17e 100644 --- a/polaris-plugins/polaris-plugins-router/router-metadata/src/main/java/com/tencent/polaris/plugins/router/metadata/MetadataRouter.java +++ b/polaris-plugins/polaris-plugins-router/router-metadata/src/main/java/com/tencent/polaris/plugins/router/metadata/MetadataRouter.java @@ -33,18 +33,16 @@ import com.tencent.polaris.api.rpc.MetadataFailoverType; import com.tencent.polaris.api.utils.CollectionUtils; import com.tencent.polaris.api.utils.MapUtils; +import com.tencent.polaris.api.utils.StringUtils; import com.tencent.polaris.plugins.router.common.AbstractServiceRouter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** * 正常场景:选出的实例子集不为空,那么优先返回健康子集,如果全部不健康则进行全死全活返回不健康子集。 - * + *

* 异常场景:需要根据GetOneInstanceRequest的请求策略进行降级决策 - * + *

* 不降级(默认):返回未找到实例错误 * 返回所有节点:优先返回服务下的健康子集,如果全部不健康则全死全活返回不健康子集 * 返回实例元数据不包含请求metadata的key的节点:优先返回筛选出的健康子集,如果全部不健康则返回不健康子集 @@ -60,6 +58,8 @@ public class MetadataRouter extends AbstractServiceRouter implements PluginConfi private static final String KEY_METADATA_FAILOVER_TYPE = "internal-metadata-failover-type"; + public static final String KEY_METADATA_KEYS = "metadataRouteKeys"; + private static final Map valueToFailoverType = new HashMap<>(); private static final Map inputToFailoverType = new HashMap<>(); @@ -188,6 +188,18 @@ private Map getRouterMetadata(RouteInfo routeInfo) { if (MapUtils.isNotEmpty(metadata)) { return metadata; } - return routeInfo.getRouterMetadata(ROUTER_TYPE_METADATA); + metadata = new HashMap<>(routeInfo.getRouterMetadata(ROUTER_TYPE_METADATA)); + if (routeInfo.getMetadataContainerGroup() != null && routeInfo.getMetadataContainerGroup().getCustomMetadataContainer() != null) { + String metadataRouteKeys = routeInfo.getMetadataContainerGroup().getCustomMetadataContainer().getRawMetadataMapValue(ROUTER_TYPE_METADATA, KEY_METADATA_KEYS); + if (StringUtils.isNotBlank(metadataRouteKeys)) { + String[] keysArr = metadataRouteKeys.split(","); + Set keysSet = new HashSet<>(Arrays.asList(keysArr)); + for (String key : keysSet) { + String value = routeInfo.getMetadataContainerGroup().getCustomMetadataContainer().getRawMetadataStringValue(key); + metadata.put(key, value); + } + } + } + return metadata; } } diff --git a/polaris-plugins/polaris-plugins-router/router-nearby/src/main/java/com/tencent/polaris/plugins/router/nearby/NearbyRouter.java b/polaris-plugins/polaris-plugins-router/router-nearby/src/main/java/com/tencent/polaris/plugins/router/nearby/NearbyRouter.java index e920e015f..ba6d611ad 100644 --- a/polaris-plugins/polaris-plugins-router/router-nearby/src/main/java/com/tencent/polaris/plugins/router/nearby/NearbyRouter.java +++ b/polaris-plugins/polaris-plugins-router/router-nearby/src/main/java/com/tencent/polaris/plugins/router/nearby/NearbyRouter.java @@ -17,8 +17,6 @@ package com.tencent.polaris.plugins.router.nearby; -import static com.tencent.polaris.client.util.Utils.isHealthyInstance; - import com.tencent.polaris.api.config.consumer.ServiceRouterConfig; import com.tencent.polaris.api.config.plugin.PluginConfigProvider; import com.tencent.polaris.api.config.verify.Verifier; @@ -40,17 +38,12 @@ import com.tencent.polaris.api.utils.StringUtils; import com.tencent.polaris.logging.LoggerFactory; import com.tencent.polaris.plugins.router.common.AbstractServiceRouter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; +import org.slf4j.Logger; + +import java.util.*; import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; -import org.slf4j.Logger; +import static com.tencent.polaris.client.util.Utils.isHealthyInstance; /** * 就近接入路由 @@ -66,7 +59,7 @@ public class NearbyRouter extends AbstractServiceRouter implements PluginConfigP public static final String ROUTER_METADATA_KEY_REGION = "region"; public static final String ROUTER_METADATA_KEY_CAMPUS = "campus"; - private static final String NEARBY_METADATA_ENABLE = "internal-enable-nearby"; + private static final String NEARBY_METADATA_ENABLE = "internal-enable-nearby"; private static final Logger LOG = LoggerFactory.getLogger(NearbyRouter.class); @@ -170,7 +163,7 @@ private LocationLevel nextLevel(LocationLevel current) { } private CheckResult hasHealthyInstances(ServiceInstances svcInstances, - LocationLevel targetLevel, Map clientInfo) { + LocationLevel targetLevel, Map clientInfo) { String clientZone = ""; String clientRegion = ""; String clientCampus = ""; @@ -353,12 +346,21 @@ public boolean enable(RouteInfo routeInfo, ServiceMetadata dstSvcInfo) { } //默认关闭,需要显示打开 + boolean enabled = false; + if (routeInfo.getMetadataContainerGroup() != null && routeInfo.getMetadataContainerGroup().getCustomMetadataContainer() != null) { + String enabledStr = routeInfo.getMetadataContainerGroup().getCustomMetadataContainer().getRawMetadataMapValue(ROUTER_TYPE_NEAR_BY, ROUTER_ENABLED); + if (StringUtils.isNotBlank(enabledStr) && Boolean.parseBoolean(enabledStr)) { + enabled = true; + } + } Map routerMetadata = routeInfo.getRouterMetadata(ROUTER_TYPE_NEAR_BY); if (MapUtils.isNotEmpty(routerMetadata)) { - String enabled = routerMetadata.get(ROUTER_ENABLED); - return StringUtils.isNotBlank(enabled) && Boolean.parseBoolean(enabled); + String enabledStr = routerMetadata.get(ROUTER_ENABLED); + if (StringUtils.isNotBlank(enabledStr) && Boolean.parseBoolean(enabledStr)) { + enabled = true; + } } - return false; + return enabled; } @Override diff --git a/polaris-plugins/polaris-plugins-router/router-rule/src/main/java/com/tencent/polaris/plugins/router/rule/RuleBasedRouter.java b/polaris-plugins/polaris-plugins-router/router-rule/src/main/java/com/tencent/polaris/plugins/router/rule/RuleBasedRouter.java index 5920e91ce..928db40a4 100644 --- a/polaris-plugins/polaris-plugins-router/router-rule/src/main/java/com/tencent/polaris/plugins/router/rule/RuleBasedRouter.java +++ b/polaris-plugins/polaris-plugins-router/router-rule/src/main/java/com/tencent/polaris/plugins/router/rule/RuleBasedRouter.java @@ -23,8 +23,10 @@ import com.tencent.polaris.api.exception.ErrorCode; import com.tencent.polaris.api.exception.PolarisException; import com.tencent.polaris.api.plugin.PluginType; +import com.tencent.polaris.api.plugin.cache.FlowCache; import com.tencent.polaris.api.plugin.common.InitContext; import com.tencent.polaris.api.plugin.common.PluginTypes; +import com.tencent.polaris.api.plugin.compose.Extensions; import com.tencent.polaris.api.plugin.route.RouteInfo; import com.tencent.polaris.api.plugin.route.RouteResult; import com.tencent.polaris.api.plugin.route.ServiceRouter; @@ -33,22 +35,19 @@ import com.tencent.polaris.api.pojo.ServiceInstances; import com.tencent.polaris.api.pojo.ServiceMetadata; import com.tencent.polaris.api.rpc.RuleBasedRouterFailoverType; -import com.tencent.polaris.api.utils.CollectionUtils; -import com.tencent.polaris.api.utils.MapUtils; -import com.tencent.polaris.api.utils.RuleUtils; -import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.api.utils.*; import com.tencent.polaris.logging.LoggerFactory; +import com.tencent.polaris.metadata.core.manager.MetadataContainerGroup; import com.tencent.polaris.plugins.router.common.AbstractServiceRouter; import com.tencent.polaris.specification.api.v1.traffic.manage.RoutingProto; import com.tencent.polaris.specification.api.v1.traffic.manage.RoutingProto.Destination; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; import org.slf4j.Logger; +import java.util.*; + +import static com.tencent.polaris.api.plugin.cache.CacheConstants.API_ID; +import static com.tencent.polaris.api.plugin.route.RouterConstants.ROUTER_FAULT_TOLERANCE_ENABLE; + /** * 基于规则的服务路由能力 * @@ -65,6 +64,8 @@ public class RuleBasedRouter extends AbstractServiceRouter implements PluginConf private RuleBasedRouterConfig routerConfig; + private FlowCache flowCache; + /** * 根据路由规则进行服务实例过滤, 并返回过滤后的实例列表 * @@ -104,8 +105,9 @@ private List getRoutesFromRule(RouteInfo routeInfo, RuleMatc // 匹配source规则 private boolean matchSource(List sources, Service sourceService, - Map trafficLabels, - RuleMatchType ruleMatchType, Map multiEnvRouterParamMap) { + Map trafficLabels, + MetadataContainerGroup metadataContainerGroup, + RuleMatchType ruleMatchType, Map multiEnvRouterParamMap) { if (CollectionUtils.isEmpty(sources)) { return true; } @@ -151,8 +153,9 @@ private boolean matchSource(List sources, Service sourceSer continue; } - matched = RuleUtils.matchMetadata( - source.getMetadataMap(), trafficLabels, true, multiEnvRouterParamMap, globalVariablesConfig); + matched = RuleUtils.matchMetadata(source.getMetadataMap(), trafficLabels, metadataContainerGroup, true, + multiEnvRouterParamMap, globalVariablesConfig, + key -> flowCache.loadPluginCacheObject(API_ID, key, path -> ApiTrieUtil.buildSimpleTrieNode((String) path))); if (matched) { break; } @@ -176,7 +179,7 @@ private List filterAvailableDestinations(List getRuleFilteredInstances(RouteInfo routeInfo, ServiceInstances instances, - RuleMatchType ruleMatchType, MatchStatus matchStatus) throws PolarisException { + RuleMatchType ruleMatchType, MatchStatus matchStatus) throws PolarisException { // 获取路由规则 List routes = getRoutesFromRule(routeInfo, ruleMatchType); if (CollectionUtils.isEmpty(routes)) { @@ -186,6 +189,8 @@ private List getRuleFilteredInstances(RouteInfo routeInfo, ServiceInst for (RoutingProto.Route route : routes) { if (route == null) { continue; + } else { + matchStatus.fallback = Boolean.parseBoolean(route.getExtendInfoMap().get(ROUTER_FAULT_TOLERANCE_ENABLE)); } if (LOG.isDebugEnabled()) { @@ -193,10 +198,10 @@ private List getRuleFilteredInstances(RouteInfo routeInfo, ServiceInst } Map trafficLabels = routeInfo.getRouterMetadata(ROUTER_TYPE_RULE_BASED); + MetadataContainerGroup metadataContainerGroup = routeInfo.getMetadataContainerGroup(); // 匹配source规则 boolean sourceMatched = matchSource(route.getSourcesList(), routeInfo.getSourceService(), trafficLabels, - ruleMatchType, - multiEnvRouterParamMap); + metadataContainerGroup, ruleMatchType, multiEnvRouterParamMap); if (!sourceMatched) { continue; } @@ -248,8 +253,8 @@ private List getRuleFilteredInstances(RouteInfo routeInfo, ServiceInst /** * populateSubsetsFromDest 根据destination中的规则填充分组列表 * - * @param instances 实例信息 - * @param dest 目标规则 + * @param instances 实例信息 + * @param dest 目标规则 * @param subsetsMap 实例分组 * @return 是否成功加入subset列表 */ @@ -330,6 +335,7 @@ public RouteResult router(RouteInfo routeInfo, ServiceInstances instances) { // 优先匹配inbound规则, 成功则不需要继续匹配outbound规则 List destFilteredInstances = null; List sourceFilteredInstances = null; + MatchStatus matchStatus = new MatchStatus(); if (routeInfo.getDestRouteRule() != null) { destFilteredInstances = getRuleFilteredInstances(routeInfo, instances, @@ -345,17 +351,20 @@ public RouteResult router(RouteInfo routeInfo, ServiceInstances instances) { // 然后匹配outbound规则 sourceFilteredInstances = getRuleFilteredInstances(routeInfo, instances, RuleMatchType.sourceRouteRuleMatch, matchStatus); - if (sourceFilteredInstances.isEmpty()) { - ruleStatus = RuleStatus.sourceRuleFail; - } else { + if (!sourceFilteredInstances.isEmpty()) { ruleStatus = RuleStatus.sourceRuleSucc; } + if (sourceFilteredInstances.isEmpty() && matchStatus.matched) { + ruleStatus = RuleStatus.sourceRuleFail; + } } switch (ruleStatus) { case sourceRuleSucc: return new RouteResult(sourceFilteredInstances, RouteResult.State.Next); case destRuleSucc: return new RouteResult(destFilteredInstances, RouteResult.State.Next); + case noRule: + return new RouteResult(instances.getInstances(), RouteResult.State.Next); default: LOG.warn("route rule not match, rule status: {}, not matched source {}", ruleStatus, routeInfo.getSourceService()); @@ -366,7 +375,7 @@ public RouteResult router(RouteInfo routeInfo, ServiceInstances instances) { failoverType = routerConfig.getFailoverType(); } - if (failoverType == RuleBasedRouterFailoverType.none) { + if (failoverType == RuleBasedRouterFailoverType.none && !matchStatus.fallback) { return new RouteResult(Collections.emptyList(), RouteResult.State.Next); } @@ -377,6 +386,8 @@ public RouteResult router(RouteInfo routeInfo, ServiceInstances instances) { private static class MatchStatus { boolean matched; + + boolean fallback = false; } private List getHealthyInstances(List instances) { @@ -436,6 +447,11 @@ public void init(InitContext ctx) throws PolarisException { .getPluginConfig(getName(), RuleBasedRouterConfig.class); } + @Override + public void postContextInit(Extensions extensions) throws PolarisException { + flowCache = extensions.getFlowCache(); + } + @Override public ServiceRouter.Aspect getAspect() { return ServiceRouter.Aspect.MIDDLE; @@ -452,13 +468,23 @@ public boolean enable(RouteInfo routeInfo, ServiceMetadata dstSvcInfo) { } //默认开启,需要显示关闭 + boolean enabled = true; + if (routeInfo.getMetadataContainerGroup() != null && routeInfo.getMetadataContainerGroup().getCustomMetadataContainer() != null) { + String enabledStr = routeInfo.getMetadataContainerGroup().getCustomMetadataContainer().getRawMetadataMapValue(ROUTER_TYPE_RULE_BASED, ROUTER_ENABLED); + if (StringUtils.isNotBlank(enabledStr) && !Boolean.parseBoolean(enabledStr)) { + enabled = false; + } + } Map routerMetadata = routeInfo.getRouterMetadata(ROUTER_TYPE_RULE_BASED); if (MapUtils.isNotEmpty(routerMetadata)) { - String enabled = routerMetadata.get(ROUTER_ENABLED); - if (StringUtils.isNotBlank(enabled) && !Boolean.parseBoolean(enabled)) { - return false; + String enabledStr = routerMetadata.get(ROUTER_ENABLED); + if (StringUtils.isNotBlank(enabledStr) && !Boolean.parseBoolean(enabledStr)) { + enabled = false; } } + if (!enabled) { + return false; + } List dstRoutes = getRoutesFromRule(routeInfo, RuleMatchType.destRouteRuleMatch); List srcRoutes = getRoutesFromRule(routeInfo, RuleMatchType.sourceRouteRuleMatch); diff --git a/polaris-ratelimit/polaris-ratelimit-client/src/main/java/com/tencent/polaris/ratelimit/client/codec/RateLimitingCacheHandler.java b/polaris-ratelimit/polaris-ratelimit-client/src/main/java/com/tencent/polaris/ratelimit/client/codec/RateLimitingCacheHandler.java index 1ecedd009..030572183 100644 --- a/polaris-ratelimit/polaris-ratelimit-client/src/main/java/com/tencent/polaris/ratelimit/client/codec/RateLimitingCacheHandler.java +++ b/polaris-ratelimit/polaris-ratelimit-client/src/main/java/com/tencent/polaris/ratelimit/client/codec/RateLimitingCacheHandler.java @@ -18,6 +18,7 @@ package com.tencent.polaris.ratelimit.client.codec; import com.google.protobuf.StringValue; +import com.tencent.polaris.api.plugin.cache.FlowCache; import com.tencent.polaris.api.plugin.registry.AbstractCacheHandler; import com.tencent.polaris.api.pojo.RegistryCacheValue; import com.tencent.polaris.api.pojo.ServiceEventKey.EventType; @@ -32,6 +33,7 @@ import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto.MatchArgument.Type; import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto.RateLimit; import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto.Rule; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -54,7 +56,7 @@ protected String getRevision(DiscoverResponse discoverResponse) { } @Override - public RegistryCacheValue messageToCacheValue(RegistryCacheValue oldValue, Object newValue, boolean isCacheLoaded) { + public RegistryCacheValue messageToCacheValue(RegistryCacheValue oldValue, Object newValue, boolean isCacheLoaded, FlowCache flowCache) { DiscoverResponse discoverResponse = (DiscoverResponse) newValue; RateLimit rateLimit = discoverResponse.getRateLimit(); String revision = getRevision(discoverResponse); diff --git a/polaris-router/polaris-router-api/src/main/java/com/tencent/polaris/router/api/rpc/ProcessRoutersRequest.java b/polaris-router/polaris-router-api/src/main/java/com/tencent/polaris/router/api/rpc/ProcessRoutersRequest.java index 352bda05d..d77628060 100644 --- a/polaris-router/polaris-router-api/src/main/java/com/tencent/polaris/router/api/rpc/ProcessRoutersRequest.java +++ b/polaris-router/polaris-router-api/src/main/java/com/tencent/polaris/router/api/rpc/ProcessRoutersRequest.java @@ -17,230 +17,246 @@ package com.tencent.polaris.router.api.rpc; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; - import com.tencent.polaris.api.pojo.RouteArgument; import com.tencent.polaris.api.pojo.ServiceInfo; import com.tencent.polaris.api.pojo.ServiceInstances; import com.tencent.polaris.api.pojo.SourceService; import com.tencent.polaris.api.rpc.MetadataFailoverType; import com.tencent.polaris.api.rpc.RequestBaseEntity; +import com.tencent.polaris.api.rpc.RuleBasedRouterFailoverType; import com.tencent.polaris.api.utils.CollectionUtils; import com.tencent.polaris.api.utils.MapUtils; +import com.tencent.polaris.metadata.core.manager.MetadataContainerGroup; + +import java.util.*; +import java.util.function.Function; /** * 路由处理请求 */ public class ProcessRoutersRequest extends RequestBaseEntity { - private SourceService sourceService; + private SourceService sourceService; + + private RouterNamesGroup routers; + + private ServiceInstances dstInstances; + + private String method; + + //各个路由插件依赖的 metadata 参数 + private Map> routerArgument; - private RouterNamesGroup routers; + private MetadataContainerGroup metadataContainerGroup; - private ServiceInstances dstInstances; + //元数据路由降级策略 + private MetadataFailoverType metadataFailoverType; + // 规则路由降级策略 + private RuleBasedRouterFailoverType ruleBasedRouterFailoverType; - private String method; - - //各个路由插件依赖的 metadata 参数 - private Map> routerArgument; - //元数据路由降级策略 - private MetadataFailoverType metadataFailoverType; - - /** - * 北极星内部治理规则执行时,会识别规则中的参数来源类别,如果发现规则中的参数来源指定为外部数据源时,会调用本接口进行获取 - * - * 可以实现该接口,实现规则中的参数来源于配置中心、数据库、环境变量等等 - */ - private Function> externalParameterSupplier = s -> Optional.empty(); - - public Function> getExternalParameterSupplier() { - return externalParameterSupplier; - } - - public void setExternalParameterSupplier(Function> externalParameterSupplier) { - this.externalParameterSupplier = externalParameterSupplier; - } - - public ServiceInfo getSourceService() { - return sourceService; - } - - public void setSourceService(ServiceInfo serviceInfo) { - this.sourceService = new SourceService(); - this.sourceService.setService(serviceInfo.getService()); - this.sourceService.setNamespace(serviceInfo.getNamespace()); - - Optional.ofNullable(serviceInfo.getMetadata()).orElse(new HashMap<>()) - .forEach((key, value) -> sourceService.appendArguments(RouteArgument.fromLabel(key, value))); - - buildRouterArgumentsBySourceService(); - } - - public String getMethod() { - return method; - } - - public void setMethod(String method) { - this.method = method; - } - - public RouterNamesGroup getRouters() { - return routers; - } - - public void setRouters(RouterNamesGroup routers) { - this.routers = routers; - } - - public ServiceInstances getDstInstances() { - return dstInstances; - } - - public void setDstInstances(ServiceInstances dstInstances) { - this.dstInstances = dstInstances; - } - - public void putRouterArgument(String routerType, Set arguments) { - if (CollectionUtils.isEmpty(arguments)) { - return; - } - if (routerArgument == null) { - routerArgument = new HashMap<>(); - } - - routerArgument.put(routerType, arguments); - } + /** + * 北极星内部治理规则执行时,会识别规则中的参数来源类别,如果发现规则中的参数来源指定为外部数据源时,会调用本接口进行获取 + *

+ * 可以实现该接口,实现规则中的参数来源于配置中心、数据库、环境变量等等 + */ + private Function> externalParameterSupplier = s -> Optional.empty(); - public Set getRouterArguments(String routerType) { - buildRouterArgumentsBySourceService(); - Set arguments = routerArgument.get(routerType); - if (CollectionUtils.isEmpty(arguments)) { - return Collections.emptySet(); - } - - return Collections.unmodifiableSet(arguments); - } - - public Map> getRouterArguments() { - buildRouterArgumentsBySourceService(); - Map> routerArgument = new HashMap<>(this.routerArgument); - return Collections.unmodifiableMap(routerArgument); - } + public Function> getExternalParameterSupplier() { + return externalParameterSupplier; + } - public MetadataFailoverType getMetadataFailoverType() { - return metadataFailoverType; - } + public void setExternalParameterSupplier(Function> externalParameterSupplier) { + this.externalParameterSupplier = externalParameterSupplier; + } + + public ServiceInfo getSourceService() { + return sourceService; + } + + public void setSourceService(ServiceInfo serviceInfo) { + this.sourceService = new SourceService(); + this.sourceService.setService(serviceInfo.getService()); + this.sourceService.setNamespace(serviceInfo.getNamespace()); + + Optional.ofNullable(serviceInfo.getMetadata()).orElse(new HashMap<>()) + .forEach((key, value) -> sourceService.appendArguments(RouteArgument.fromLabel(key, value))); + + buildRouterArgumentsBySourceService(); + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public RouterNamesGroup getRouters() { + return routers; + } + + public void setRouters(RouterNamesGroup routers) { + this.routers = routers; + } + + public ServiceInstances getDstInstances() { + return dstInstances; + } + + public void setDstInstances(ServiceInstances dstInstances) { + this.dstInstances = dstInstances; + } + + public void putRouterArgument(String routerType, Set arguments) { + if (CollectionUtils.isEmpty(arguments)) { + return; + } + if (routerArgument == null) { + routerArgument = new HashMap<>(); + } + + routerArgument.put(routerType, arguments); + } + + public Set getRouterArguments(String routerType) { + buildRouterArgumentsBySourceService(); + Set arguments = routerArgument.get(routerType); + if (CollectionUtils.isEmpty(arguments)) { + return Collections.emptySet(); + } + + return Collections.unmodifiableSet(arguments); + } + + public Map> getRouterArguments() { + buildRouterArgumentsBySourceService(); + Map> routerArgument = new HashMap<>(this.routerArgument); + return Collections.unmodifiableMap(routerArgument); + } - public void setMetadataFailoverType(MetadataFailoverType metadataFailoverType) { - this.metadataFailoverType = metadataFailoverType; - } - - private void buildRouterArgumentsBySourceService() { - if (CollectionUtils.isEmpty(routerArgument)) { - routerArgument = new HashMap<>(); - } - if (Objects.isNull(sourceService)) { - return; - } - Set arguments = routerArgument.computeIfAbsent("ruleRouter", k -> new HashSet<>()); - arguments.addAll(sourceService.getArguments()); - } - - @Deprecated - public void putRouterMetadata(String routerType, Map metadata) { - if (MapUtils.isEmpty(metadata)) { - return; - } - if (routerArgument == null) { - routerArgument = new HashMap<>(); - } - - Set arguments = new HashSet<>(); - metadata.forEach((key, value) -> arguments.add(RouteArgument.fromLabel(key, value))); - - routerArgument.put(routerType, arguments); - } - - @Deprecated - public void addRouterMetadata(String routerType, Map metadata) { - if (MapUtils.isEmpty(metadata)) { - return; - } - - if (routerArgument == null) { - routerArgument = new HashMap<>(); - } - - Set arguments = routerArgument.computeIfAbsent(routerType, k -> new HashSet<>()); - metadata.forEach((key, value) -> arguments.add(RouteArgument.fromLabel(key, value))); - } - - @Deprecated - public Map getRouterMetadata(String routerType) { - buildRouterArgumentsBySourceService(); - Set arguments = routerArgument.get(routerType); - if (CollectionUtils.isEmpty(arguments)) { - return Collections.emptyMap(); - } - - Map metadata = new HashMap<>(); - arguments.forEach(argument -> argument.toLabel(metadata)); - - return Collections.unmodifiableMap(metadata); - } - - @Deprecated - public Map> getRouterMetadata() { - buildRouterArgumentsBySourceService(); - - Map> ret = new HashMap<>(); - - routerArgument.forEach((routerType, arguments) -> { - Map entry = ret.computeIfAbsent(routerType, k -> new HashMap<>()); - arguments.forEach(argument -> argument.toLabel(entry)); - }); - - return ret; - } - - public static class RouterNamesGroup { - - private List beforeRouters; - - private List coreRouters; - - private List afterRouters; - - public List getBeforeRouters() { - return beforeRouters; - } - - public void setBeforeRouters(List beforeRouters) { - this.beforeRouters = beforeRouters; - } - - public List getCoreRouters() { - return coreRouters; - } - - public void setCoreRouters(List coreRouters) { - this.coreRouters = coreRouters; - } - - public List getAfterRouters() { - return afterRouters; - } - - public void setAfterRouters(List afterRouters) { - this.afterRouters = afterRouters; - } - } + public MetadataFailoverType getMetadataFailoverType() { + return metadataFailoverType; + } + + public void setMetadataFailoverType(MetadataFailoverType metadataFailoverType) { + this.metadataFailoverType = metadataFailoverType; + } + + public RuleBasedRouterFailoverType getRuleBasedRouterFailoverType() { + return ruleBasedRouterFailoverType; + } + + public void setRuleBasedRouterFailoverType(RuleBasedRouterFailoverType ruleBasedRouterFailoverType) { + this.ruleBasedRouterFailoverType = ruleBasedRouterFailoverType; + } + + public MetadataContainerGroup getMetadataContainerGroup() { + return metadataContainerGroup; + } + + public void setMetadataContainerGroup(MetadataContainerGroup metadataContainerGroup) { + this.metadataContainerGroup = metadataContainerGroup; + } + + private void buildRouterArgumentsBySourceService() { + if (CollectionUtils.isEmpty(routerArgument)) { + routerArgument = new HashMap<>(); + } + if (Objects.isNull(sourceService)) { + return; + } + Set arguments = routerArgument.computeIfAbsent("ruleRouter", k -> new HashSet<>()); + arguments.addAll(sourceService.getArguments()); + } + + @Deprecated + public void putRouterMetadata(String routerType, Map metadata) { + if (MapUtils.isEmpty(metadata)) { + return; + } + if (routerArgument == null) { + routerArgument = new HashMap<>(); + } + + Set arguments = new HashSet<>(); + metadata.forEach((key, value) -> arguments.add(RouteArgument.fromLabel(key, value))); + + routerArgument.put(routerType, arguments); + } + + @Deprecated + public void addRouterMetadata(String routerType, Map metadata) { + if (MapUtils.isEmpty(metadata)) { + return; + } + + if (routerArgument == null) { + routerArgument = new HashMap<>(); + } + + Set arguments = routerArgument.computeIfAbsent(routerType, k -> new HashSet<>()); + metadata.forEach((key, value) -> arguments.add(RouteArgument.fromLabel(key, value))); + } + + @Deprecated + public Map getRouterMetadata(String routerType) { + buildRouterArgumentsBySourceService(); + Set arguments = routerArgument.get(routerType); + if (CollectionUtils.isEmpty(arguments)) { + return Collections.emptyMap(); + } + + Map metadata = new HashMap<>(); + arguments.forEach(argument -> argument.toLabel(metadata)); + + return Collections.unmodifiableMap(metadata); + } + + @Deprecated + public Map> getRouterMetadata() { + buildRouterArgumentsBySourceService(); + + Map> ret = new HashMap<>(); + + routerArgument.forEach((routerType, arguments) -> { + Map entry = ret.computeIfAbsent(routerType, k -> new HashMap<>()); + arguments.forEach(argument -> argument.toLabel(entry)); + }); + + return ret; + } + + public static class RouterNamesGroup { + + private List beforeRouters; + + private List coreRouters; + + private List afterRouters; + + public List getBeforeRouters() { + return beforeRouters; + } + + public void setBeforeRouters(List beforeRouters) { + this.beforeRouters = beforeRouters; + } + + public List getCoreRouters() { + return coreRouters; + } + + public void setCoreRouters(List coreRouters) { + this.coreRouters = coreRouters; + } + + public List getAfterRouters() { + return afterRouters; + } + + public void setAfterRouters(List afterRouters) { + this.afterRouters = afterRouters; + } + } } diff --git a/polaris-router/polaris-router-client/src/main/java/com/tencent/polaris/router/client/flow/DefaultRouterFlow.java b/polaris-router/polaris-router-client/src/main/java/com/tencent/polaris/router/client/flow/DefaultRouterFlow.java index 844f22926..37b238580 100644 --- a/polaris-router/polaris-router-client/src/main/java/com/tencent/polaris/router/client/flow/DefaultRouterFlow.java +++ b/polaris-router/polaris-router-client/src/main/java/com/tencent/polaris/router/client/flow/DefaultRouterFlow.java @@ -25,13 +25,8 @@ import com.tencent.polaris.api.plugin.loadbalance.LoadBalancer; import com.tencent.polaris.api.plugin.route.RouteInfo; import com.tencent.polaris.api.plugin.route.ServiceRouter; -import com.tencent.polaris.api.pojo.DefaultServiceEventKeysProvider; -import com.tencent.polaris.api.pojo.Instance; -import com.tencent.polaris.api.pojo.ServiceEventKey; +import com.tencent.polaris.api.pojo.*; import com.tencent.polaris.api.pojo.ServiceEventKey.EventType; -import com.tencent.polaris.api.pojo.ServiceInstances; -import com.tencent.polaris.api.pojo.ServiceKey; -import com.tencent.polaris.api.pojo.SourceService; import com.tencent.polaris.api.utils.CollectionUtils; import com.tencent.polaris.api.utils.StringUtils; import com.tencent.polaris.client.api.SDKContext; @@ -45,10 +40,11 @@ import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest; import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest.RouterNamesGroup; import com.tencent.polaris.router.api.rpc.ProcessRoutersResponse; +import org.slf4j.Logger; + import java.util.HashSet; import java.util.List; import java.util.Set; -import org.slf4j.Logger; public class DefaultRouterFlow implements RouterFlow { @@ -103,6 +99,12 @@ public ProcessRoutersResponse processRouters(ProcessRoutersRequest request) { if (request.getMetadataFailoverType() != null) { routeInfo.setMetadataFailoverType(request.getMetadataFailoverType()); } + if (request.getRuleBasedRouterFailoverType() != null) { + routeInfo.setRuleBasedRouterFailoverType(request.getRuleBasedRouterFailoverType()); + } + if (request.getMetadataContainerGroup() != null) { + routeInfo.setMetadataContainerGroup(request.getMetadataContainerGroup()); + } //获取路由规则 DefaultFlowControlParam engineFlowControlParam = new DefaultFlowControlParam(); BaseFlow.buildFlowControlParam(request, config, engineFlowControlParam);