From f69eb5f55933925cea8d124424cc3db2ccd89fdb Mon Sep 17 00:00:00 2001 From: provenceee <83857838+provenceee@users.noreply.github.com> Date: Tue, 19 Sep 2023 14:58:30 +0800 Subject: [PATCH] [1071] support affinity tag Service Instance Filter --- .../loadbalancer/ServiceInstanceFilter.java | 9 ++- .../nacos/NacosAdaptersAutoConfiguration.java | 12 ++++ .../NacosAffinityTagFilterAdapter.java | 28 +++++++++ .../MetadataNacosRegistrationCustomizer.java | 50 ++++++++++++++++ .../client/RouterClientAutoConfiguration.java | 10 ++++ .../AffinityTagFilterAdapter.java | 38 ++++++++++++ .../AffinityTagServiceInstanceFilter.java | 59 +++++++++++++++++++ .../CanaryServiceInstanceFilter.java | 2 +- .../ZoneAwareServiceInstanceFilter.java | 2 +- .../discovery/DiscoveryAutoConfiguration.java | 6 ++ .../ServiceCombAffinityTagFilterAdapter.java | 41 +++++++++++++ 11 files changed, 253 insertions(+), 4 deletions(-) create mode 100644 spring-cloud-huawei-nacos/src/main/java/com/huaweicloud/nacos/loadbalancer/NacosAffinityTagFilterAdapter.java create mode 100644 spring-cloud-huawei-nacos/src/main/java/com/huaweicloud/nacos/registry/MetadataNacosRegistrationCustomizer.java create mode 100644 spring-cloud-huawei-router/src/main/java/com/huaweicloud/router/client/loadbalancer/AffinityTagFilterAdapter.java create mode 100644 spring-cloud-huawei-router/src/main/java/com/huaweicloud/router/client/loadbalancer/AffinityTagServiceInstanceFilter.java create mode 100644 spring-cloud-huawei-service-engine/service-engine-discovery/src/main/java/com/huaweicloud/servicecomb/discovery/loadbalancer/ServiceCombAffinityTagFilterAdapter.java diff --git a/spring-cloud-huawei-governance/src/main/java/com/huaweicloud/governance/adapters/loadbalancer/ServiceInstanceFilter.java b/spring-cloud-huawei-governance/src/main/java/com/huaweicloud/governance/adapters/loadbalancer/ServiceInstanceFilter.java index d9d512a10..eb04d04bd 100644 --- a/spring-cloud-huawei-governance/src/main/java/com/huaweicloud/governance/adapters/loadbalancer/ServiceInstanceFilter.java +++ b/spring-cloud-huawei-governance/src/main/java/com/huaweicloud/governance/adapters/loadbalancer/ServiceInstanceFilter.java @@ -17,14 +17,19 @@ package com.huaweicloud.governance.adapters.loadbalancer; +import java.util.List; + import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.Request; import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; import org.springframework.core.Ordered; -import java.util.List; - public interface ServiceInstanceFilter extends Ordered { + int ZONE_AWARE_ORDER = -2; + + int CANARY_ORDER = -1; + + int AFFINITY_TAG_ORDER = 0; /** * filter service instance diff --git a/spring-cloud-huawei-nacos/src/main/java/com/huaweicloud/nacos/NacosAdaptersAutoConfiguration.java b/spring-cloud-huawei-nacos/src/main/java/com/huaweicloud/nacos/NacosAdaptersAutoConfiguration.java index 96531269e..a4c789961 100644 --- a/spring-cloud-huawei-nacos/src/main/java/com/huaweicloud/nacos/NacosAdaptersAutoConfiguration.java +++ b/spring-cloud-huawei-nacos/src/main/java/com/huaweicloud/nacos/NacosAdaptersAutoConfiguration.java @@ -25,6 +25,8 @@ import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled; import com.huaweicloud.common.configration.dynamic.GovernanceProperties; import com.huaweicloud.nacos.authentication.NacosAuthenticationAdapter; +import com.huaweicloud.nacos.registry.MetadataNacosRegistrationCustomizer; +import com.huaweicloud.nacos.loadbalancer.NacosAffinityTagFilterAdapter; import com.huaweicloud.nacos.loadbalancer.NacosCanaryFilterAdapter; import com.huaweicloud.nacos.loadbalancer.NacosZoneAwareFilterAdapter; @@ -47,4 +49,14 @@ public NacosCanaryFilterAdapter nacosCanaryFilterAdapter() { public NacosZoneAwareFilterAdapter nacosZoneAwareFilterAdapter() { return new NacosZoneAwareFilterAdapter(); } + + @Bean + public NacosAffinityTagFilterAdapter nacosAffinityTagFilterAdapter() { + return new NacosAffinityTagFilterAdapter(); + } + + @Bean + public MetadataNacosRegistrationCustomizer metadataNacosRegistrationCustomizer() { + return new MetadataNacosRegistrationCustomizer(); + } } diff --git a/spring-cloud-huawei-nacos/src/main/java/com/huaweicloud/nacos/loadbalancer/NacosAffinityTagFilterAdapter.java b/spring-cloud-huawei-nacos/src/main/java/com/huaweicloud/nacos/loadbalancer/NacosAffinityTagFilterAdapter.java new file mode 100644 index 000000000..1a287300e --- /dev/null +++ b/spring-cloud-huawei-nacos/src/main/java/com/huaweicloud/nacos/loadbalancer/NacosAffinityTagFilterAdapter.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.huaweicloud.nacos.loadbalancer; + +import com.huaweicloud.router.client.loadbalancer.AffinityTagFilterAdapter; + +/** + * nacos affinity tag adapter + * + * @author provenceee + * @since 2023-09-19 + */ +public class NacosAffinityTagFilterAdapter implements AffinityTagFilterAdapter { +} diff --git a/spring-cloud-huawei-nacos/src/main/java/com/huaweicloud/nacos/registry/MetadataNacosRegistrationCustomizer.java b/spring-cloud-huawei-nacos/src/main/java/com/huaweicloud/nacos/registry/MetadataNacosRegistrationCustomizer.java new file mode 100644 index 000000000..1f38b3f1e --- /dev/null +++ b/spring-cloud-huawei-nacos/src/main/java/com/huaweicloud/nacos/registry/MetadataNacosRegistrationCustomizer.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.huaweicloud.nacos.registry; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.commons.configuration.EnvironmentConfiguration; + +import com.alibaba.cloud.nacos.registry.NacosRegistration; +import com.alibaba.cloud.nacos.registry.NacosRegistrationCustomizer; + +/** + * add nacos metadata + * + * @author provenceee + * @since 2023-09-19 + */ +public class MetadataNacosRegistrationCustomizer implements NacosRegistrationCustomizer { + private static final String INSTANCE_PROPS = "SERVICECOMB_INSTANCE_PROPS"; + + @Override + public void customize(NacosRegistration registration) { + EnvironmentConfiguration envConfig = new EnvironmentConfiguration(); + String[] instancePropArray = envConfig.getStringArray(INSTANCE_PROPS); + if (instancePropArray.length != 0) { + registration.getMetadata().putAll(parseProps(instancePropArray)); + } + } + + private Map parseProps(String... value) { + return Arrays.stream(value).map(v -> v.split(":")) + .filter(v -> v.length == 2) + .collect(Collectors.toMap(v -> v[0], v -> v[1])); + } +} diff --git a/spring-cloud-huawei-router/src/main/java/com/huaweicloud/router/client/RouterClientAutoConfiguration.java b/spring-cloud-huawei-router/src/main/java/com/huaweicloud/router/client/RouterClientAutoConfiguration.java index 9359e9d68..8122ff3d2 100644 --- a/spring-cloud-huawei-router/src/main/java/com/huaweicloud/router/client/RouterClientAutoConfiguration.java +++ b/spring-cloud-huawei-router/src/main/java/com/huaweicloud/router/client/RouterClientAutoConfiguration.java @@ -28,6 +28,8 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; +import com.huaweicloud.router.client.loadbalancer.AffinityTagFilterAdapter; +import com.huaweicloud.router.client.loadbalancer.AffinityTagServiceInstanceFilter; import com.huaweicloud.router.client.loadbalancer.CanaryFilterAdapter; import com.huaweicloud.router.client.loadbalancer.CanaryServiceInstanceFilter; import com.huaweicloud.router.client.loadbalancer.SpringCloudRouterDistributor; @@ -59,4 +61,12 @@ public ZoneAwareServiceInstanceFilter zoneAwareServiceInstanceFilter(Registratio ZoneAwareFilterAdapter adapter) { return new ZoneAwareServiceInstanceFilter(registration, adapter); } + + @Bean + @ConditionalOnMissingBean(AffinityTagServiceInstanceFilter.class) + @ConditionalOnProperty(value = "spring.cloud.servicecomb.discovery.enabledAffinityTag", havingValue = "true") + public AffinityTagServiceInstanceFilter affinityTagServiceInstanceFilter(Registration registration, + AffinityTagFilterAdapter adapter) { + return new AffinityTagServiceInstanceFilter(registration, adapter); + } } diff --git a/spring-cloud-huawei-router/src/main/java/com/huaweicloud/router/client/loadbalancer/AffinityTagFilterAdapter.java b/spring-cloud-huawei-router/src/main/java/com/huaweicloud/router/client/loadbalancer/AffinityTagFilterAdapter.java new file mode 100644 index 000000000..a8e75477a --- /dev/null +++ b/spring-cloud-huawei-router/src/main/java/com/huaweicloud/router/client/loadbalancer/AffinityTagFilterAdapter.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.huaweicloud.router.client.loadbalancer; + +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.serviceregistry.Registration; + +/** + * affinity tag adapter + * + * @author provenceee + * @since 2023-09-19 + */ +public interface AffinityTagFilterAdapter { + String AFFINITY_TAG = "affinity-tag"; + + default String getAffinityTag(ServiceInstance serviceInstance) { + return serviceInstance.getMetadata().get(AFFINITY_TAG); + } + + default String getAffinityTag(Registration registration) { + return registration.getMetadata().get(AFFINITY_TAG); + } +} diff --git a/spring-cloud-huawei-router/src/main/java/com/huaweicloud/router/client/loadbalancer/AffinityTagServiceInstanceFilter.java b/spring-cloud-huawei-router/src/main/java/com/huaweicloud/router/client/loadbalancer/AffinityTagServiceInstanceFilter.java new file mode 100644 index 000000000..91551347d --- /dev/null +++ b/spring-cloud-huawei-router/src/main/java/com/huaweicloud/router/client/loadbalancer/AffinityTagServiceInstanceFilter.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.huaweicloud.router.client.loadbalancer; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.Request; +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; +import org.springframework.util.CollectionUtils; + +import com.huaweicloud.governance.adapters.loadbalancer.ServiceInstanceFilter; + +/** + * affinity tag instance filter + * @author provenceee + * @since 2023-09-19 + */ +public class AffinityTagServiceInstanceFilter implements ServiceInstanceFilter { + private final Registration registration; + + private final AffinityTagFilterAdapter adapter; + + public AffinityTagServiceInstanceFilter(Registration registration, AffinityTagFilterAdapter adapter) { + this.registration = registration; + this.adapter = adapter; + } + + @Override + public List filter(ServiceInstanceListSupplier supplier, List instances, + Request request) { + String affinityTag = adapter.getAffinityTag(registration); + List serviceInstances = instances.stream().filter( + instance -> Objects.equals(affinityTag, adapter.getAffinityTag(instance))).collect(Collectors.toList()); + return CollectionUtils.isEmpty(serviceInstances) ? instances : serviceInstances; + } + + @Override + public int getOrder() { + return AFFINITY_TAG_ORDER; + } +} diff --git a/spring-cloud-huawei-router/src/main/java/com/huaweicloud/router/client/loadbalancer/CanaryServiceInstanceFilter.java b/spring-cloud-huawei-router/src/main/java/com/huaweicloud/router/client/loadbalancer/CanaryServiceInstanceFilter.java index a466d1e17..acc9ff1c2 100644 --- a/spring-cloud-huawei-router/src/main/java/com/huaweicloud/router/client/loadbalancer/CanaryServiceInstanceFilter.java +++ b/spring-cloud-huawei-router/src/main/java/com/huaweicloud/router/client/loadbalancer/CanaryServiceInstanceFilter.java @@ -94,6 +94,6 @@ public List filter(ServiceInstanceListSupplier supplier, List filter(ServiceInstanceListSupplier supplier, List zoneAwareDiscoveryFilter(List instances) { diff --git a/spring-cloud-huawei-service-engine/service-engine-discovery/src/main/java/com/huaweicloud/servicecomb/discovery/DiscoveryAutoConfiguration.java b/spring-cloud-huawei-service-engine/service-engine-discovery/src/main/java/com/huaweicloud/servicecomb/discovery/DiscoveryAutoConfiguration.java index 874f99e53..6568540db 100644 --- a/spring-cloud-huawei-service-engine/service-engine-discovery/src/main/java/com/huaweicloud/servicecomb/discovery/DiscoveryAutoConfiguration.java +++ b/spring-cloud-huawei-service-engine/service-engine-discovery/src/main/java/com/huaweicloud/servicecomb/discovery/DiscoveryAutoConfiguration.java @@ -34,6 +34,7 @@ import com.huaweicloud.service.engine.common.disovery.ServiceCenterUtils; import com.huaweicloud.servicecomb.discovery.authentication.ServiceCombAuthenticationAdapter; import com.huaweicloud.servicecomb.discovery.discovery.DiscoveryProperties; +import com.huaweicloud.servicecomb.discovery.loadbalancer.ServiceCombAffinityTagFilterAdapter; import com.huaweicloud.servicecomb.discovery.loadbalancer.ServiceCombCanaryFilterAdapter; import com.huaweicloud.servicecomb.discovery.loadbalancer.ServiceCombZoneAwareFilterAdapter; @@ -73,4 +74,9 @@ public ServiceCombCanaryFilterAdapter serviceCombCanaryFilterAdapter() { public ServiceCombZoneAwareFilterAdapter serviceCombZoneAwareFilterAdapter() { return new ServiceCombZoneAwareFilterAdapter(); } + + @Bean + public ServiceCombAffinityTagFilterAdapter serviceCombAffinityTagFilterAdapter() { + return new ServiceCombAffinityTagFilterAdapter(); + } } diff --git a/spring-cloud-huawei-service-engine/service-engine-discovery/src/main/java/com/huaweicloud/servicecomb/discovery/loadbalancer/ServiceCombAffinityTagFilterAdapter.java b/spring-cloud-huawei-service-engine/service-engine-discovery/src/main/java/com/huaweicloud/servicecomb/discovery/loadbalancer/ServiceCombAffinityTagFilterAdapter.java new file mode 100644 index 000000000..0b263a11c --- /dev/null +++ b/spring-cloud-huawei-service-engine/service-engine-discovery/src/main/java/com/huaweicloud/servicecomb/discovery/loadbalancer/ServiceCombAffinityTagFilterAdapter.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.huaweicloud.servicecomb.discovery.loadbalancer; + +import org.apache.servicecomb.service.center.client.model.MicroserviceInstance; +import org.springframework.cloud.client.serviceregistry.Registration; + +import com.huaweicloud.router.client.loadbalancer.AffinityTagFilterAdapter; +import com.huaweicloud.servicecomb.discovery.registry.ServiceCombRegistration; + +/** + * serviceComb affinity tag adapter + * + * @author provenceee + * @since 2023-09-19 + */ +public class ServiceCombAffinityTagFilterAdapter implements AffinityTagFilterAdapter { + @Override + public String getAffinityTag(Registration registration) { + ServiceCombRegistration serviceCombRegistration = (ServiceCombRegistration) registration; + MicroserviceInstance microserviceInstance = serviceCombRegistration.getMicroserviceInstance(); + if (microserviceInstance.getProperties() == null) { + return null; + } + return microserviceInstance.getProperties().get(AFFINITY_TAG); + } +}