[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 allIPs = false;
|
||||||
|
|
||||||
|
private volatile boolean reachProtectionThreshold = false;
|
||||||
|
|
||||||
public ServiceInfo() {
|
public ServiceInfo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,6 +285,14 @@ public class ServiceInfo {
|
|||||||
return str1 == null ? str2 == null : str1.equals(str2);
|
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 EMPTY = "";
|
||||||
|
|
||||||
private static final String ALL_IPS = "000--00-ALL_IPS--00--000";
|
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.InstanceMetadata;
|
||||||
import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager;
|
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.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.InstancePublishInfo;
|
||||||
import com.alibaba.nacos.naming.core.v2.pojo.Service;
|
import com.alibaba.nacos.naming.core.v2.pojo.Service;
|
||||||
import com.alibaba.nacos.naming.core.v2.service.ClientOperationService;
|
import com.alibaba.nacos.naming.core.v2.service.ClientOperationService;
|
||||||
@ -168,7 +169,8 @@ public class InstanceOperatorClientImpl implements InstanceOperator {
|
|||||||
clientOperationService.subscribeService(service, subscriber, clientId);
|
clientOperationService.subscribeService(service, subscriber, clientId);
|
||||||
}
|
}
|
||||||
ServiceInfo serviceInfo = serviceStorage.getData(service);
|
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
|
// adapt for v1.x sdk
|
||||||
result.setName(NamingUtils.getGroupedName(result.getName(), result.getGroupName()));
|
result.setName(NamingUtils.getGroupedName(result.getName(), result.getGroupName()));
|
||||||
return result;
|
return result;
|
||||||
|
@ -193,16 +193,22 @@ public class InstanceOperatorServiceImpl implements InstanceOperator {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long total = 0;
|
||||||
Map<Boolean, List<com.alibaba.nacos.naming.core.Instance>> ipMap = new HashMap<>(2);
|
Map<Boolean, List<com.alibaba.nacos.naming.core.Instance>> ipMap = new HashMap<>(2);
|
||||||
ipMap.put(Boolean.TRUE, new ArrayList<>());
|
ipMap.put(Boolean.TRUE, new ArrayList<>());
|
||||||
ipMap.put(Boolean.FALSE, new ArrayList<>());
|
ipMap.put(Boolean.FALSE, new ArrayList<>());
|
||||||
|
|
||||||
for (com.alibaba.nacos.naming.core.Instance ip : srvedIPs) {
|
for (com.alibaba.nacos.naming.core.Instance ip : srvedIPs) {
|
||||||
|
// remove disabled instance:
|
||||||
|
if (!ip.isEnabled()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
ipMap.get(ip.isHealthy()).add(ip);
|
ipMap.get(ip.isHealthy()).add(ip);
|
||||||
|
total += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
double threshold = service.getProtectThreshold();
|
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);
|
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();
|
ipMap.get(Boolean.FALSE).clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Instance> hosts = new LinkedList<>();
|
List<Instance> hosts = new LinkedList<>(ipMap.get(Boolean.TRUE));
|
||||||
|
if (!healthOnly) {
|
||||||
for (Map.Entry<Boolean, List<com.alibaba.nacos.naming.core.Instance>> entry : ipMap.entrySet()) {
|
hosts.addAll(ipMap.get(Boolean.FALSE));
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result.setHosts(hosts);
|
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.auth.common.ActionTypes;
|
||||||
import com.alibaba.nacos.core.remote.RequestHandler;
|
import com.alibaba.nacos.core.remote.RequestHandler;
|
||||||
import com.alibaba.nacos.naming.core.v2.index.ServiceStorage;
|
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.core.v2.pojo.Service;
|
||||||
import com.alibaba.nacos.naming.utils.ServiceUtil;
|
import com.alibaba.nacos.naming.utils.ServiceUtil;
|
||||||
import com.alibaba.nacos.naming.web.NamingResourceParser;
|
import com.alibaba.nacos.naming.web.NamingResourceParser;
|
||||||
@ -40,8 +42,12 @@ public class ServiceQueryRequestHandler extends RequestHandler<ServiceQueryReque
|
|||||||
|
|
||||||
private final ServiceStorage serviceStorage;
|
private final ServiceStorage serviceStorage;
|
||||||
|
|
||||||
public ServiceQueryRequestHandler(ServiceStorage serviceStorage) {
|
private final NamingMetadataManager metadataManager;
|
||||||
|
|
||||||
|
public ServiceQueryRequestHandler(ServiceStorage serviceStorage,
|
||||||
|
NamingMetadataManager metadataManager) {
|
||||||
this.serviceStorage = serviceStorage;
|
this.serviceStorage = serviceStorage;
|
||||||
|
this.metadataManager = metadataManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -54,7 +60,8 @@ public class ServiceQueryRequestHandler extends RequestHandler<ServiceQueryReque
|
|||||||
String cluster = null == request.getCluster() ? "" : request.getCluster();
|
String cluster = null == request.getCluster() ? "" : request.getCluster();
|
||||||
boolean healthyOnly = request.isHealthyOnly();
|
boolean healthyOnly = request.isHealthyOnly();
|
||||||
ServiceInfo result = serviceStorage.getData(service);
|
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);
|
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.common.utils.JacksonUtils;
|
||||||
import com.alibaba.nacos.naming.core.Instance;
|
import com.alibaba.nacos.naming.core.Instance;
|
||||||
import com.alibaba.nacos.naming.core.Service;
|
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 com.fasterxml.jackson.databind.JsonNode;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
@ -238,6 +240,20 @@ public class ServiceUtil {
|
|||||||
*/
|
*/
|
||||||
public static ServiceInfo selectInstances(ServiceInfo serviceInfo, String cluster, boolean healthyOnly,
|
public static ServiceInfo selectInstances(ServiceInfo serviceInfo, String cluster, boolean healthyOnly,
|
||||||
boolean enableOnly) {
|
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();
|
ServiceInfo result = new ServiceInfo();
|
||||||
result.setName(serviceInfo.getName());
|
result.setName(serviceInfo.getName());
|
||||||
result.setGroupName(serviceInfo.getGroupName());
|
result.setGroupName(serviceInfo.getGroupName());
|
||||||
@ -246,12 +262,34 @@ public class ServiceUtil {
|
|||||||
result.setClusters(cluster);
|
result.setClusters(cluster);
|
||||||
Set<String> clusterSets = com.alibaba.nacos.common.utils.StringUtils.isNotBlank(cluster) ? new HashSet<>(
|
Set<String> clusterSets = com.alibaba.nacos.common.utils.StringUtils.isNotBlank(cluster) ? new HashSet<>(
|
||||||
Arrays.asList(cluster.split(","))) : new HashSet<>();
|
Arrays.asList(cluster.split(","))) : new HashSet<>();
|
||||||
List<com.alibaba.nacos.api.naming.pojo.Instance> filteredInstance = new LinkedList<>();
|
float threshold = 0F;
|
||||||
for (com.alibaba.nacos.api.naming.pojo.Instance each : serviceInfo.getHosts()) {
|
// TODO: filter ips using selector
|
||||||
if (checkCluster(clusterSets, each) && checkHealthy(healthyOnly, each) && checkEnabled(enableOnly, each)) {
|
if (serviceMetadata != null) {
|
||||||
filteredInstance.add(each);
|
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);
|
result.setHosts(filteredInstance);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -263,10 +301,6 @@ public class ServiceUtil {
|
|||||||
return clusterSets.contains(instance.getClusterName());
|
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) {
|
private static boolean checkEnabled(boolean enableOnly, com.alibaba.nacos.api.naming.pojo.Instance instance) {
|
||||||
return !enableOnly || instance.isEnabled();
|
return !enableOnly || instance.isEnabled();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user