diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryProperties.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryProperties.java index 0dadefc4..fd35cb47 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryProperties.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryProperties.java @@ -16,10 +16,27 @@ package org.springframework.cloud.alibaba.nacos; -import com.alibaba.nacos.api.NacosFactory; -import com.alibaba.nacos.api.naming.NamingService; -import com.alibaba.nacos.api.naming.PreservedMetadataKeys; -import com.alibaba.nacos.client.naming.utils.UtilAndComs; +import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY; +import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME; +import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT; +import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT_PORT; +import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE; +import static com.alibaba.nacos.api.PropertyKeyConst.NAMING_LOAD_CACHE_AT_START; +import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY; +import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; + +import javax.annotation.PostConstruct; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -28,14 +45,13 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.cloud.commons.util.InetUtils; import org.springframework.core.env.Environment; import org.springframework.util.StringUtils; -import javax.annotation.PostConstruct; -import java.net.Inet4Address; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.SocketException; -import java.util.*; -import static com.alibaba.nacos.api.PropertyKeyConst.*; +import com.alibaba.nacos.api.NacosFactory; +import com.alibaba.nacos.api.naming.NamingMaintainFactory; +import com.alibaba.nacos.api.naming.NamingMaintainService; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.PreservedMetadataKeys; +import com.alibaba.nacos.client.naming.utils.UtilAndComs; /** * @author dungu.zpf @@ -147,6 +163,8 @@ public class NacosDiscoveryProperties { private NamingService namingService; + private NamingMaintainService namingMaintainService; + @PostConstruct public void init() throws SocketException { @@ -389,6 +407,34 @@ public class NacosDiscoveryProperties { return namingService; } + try { + namingService = NacosFactory.createNamingService(getNacosProperties()); + } + catch (Exception e) { + log.error("create naming service error!properties={},e=,", this, e); + return null; + } + return namingService; + } + + public NamingMaintainService namingMaintainServiceInstance() { + + if (null != namingMaintainService) { + return namingMaintainService; + } + + try { + namingMaintainService = NamingMaintainFactory + .createMaintainService(getNacosProperties()); + } + catch (Exception e) { + log.error("create naming service error!properties={},e=,", this, e); + return null; + } + return namingMaintainService; + } + + private Properties getNacosProperties() { Properties properties = new Properties(); properties.put(SERVER_ADDR, serverAddr); properties.put(NAMESPACE, namespace); @@ -407,15 +453,7 @@ public class NacosDiscoveryProperties { properties.put(SECRET_KEY, secretKey); properties.put(CLUSTER_NAME, clusterName); properties.put(NAMING_LOAD_CACHE_AT_START, namingLoadCacheAtStart); - - try { - namingService = NacosFactory.createNamingService(properties); - } - catch (Exception e) { - log.error("create naming service error!properties={},e=,", this, e); - return null; - } - return namingService; + return properties; } } diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosServiceRegistry.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosServiceRegistry.java index 6c362af6..3e23fefc 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosServiceRegistry.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosServiceRegistry.java @@ -16,8 +16,8 @@ package org.springframework.cloud.alibaba.nacos.registry; -import com.alibaba.nacos.api.naming.NamingService; -import com.alibaba.nacos.api.naming.pojo.Instance; +import java.util.List; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties; @@ -25,6 +25,9 @@ import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import org.springframework.util.StringUtils; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.pojo.Instance; + /** * @author xiaojing * @author Mercy @@ -52,12 +55,7 @@ public class NacosServiceRegistry implements ServiceRegistry { String serviceId = registration.getServiceId(); - Instance instance = new Instance(); - instance.setIp(registration.getHost()); - instance.setPort(registration.getPort()); - instance.setWeight(nacosDiscoveryProperties.getWeight()); - instance.setClusterName(nacosDiscoveryProperties.getClusterName()); - instance.setMetadata(registration.getMetadata()); + Instance instance = getNacosInstanceFromRegistration(registration); try { namingService.registerInstance(serviceId, instance); @@ -102,13 +100,60 @@ public class NacosServiceRegistry implements ServiceRegistry { @Override public void setStatus(Registration registration, String status) { - // nacos doesn't support set status of a particular registration. + + if (!status.equalsIgnoreCase("UP") && !status.equalsIgnoreCase("DOWN")) { + log.warn("can't support status {},please choose UP or DOWN", status); + return; + } + + String serviceId = registration.getServiceId(); + + Instance instance = getNacosInstanceFromRegistration(registration); + + if (status.equalsIgnoreCase("DOWN")) { + instance.setEnabled(false); + } + else { + instance.setEnabled(true); + } + + try { + nacosDiscoveryProperties.namingMaintainServiceInstance() + .updateInstance(serviceId, instance); + } + catch (Exception e) { + throw new RuntimeException("update nacos instance status fail", e); + } + } @Override - public T getStatus(Registration registration) { - // nacos doesn't support query status of a particular registration. + public Object getStatus(Registration registration) { + + String serviceName = registration.getServiceId(); + try { + List instances = nacosDiscoveryProperties.namingServiceInstance() + .getAllInstances(serviceName); + for (Instance instance : instances) { + if (instance.getIp().equalsIgnoreCase(nacosDiscoveryProperties.getIp()) + && instance.getPort() == nacosDiscoveryProperties.getPort()) + return instance.isEnabled() ? "UP" : "DOWN"; + } + } + catch (Exception e) { + log.error("get all instance of {} error,", serviceName, e); + } return null; } + private Instance getNacosInstanceFromRegistration(Registration registration) { + Instance instance = new Instance(); + instance.setIp(registration.getHost()); + instance.setPort(registration.getPort()); + instance.setWeight(nacosDiscoveryProperties.getWeight()); + instance.setClusterName(nacosDiscoveryProperties.getClusterName()); + instance.setMetadata(registration.getMetadata()); + return instance; + } + } diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/ExtendBalancer.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/ExtendBalancer.java new file mode 100644 index 00000000..d581673c --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/ExtendBalancer.java @@ -0,0 +1,21 @@ +package org.springframework.cloud.alibaba.nacos.ribbon; + +import java.util.List; + +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.client.naming.core.Balancer; + +/** + * @author itmuch.com + */ +public class ExtendBalancer extends Balancer { + /** + * 根据权重,随机选择实例 + * + * @param instances 实例列表 + * @return 选择的实例 + */ + public static Instance getHostByRandomWeight2(List instances) { + return getHostByRandomWeight(instances); + } +} diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/NacosRule.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/NacosRule.java new file mode 100644 index 00000000..c388a4ff --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/NacosRule.java @@ -0,0 +1,80 @@ +package org.springframework.cloud.alibaba.nacos.ribbon; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties; +import org.springframework.util.CollectionUtils; + +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.pojo.Instance; + +import com.netflix.client.config.IClientConfig; +import com.netflix.loadbalancer.AbstractLoadBalancerRule; +import com.netflix.loadbalancer.DynamicServerListLoadBalancer; +import com.netflix.loadbalancer.Server; + +/** + * Supports preferentially calling the ribbon load balancing rules of the same cluster + * instance. + * + * @author itmuch.com + */ +public class NacosRule extends AbstractLoadBalancerRule { + private static final Logger LOGGER = LoggerFactory.getLogger(NacosRule.class); + + @Autowired + private NacosDiscoveryProperties nacosDiscoveryProperties; + + @Override + public Server choose(Object key) { + try { + String clusterName = this.nacosDiscoveryProperties.getClusterName(); + DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer(); + String name = loadBalancer.getName(); + + NamingService namingService = this.nacosDiscoveryProperties + .namingServiceInstance(); + List instances = namingService.selectInstances(name, true); + if (CollectionUtils.isEmpty(instances)) { + LOGGER.warn("no instance in service {}", name); + return null; + } + + List instancesToChoose = instances; + if (StringUtils.isNotBlank(clusterName)) { + List sameClusterInstances = new ArrayList<>(); + for (Instance instance : instances) { + if (Objects.equals(clusterName, instance.getClusterName())) { + sameClusterInstances.add(instance); + } + } + if (!CollectionUtils.isEmpty(sameClusterInstances)) { + instancesToChoose = sameClusterInstances; + } + else { + LOGGER.warn( + "A cross-cluster call occurs,name = {}, clusterName = {}, instance = {}", + name, clusterName, instances); + } + } + + Instance instance = ExtendBalancer.getHostByRandomWeight2(instancesToChoose); + + return new NacosServer(instance); + } + catch (Exception e) { + LOGGER.warn("NacosRule error", e); + return null; + } + } + + @Override + public void initWithNiwsConfig(IClientConfig iClientConfig) { + } +}