作者:幼俐佩其392 | 来源:互联网 | 2023-08-17 18:13
一、服务实例过滤器ServerListFilter
服务实例过滤器(ServerListFilter)为负载均衡器(Loadbalancer)提供从服务实例列表(ServerList)获取的服务实例过滤出符合要求的服务实例。
负载均衡器(Loadbalancer)通过服务实例列表(ServerList)从注册中心(register)或者配置文件(yaml或properties)上读取全部服务实例(server),然后以服务实例过滤器(ServerListFilter)的过滤方式进行筛选留下满足条件的服务实例,进而借助负载均衡策略(IRule)选择出一个合适的服务实例。
二、ServerListFilter实现类
![](https://img8.php1.cn/3cdc5/18a53/a6e/e29710d9d8545383.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21vYWt1bg==,size_16,color_FFFFFF,t_70)
ZoneAffinityServerListFilter 区区域相关性筛选服务实例列表过滤器
ZonePreferenceServerListFilter 首选本地区域服务实例列表过滤器
ServerListSubsetFilter 服务实例数限制为所有服务实例的子集 筛选过滤器
三、具体代码实现
(1)ZoneAffinityServerListFilter
public class ZoneAffinityServerListFilter extendsAbstractServerListFilter implements IClientConfigAware {private volatile boolean zoneAffinity = DefaultClientConfigImpl.DEFAULT_ENABLE_ZONE_AFFINITY;private volatile boolean zoneExclusive = DefaultClientConfigImpl.DEFAULT_ENABLE_ZONE_EXCLUSIVITY;private DynamicDoubleProperty activeReqeustsPerServerThreshold;private DynamicDoubleProperty blackOutServerPercentageThreshold;private DynamicIntProperty availableServersThreshold;private Counter overrideCounter;private ZoneAffinityPredicate zoneAffinityPredicate = new ZoneAffinityPredicate();private static Logger logger = LoggerFactory.getLogger(ZoneAffinityServerListFilter.class);String zone;public ZoneAffinityServerListFilter() { }public ZoneAffinityServerListFilter(IClientConfig niwsClientConfig) {initWithNiwsConfig(niwsClientConfig);}@Overridepublic void initWithNiwsConfig(IClientConfig niwsClientConfig) {String sZoneAffinity = "" + niwsClientConfig.getProperty(CommonClientConfigKey.EnableZoneAffinity, false);if (sZoneAffinity != null){zoneAffinity = Boolean.parseBoolean(sZoneAffinity);logger.debug("ZoneAffinity is set to {}", zoneAffinity);}String sZoneExclusive = "" + niwsClientConfig.getProperty(CommonClientConfigKey.EnableZoneExclusivity, false);if (sZoneExclusive != null){zoneExclusive = Boolean.parseBoolean(sZoneExclusive);}if (ConfigurationManager.getDeploymentContext() != null) {zone = ConfigurationManager.getDeploymentContext().getValue(ContextKey.zone);}activeReqeustsPerServerThreshold = DynamicPropertyFactory.getInstance().getDoubleProperty(niwsClientConfig.getClientName() + "." + niwsClientConfig.getNameSpace() + ".zoneAffinity.maxLoadPerServer", 0.6d);logger.debug("activeReqeustsPerServerThreshold: {}", activeReqeustsPerServerThreshold.get());blackOutServerPercentageThreshold = DynamicPropertyFactory.getInstance().getDoubleProperty(niwsClientConfig.getClientName() + "." + niwsClientConfig.getNameSpace() + ".zoneAffinity.maxBlackOutServesrPercentage", 0.8d);logger.debug("blackOutServerPercentageThreshold: {}", blackOutServerPercentageThreshold.get());availableServersThreshold = DynamicPropertyFactory.getInstance().getIntProperty(niwsClientConfig.getClientName() + "." + niwsClientConfig.getNameSpace() + ".zoneAffinity.minAvailableServers", 2);logger.debug("availableServersThreshold: {}", availableServersThreshold.get());overrideCounter = Monitors.newCounter("ZoneAffinity_OverrideCounter");Monitors.registerObject("NIWSServerListFilter_" + niwsClientConfig.getClientName());}private boolean shouldEnableZoneAffinity(List filtered) { if (!zoneAffinity && !zoneExclusive) {return false;}if (zoneExclusive) {return true;}LoadBalancerStats stats = getLoadBalancerStats();if (stats == null) {return zoneAffinity;} else {logger.debug("Determining if zone affinity should be enabled with given server list: {}", filtered);ZoneSnapshot snapshot = stats.getZoneSnapshot(filtered);double loadPerServer = snapshot.getLoadPerServer();int instanceCount = snapshot.getInstanceCount(); int circuitBreakerTrippedCount = snapshot.getCircuitTrippedCount();if (((double) circuitBreakerTrippedCount) / instanceCount >= blackOutServerPercentageThreshold.get() || loadPerServer >= activeReqeustsPerServerThreshold.get()|| (instanceCount - circuitBreakerTrippedCount) getFilteredListOfServers(List servers) {if (zone != null && (zoneAffinity || zoneExclusive) && servers !=null && servers.size() > 0){List filteredServers = Lists.newArrayList(Iterables.filter(servers, this.zoneAffinityPredicate.getServerOnlyPredicate()));if (shouldEnableZoneAffinity(filteredServers)) {return filteredServers;} else if (zoneAffinity) {overrideCounter.increment();}}return servers;}@Overridepublic String toString(){StringBuilder sb = new StringBuilder("ZoneAffinityServerListFilter:");sb.append(", zone: ").append(zone).append(", zoneAffinity:").append(zoneAffinity);sb.append(", zoneExclusivity:").append(zoneExclusive);return sb.toString(); }
}
(2)ZonePreferenceServerListFilter
public class ZonePreferenceServerListFilter extends ZoneAffinityServerListFilter {private String zone;&#64;Overridepublic void initWithNiwsConfig(IClientConfig niwsClientConfig) {super.initWithNiwsConfig(niwsClientConfig);if (ConfigurationManager.getDeploymentContext() !&#61; null) {this.zone &#61; ConfigurationManager.getDeploymentContext().getValue(ContextKey.zone);}}&#64;Overridepublic List getFilteredListOfServers(List servers) {List output &#61; super.getFilteredListOfServers(servers);if (this.zone !&#61; null && output.size() &#61;&#61; servers.size()) {List local &#61; new ArrayList<>();for (Server server : output) {if (this.zone.equalsIgnoreCase(server.getZone())) {local.add(server);}}if (!local.isEmpty()) {return local;}}return output;}public String getZone() {return zone;}public void setZone(String zone) {this.zone &#61; zone;}&#64;Overridepublic boolean equals(Object o) {if (this &#61;&#61; o) {return true;}if (o &#61;&#61; null || getClass() !&#61; o.getClass()) {return false;}ZonePreferenceServerListFilter that &#61; (ZonePreferenceServerListFilter) o;return Objects.equals(zone, that.zone);}&#64;Overridepublic int hashCode() {return Objects.hash(zone);}&#64;Overridepublic String toString() {return new StringBuilder("ZonePreferenceServerListFilter{").append("zone&#61;&#39;").append(zone).append("&#39;").append("}").toString();}}
&#xff08;3&#xff09;ServerListSubsetFilter
public class ServerListSubsetFilter extends ZoneAffinityServerListFilter implements IClientConfigAware, Comparator{private Random random &#61; new Random();private volatile Set currentSubset &#61; Sets.newHashSet(); private DynamicIntProperty sizeProp &#61; new DynamicIntProperty(DefaultClientConfigImpl.DEFAULT_PROPERTY_NAME_SPACE &#43; ".ServerListSubsetFilter.size", 20);private DynamicFloatProperty eliminationPercent &#61; new DynamicFloatProperty(DefaultClientConfigImpl.DEFAULT_PROPERTY_NAME_SPACE &#43; ".ServerListSubsetFilter.forceEliminatePercent", 0.1f);private DynamicIntProperty eliminationFailureCountThreshold &#61; new DynamicIntProperty(DefaultClientConfigImpl.DEFAULT_PROPERTY_NAME_SPACE &#43; ".ServerListSubsetFilter.eliminationFailureThresold", 0);private DynamicIntProperty eliminationConnectionCountThreshold &#61; new DynamicIntProperty(DefaultClientConfigImpl.DEFAULT_PROPERTY_NAME_SPACE &#43; ".ServerListSubsetFilter.eliminationConnectionThresold", 0);&#64;Overridepublic void initWithNiwsConfig(IClientConfig clientConfig) {super.initWithNiwsConfig(clientConfig);sizeProp &#61; new DynamicIntProperty(clientConfig.getClientName() &#43; "." &#43; clientConfig.getNameSpace() &#43; ".ServerListSubsetFilter.size", 20);eliminationPercent &#61; new DynamicFloatProperty(clientConfig.getClientName() &#43; "." &#43; clientConfig.getNameSpace() &#43; ".ServerListSubsetFilter.forceEliminatePercent", 0.1f);eliminationFailureCountThreshold &#61; new DynamicIntProperty( clientConfig.getClientName() &#43; "." &#43; clientConfig.getNameSpace()&#43; ".ServerListSubsetFilter.eliminationFailureThresold", 0);eliminationConnectionCountThreshold &#61; new DynamicIntProperty(clientConfig.getClientName() &#43; "." &#43; clientConfig.getNameSpace()&#43; ".ServerListSubsetFilter.eliminationConnectionThresold", 0);}/*** Given all the servers, keep only a stable subset of servers to use. This method* keeps the current list of subset in use and keep returning the same list, with exceptions* to relatively unhealthy servers, which are defined as the following:* *
* - Servers with their concurrent connection count exceeding the client configuration for * {&#64;code ..ServerListSubsetFilter.eliminationConnectionThresold} (default is 0)*
- Servers with their failure count exceeding the client configuration for * {&#64;code ..ServerListSubsetFilter.eliminationFailureThresold} (default is 0)*
- If the servers evicted above is less than the forced eviction percentage as defined by client configuration* {&#64;code ..ServerListSubsetFilter.forceEliminatePercent} (default is 10%, or 0.1), the* remaining servers will be sorted by their health status and servers will worst health status will be* forced evicted.*
* * After the elimination, new servers will be randomly chosen from all servers pool to keep the* number of the subset unchanged. * */&#64;Overridepublic List getFilteredListOfServers(List servers) {List zoneAffinityFiltered &#61; super.getFilteredListOfServers(servers);Set candidates &#61; Sets.newHashSet(zoneAffinityFiltered);Set newSubSet &#61; Sets.newHashSet(currentSubset);LoadBalancerStats lbStats &#61; getLoadBalancerStats();for (T server: currentSubset) {// this server is either down or out of serviceif (!candidates.contains(server)) {newSubSet.remove(server);} else {ServerStats stats &#61; lbStats.getSingleServerStat(server);// remove the servers that do not meet health criteriaif (stats.getActiveRequestsCount() > eliminationConnectionCountThreshold.get()|| stats.getFailureCount() > eliminationFailureCountThreshold.get()) {newSubSet.remove(server);// also remove from the general pool to avoid selecting them againcandidates.remove(server);}}}int targetedListSize &#61; sizeProp.get();int numEliminated &#61; currentSubset.size() - newSubSet.size();int minElimination &#61; (int) (targetedListSize * eliminationPercent.get());int numToForceEliminate &#61; 0;if (targetedListSize numEliminated) {numToForceEliminate &#61; minElimination - numEliminated; }if (numToForceEliminate > newSubSet.size()) {numToForceEliminate &#61; newSubSet.size();}if (numToForceEliminate > 0) {List sortedSubSet &#61; Lists.newArrayList(newSubSet); Collections.sort(sortedSubSet, this);List forceEliminated &#61; sortedSubSet.subList(0, numToForceEliminate);newSubSet.removeAll(forceEliminated);candidates.removeAll(forceEliminated);}// after forced elimination or elimination of unhealthy instances,// the size of the set may be less than the targeted size,// then we just randomly add servers from the big poolif (newSubSet.size() candidates.size()) {// Not enough healthy instances to choose, fallback to use the// total server poolcandidates &#61; Sets.newHashSet(zoneAffinityFiltered);candidates.removeAll(newSubSet);}List chosen &#61; randomChoose(Lists.newArrayList(candidates), numToChoose);for (T server: chosen) {newSubSet.add(server);}}currentSubset &#61; newSubSet; return Lists.newArrayList(newSubSet); }/*** Randomly shuffle the beginning portion of server list (according to the number passed into the method) * and return them.* * &#64;param servers* &#64;param toChoose* &#64;return*/private List randomChoose(List servers, int toChoose) {int size &#61; servers.size();if (toChoose >&#61; size || toChoose <0) {return servers;} for (int i &#61; 0; i }