[ISSUE #5054] Support naming instance list with healthy protection using service.protectionThreshold. (#5055)
* [ISSUE #5054] Support naming instance list with healthy protection using service.protectionThreshold. * [ISSUE #5054] Fix code formatting.
This commit is contained in:
parent
0c35f056b0
commit
5c8559b8ba
@ -57,6 +57,8 @@ public class ServiceInfo {
|
||||
|
||||
private volatile boolean allIPs = false;
|
||||
|
||||
private volatile boolean reachProtectionThreshold = false;
|
||||
|
||||
public ServiceInfo() {
|
||||
}
|
||||
|
||||
@ -283,6 +285,14 @@ public class ServiceInfo {
|
||||
return str1 == null ? str2 == null : str1.equals(str2);
|
||||
}
|
||||
|
||||
public boolean isReachProtectionThreshold() {
|
||||
return reachProtectionThreshold;
|
||||
}
|
||||
|
||||
public void setReachProtectionThreshold(boolean reachProtectionThreshold) {
|
||||
this.reachProtectionThreshold = reachProtectionThreshold;
|
||||
}
|
||||
|
||||
private static final String EMPTY = "";
|
||||
|
||||
private static final String ALL_IPS = "000--00-ALL_IPS--00--000";
|
||||
|
@ -33,6 +33,7 @@ import com.alibaba.nacos.naming.core.v2.index.ServiceStorage;
|
||||
import com.alibaba.nacos.naming.core.v2.metadata.InstanceMetadata;
|
||||
import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager;
|
||||
import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataOperateService;
|
||||
import com.alibaba.nacos.naming.core.v2.metadata.ServiceMetadata;
|
||||
import com.alibaba.nacos.naming.core.v2.pojo.InstancePublishInfo;
|
||||
import com.alibaba.nacos.naming.core.v2.pojo.Service;
|
||||
import com.alibaba.nacos.naming.core.v2.service.ClientOperationService;
|
||||
@ -168,7 +169,8 @@ public class InstanceOperatorClientImpl implements InstanceOperator {
|
||||
clientOperationService.subscribeService(service, subscriber, clientId);
|
||||
}
|
||||
ServiceInfo serviceInfo = serviceStorage.getData(service);
|
||||
ServiceInfo result = ServiceUtil.selectInstances(serviceInfo, cluster, healthOnly, true);
|
||||
ServiceMetadata serviceMetadata = metadataManager.getServiceMetadata(service).orElse(null);
|
||||
ServiceInfo result = ServiceUtil.selectInstances(serviceInfo, serviceMetadata, cluster, healthOnly, true);
|
||||
// adapt for v1.x sdk
|
||||
result.setName(NamingUtils.getGroupedName(result.getName(), result.getGroupName()));
|
||||
return result;
|
||||
|
@ -193,16 +193,22 @@ public class InstanceOperatorServiceImpl implements InstanceOperator {
|
||||
return result;
|
||||
}
|
||||
|
||||
long total = 0;
|
||||
Map<Boolean, List<com.alibaba.nacos.naming.core.Instance>> ipMap = new HashMap<>(2);
|
||||
ipMap.put(Boolean.TRUE, new ArrayList<>());
|
||||
ipMap.put(Boolean.FALSE, new ArrayList<>());
|
||||
|
||||
for (com.alibaba.nacos.naming.core.Instance ip : srvedIPs) {
|
||||
// remove disabled instance:
|
||||
if (!ip.isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
ipMap.get(ip.isHealthy()).add(ip);
|
||||
total += 1;
|
||||
}
|
||||
|
||||
double threshold = service.getProtectThreshold();
|
||||
if ((float) ipMap.get(Boolean.TRUE).size() / srvedIPs.size() <= threshold) {
|
||||
if ((float) ipMap.get(Boolean.TRUE).size() / total <= threshold) {
|
||||
|
||||
Loggers.SRV_LOG.warn("protect threshold reached, return all ips, service: {}", serviceName);
|
||||
|
||||
@ -210,23 +216,9 @@ public class InstanceOperatorServiceImpl implements InstanceOperator {
|
||||
ipMap.get(Boolean.FALSE).clear();
|
||||
}
|
||||
|
||||
List<Instance> hosts = new LinkedList<>();
|
||||
|
||||
for (Map.Entry<Boolean, List<com.alibaba.nacos.naming.core.Instance>> entry : ipMap.entrySet()) {
|
||||
List<com.alibaba.nacos.naming.core.Instance> ips = entry.getValue();
|
||||
|
||||
if (healthOnly && !entry.getKey()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (com.alibaba.nacos.naming.core.Instance instance : ips) {
|
||||
|
||||
// remove disabled instance:
|
||||
if (!instance.isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
hosts.add(instance);
|
||||
}
|
||||
List<Instance> hosts = new LinkedList<>(ipMap.get(Boolean.TRUE));
|
||||
if (!healthOnly) {
|
||||
hosts.addAll(ipMap.get(Boolean.FALSE));
|
||||
}
|
||||
|
||||
result.setHosts(hosts);
|
||||
|
@ -25,6 +25,8 @@ import com.alibaba.nacos.auth.annotation.Secured;
|
||||
import com.alibaba.nacos.auth.common.ActionTypes;
|
||||
import com.alibaba.nacos.core.remote.RequestHandler;
|
||||
import com.alibaba.nacos.naming.core.v2.index.ServiceStorage;
|
||||
import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager;
|
||||
import com.alibaba.nacos.naming.core.v2.metadata.ServiceMetadata;
|
||||
import com.alibaba.nacos.naming.core.v2.pojo.Service;
|
||||
import com.alibaba.nacos.naming.utils.ServiceUtil;
|
||||
import com.alibaba.nacos.naming.web.NamingResourceParser;
|
||||
@ -40,8 +42,12 @@ public class ServiceQueryRequestHandler extends RequestHandler<ServiceQueryReque
|
||||
|
||||
private final ServiceStorage serviceStorage;
|
||||
|
||||
public ServiceQueryRequestHandler(ServiceStorage serviceStorage) {
|
||||
private final NamingMetadataManager metadataManager;
|
||||
|
||||
public ServiceQueryRequestHandler(ServiceStorage serviceStorage,
|
||||
NamingMetadataManager metadataManager) {
|
||||
this.serviceStorage = serviceStorage;
|
||||
this.metadataManager = metadataManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -54,7 +60,8 @@ public class ServiceQueryRequestHandler extends RequestHandler<ServiceQueryReque
|
||||
String cluster = null == request.getCluster() ? "" : request.getCluster();
|
||||
boolean healthyOnly = request.isHealthyOnly();
|
||||
ServiceInfo result = serviceStorage.getData(service);
|
||||
result = ServiceUtil.selectInstances(result, cluster, healthyOnly, true);
|
||||
ServiceMetadata serviceMetadata = metadataManager.getServiceMetadata(service).orElse(null);
|
||||
result = ServiceUtil.selectInstances(result, serviceMetadata, cluster, healthyOnly, true);
|
||||
return QueryServiceResponse.buildSuccessResponse(result);
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ import com.alibaba.nacos.api.selector.SelectorType;
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import com.alibaba.nacos.naming.core.Instance;
|
||||
import com.alibaba.nacos.naming.core.Service;
|
||||
import com.alibaba.nacos.naming.core.v2.metadata.ServiceMetadata;
|
||||
import com.alibaba.nacos.naming.misc.Loggers;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@ -238,6 +240,20 @@ public class ServiceUtil {
|
||||
*/
|
||||
public static ServiceInfo selectInstances(ServiceInfo serviceInfo, String cluster, boolean healthyOnly,
|
||||
boolean enableOnly) {
|
||||
return selectInstances(serviceInfo, null, cluster, healthyOnly, enableOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select instance of service info.
|
||||
*
|
||||
* @param serviceInfo original service info
|
||||
* @param cluster cluster of instances
|
||||
* @param healthyOnly whether only select instance which healthy
|
||||
* @param enableOnly whether only select instance which enabled
|
||||
* @return new service info
|
||||
*/
|
||||
public static ServiceInfo selectInstances(ServiceInfo serviceInfo, ServiceMetadata serviceMetadata, String cluster,
|
||||
boolean healthyOnly, boolean enableOnly) {
|
||||
ServiceInfo result = new ServiceInfo();
|
||||
result.setName(serviceInfo.getName());
|
||||
result.setGroupName(serviceInfo.getGroupName());
|
||||
@ -246,12 +262,34 @@ public class ServiceUtil {
|
||||
result.setClusters(cluster);
|
||||
Set<String> clusterSets = com.alibaba.nacos.common.utils.StringUtils.isNotBlank(cluster) ? new HashSet<>(
|
||||
Arrays.asList(cluster.split(","))) : new HashSet<>();
|
||||
List<com.alibaba.nacos.api.naming.pojo.Instance> filteredInstance = new LinkedList<>();
|
||||
for (com.alibaba.nacos.api.naming.pojo.Instance each : serviceInfo.getHosts()) {
|
||||
if (checkCluster(clusterSets, each) && checkHealthy(healthyOnly, each) && checkEnabled(enableOnly, each)) {
|
||||
filteredInstance.add(each);
|
||||
float threshold = 0F;
|
||||
// TODO: filter ips using selector
|
||||
if (serviceMetadata != null) {
|
||||
threshold = serviceMetadata.getProtectThreshold();
|
||||
}
|
||||
if (threshold < 0) {
|
||||
threshold = 0F;
|
||||
}
|
||||
long total = 0L;
|
||||
Map<Boolean, List<com.alibaba.nacos.api.naming.pojo.Instance>> ipMap = new HashMap<>(2);
|
||||
ipMap.put(Boolean.TRUE, new LinkedList<>());
|
||||
ipMap.put(Boolean.FALSE, new LinkedList<>());
|
||||
for (com.alibaba.nacos.api.naming.pojo.Instance ip : serviceInfo.getHosts()) {
|
||||
if (checkCluster(clusterSets, ip) && checkEnabled(enableOnly, ip)) {
|
||||
ipMap.get(ip.isHealthy()).add(ip);
|
||||
total += 1;
|
||||
}
|
||||
}
|
||||
if ((float) ipMap.get(Boolean.TRUE).size() / total <= threshold) {
|
||||
Loggers.SRV_LOG.warn("protect threshold reached, return all ips, service: {}", serviceInfo.getName());
|
||||
serviceInfo.setReachProtectionThreshold(true);
|
||||
ipMap.get(Boolean.TRUE).addAll(ipMap.get(Boolean.FALSE));
|
||||
ipMap.get(Boolean.FALSE).clear();
|
||||
}
|
||||
List<com.alibaba.nacos.api.naming.pojo.Instance> filteredInstance = ipMap.get(Boolean.TRUE);
|
||||
if (!healthyOnly) {
|
||||
filteredInstance.addAll(ipMap.get(Boolean.FALSE));
|
||||
}
|
||||
result.setHosts(filteredInstance);
|
||||
return result;
|
||||
}
|
||||
@ -263,10 +301,6 @@ public class ServiceUtil {
|
||||
return clusterSets.contains(instance.getClusterName());
|
||||
}
|
||||
|
||||
private static boolean checkHealthy(boolean healthyOnly, com.alibaba.nacos.api.naming.pojo.Instance instance) {
|
||||
return !healthyOnly || instance.isHealthy();
|
||||
}
|
||||
|
||||
private static boolean checkEnabled(boolean enableOnly, com.alibaba.nacos.api.naming.pojo.Instance instance) {
|
||||
return !enableOnly || instance.isEnabled();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user