深入理解ribbon
负载均衡器
AbstractLoadBalancer
public abstract class AbstractLoadBalancer implements ILoadBalancer {
public enum ServerGroup{
ALL,
STATUS_UP,
STATUS_NOT_UP
}
public Server chooseServer ( ) {
return chooseServer ( null) ;
}
public abstract List< Server> getServerList ( ServerGroup serverGroup) ;
public abstract LoadBalancerStats getLoadBalancerStats ( ) ;
}
BaseLoadBalancer
public class BaseLoadBalancer extends AbstractLoadBalancer implements
PrimeConnections. PrimeConnectionListener , IClientConfigAware {
@Monitor ( name = PREFIX + "AllServerList" , type = DataSourceType. INFORMATIONAL)
protected volatile List< Server> allServerList = Collections
. synchronizedList ( new ArrayList < Server> ( ) ) ;
@Monitor ( name = PREFIX + "UpServerList" , type = DataSourceType. INFORMATIONAL)
protected volatile List< Server> upServerList = Collections
. synchronizedList ( new ArrayList < Server> ( ) ) ;
protected LoadBalancerStats lbStats;
protected IPing ping = null;
protected IPingStrategy pingStrategy = DEFAULT_PING_STRATEGY;
private final static SerialPingStrategy DEFAULT_PING_STRATEGY = new SerialPingStrategy ( ) ;
private static class SerialPingStrategy implements IPingStrategy {
@Override
public boolean [ ] pingServers ( IPing ping, Server[ ] servers) {
int numCandidates = servers. length;
boolean [ ] results = new boolean [ numCandidates] ;
if ( logger. isDebugEnabled ( ) ) {
logger. debug ( "LoadBalancer: PingTask executing ["
+ numCandidates + "] servers configured" ) ;
}
for ( int i = 0 ; i < numCandidates; i++ ) {
results[ i] = false ;
try {
if ( ping != null) {
results[ i] = ping. isAlive ( servers[ i] ) ;
}
} catch ( Throwable t) {
logger. error ( "Exception while pinging Server:"
+ servers[ i] , t) ;
}
}
return results;
}
}
protected IRule rule = DEFAULT_RULE;
private final static IRule DEFAULT_RULE = new RoundRobinRule ( ) ;
public Server chooseServer ( Object key) {
if ( counter == null) {
counter = createCounter ( ) ;
}
counter. increment ( ) ;
if ( rule == null) {
return null;
} else {
try {
return rule. choose ( key) ;
} catch ( Throwable t) {
return null;
}
}
}
public BaseLoadBalancer ( ) {
this . name = DEFAULT_NAME;
this . ping = null;
setRule ( DEFAULT_RULE) ;
setupPingTask ( ) ;
lbStats = new LoadBalancerStats ( DEFAULT_NAME) ;
}
void setupPingTask ( ) {
if ( canSkipPing ( ) ) {
return ;
}
if ( lbTimer != null) {
lbTimer. cancel ( ) ;
}
lbTimer = new ShutdownEnabledTimer ( "NFLoadBalancer-PingTimer-" + name,
true ) ;
lbTimer. schedule ( new PingTask ( ) , 0 , pingIntervalSeconds * 1000 ) ;
forceQuickPing ( ) ;
}
public void markServerDown ( Server server) {
if ( server == null) {
return ;
}
if ( ! server. isAlive ( ) ) {
return ;
}
logger. error ( "LoadBalancer: markServerDown called on ["
+ server. getId ( ) + "]" ) ;
server. setAlive ( false ) ;
notifyServerStatusChangeListener ( singleton ( server) ) ;
}
@Override
public List< Server> getReachableServers ( ) {
return Collections. unmodifiableList ( upServerList) ;
}
@Override
public List< Server> getAllServers ( ) {
return Collections. unmodifiableList ( allServerList) ;
}
}
DynamicServerListLoadBalancer
DynamicServerListLoadBalancer
类继承于BaseLoadBalancer
类,是对基础负载均衡器的扩展。实现了服务实例清单在运行期间动态更新的能力。 还具备对服务实例清单过滤的功能,也就是说可以通过过滤器来选择性地获取一批服务实例清单。
public class DynamicServerListLoadBalancer < T extends Server > extends BaseLoadBalancer {
private static final Logger LOGGER = LoggerFactory. getLogger ( DynamicServerListLoadBalancer. class ) ;
boolean isSecure = false ;
boolean useTunnel = false ;
protected AtomicBoolean serverListUpdateInProgress = new AtomicBoolean ( false ) ;
volatile ServerList< T> serverListImpl;
volatile ServerListFilter< T> filter;
protected final ServerListUpdater. UpdateAction updateAction = new ServerListUpdater. UpdateAction ( ) {
@Override
public void doUpdate ( ) {
updateListOfServers ( ) ;
}
} ;
protected volatile ServerListUpdater serverListUpdater;
public DynamicServerListLoadBalancer ( ) {
super ( ) ;
}
public DynamicServerListLoadBalancer ( IClientConfig clientConfig, IRule rule, IPing ping,
ServerList< T> serverList, ServerListFilter< T> filter,
ServerListUpdater serverListUpdater) {
super ( clientConfig, rule, ping) ;
this . serverListImpl = serverList;
this . filter = filter;
this . serverListUpdater = serverListUpdater;
if ( filter instanceof AbstractServerListFilter ) {
( ( AbstractServerListFilter) filter) . setLoadBalancerStats ( getLoadBalancerStats ( ) ) ;
}
restOfInit ( clientConfig) ;
}
public DynamicServerListLoadBalancer ( IClientConfig clientConfig) {
initWithNiwsConfig ( clientConfig) ;
}
@Override
public void setServersList ( List lsrv) {
super . setServersList ( lsrv) ;
List< T> serverList = ( List< T> ) lsrv;
Map< String, List< Server> > serversInZones = new HashMap < String, List< Server> > ( ) ;
for ( Server server : serverList) {
getLoadBalancerStats ( ) . getSingleServerStat ( server) ;
String zone = server. getZone ( ) ;
if ( zone != null) {
zone = zone. toLowerCase ( ) ;
List< Server> servers = serversInZones. get ( zone) ;
if ( servers == null) {
servers = new ArrayList < Server> ( ) ;
serversInZones. put ( zone, servers) ;
}
servers. add ( server) ;
}
}
setServerListForZones ( serversInZones) ;
}
protected void setServerListForZones (
Map< String, List< Server> > zoneServersMap) {
LOGGER. debug ( "Setting server list for zones: {}" , zoneServersMap) ;
getLoadBalancerStats ( ) . updateZoneServerMapping ( zoneServersMap) ;
}
@VisibleForTesting
public void updateListOfServers ( ) {
List< T> servers = new ArrayList < T> ( ) ;
if ( serverListImpl != null) {
servers = serverListImpl. getUpdatedListOfServers ( ) ;
LOGGER. debug ( "List of Servers for {} obtained from Discovery client: {}" ,
getIdentifier ( ) , servers) ;
if ( filter != null) {
servers = filter. getFilteredListOfServers ( servers) ;
LOGGER. debug ( "Filtered List of Servers for {} obtained from Discovery client: {}" ,
getIdentifier ( ) , servers) ;
}
}
updateAllServerList ( servers) ;
}
protected void updateAllServerList ( List< T> ls) {
if ( serverListUpdateInProgress. compareAndSet ( false , true ) ) {
for ( T s : ls) {
s. setAlive ( true ) ;
}
setServersList ( ls) ;
super . forceQuickPing ( ) ;
serverListUpdateInProgress. set ( false ) ;
}
}
}
ServerList
public interface ServerList < T extends Server > {
public List< T> getInitialListOfServers ( ) ;
public List< T> getUpdatedListOfServers ( ) ;
}
可在EurekaRibbonClientConfiguration
类中找到配置serverList
实例的内容:
@Bean
@ConditionalOnMissingBean
public ServerList< ? > ribbonServerList ( IClientConfig config) {
DiscoveryEnabledNIWSServerList discoveryServerList =
new DiscoveryEnabledNIWSServerList ( config) ;
DomainExtractingServerList serverList = new DomainExtractingServerList (
discoveryServerList, config, this . approximateZoneFromHostname) ;
return serverList;
}
DomainExtractingServerList
源码如下,可以看出对getInitialListOfServers
和getUpdatedListOfServers
的具体实现,其实委托给了内部定义的ServerList list
对象。该对象通过构造函数传入的DiscoveryEnabledNIWSServerList
实现。
public class DomainExtractingServerList implements ServerList < DiscoveryEnabledServer> {
private ServerList< DiscoveryEnabledServer> list;
public DomainExtractingServerList ( ServerList< DiscoveryEnabledServer> list,
IClientConfig clientConfig, boolean approximateZoneFromHostname) {
this . list = list;
this . clientConfig = clientConfig;
this . approximateZoneFromHostname = approximateZoneFromHostname;
}
@Override
public List< DiscoveryEnabledServer> getInitialListOfServers ( ) {
List< DiscoveryEnabledServer> servers = setZones ( this . list
. getInitialListOfServers ( ) ) ;
return servers;
}
@Override
public List< DiscoveryEnabledServer> getUpdatedListOfServers ( ) {
List< DiscoveryEnabledServer> servers = setZones ( this . list
. getUpdatedListOfServers ( ) ) ;
return servers;
}
private List< DiscoveryEnabledServer> setZones ( List< DiscoveryEnabledServer> servers) {
List< DiscoveryEnabledServer> result = new ArrayList < > ( ) ;
boolean isSecure = this . clientConfig. getPropertyAsBoolean (
CommonClientConfigKey. IsSecure, Boolean. TRUE) ;
boolean shouldUseIpAddr = this . clientConfig. getPropertyAsBoolean (
CommonClientConfigKey. UseIPAddrForServer, Boolean. FALSE) ;
for ( DiscoveryEnabledServer server : servers) {
result. add ( new DomainExtractingServer ( server, isSecure, shouldUseIpAddr,
this . approximateZoneFromHostname) ) ;
}
return result;
}
}
DiscoveryEnabledNIWSServerList
类中这两个方法的实现都是通过该类中的一个私有函数obtainServerViaDiscovery
通过服务发现机制来实现服务实例的获取。
@Override
public List< DiscoveryEnabledServer> getInitialListOfServers ( ) {
return obtainServersViaDiscovery ( ) ;
}
@Override
public List< DiscoveryEnabledServer> getUpdatedListOfServers ( ) {
return obtainServersViaDiscovery ( ) ;
}
obtainServerViaDiscovery
的实现逻辑如下
private List< DiscoveryEnabledServer> obtainServersViaDiscovery ( ) {
List< DiscoveryEnabledServer> serverList = new ArrayList < DiscoveryEnabledServer> ( ) ;
if ( eurekaClientProvider == null || eurekaClientProvider. get ( ) == null) {
logger. warn ( "EurekaClient has not been initialized yet, returning an empty list" ) ;
return new ArrayList < DiscoveryEnabledServer> ( ) ;
}
EurekaClient eurekaClient = eurekaClientProvider. get ( ) ;
if ( vipAddresses != null) {
for ( String vipAddress : vipAddresses. split ( "," ) ) {
List< InstanceInfo> listOfInstanceInfo = eurekaClient. getInstancesByVipAddress ( vipAddress, isSecure, targetRegion) ;
for ( InstanceInfo ii : listOfInstanceInfo) {
if ( ii. getStatus ( ) . equals ( InstanceStatus. UP) ) {
if ( shouldUseOverridePort) {
if ( logger. isDebugEnabled ( ) ) {
logger. debug ( "Overriding port on client name: " + clientName + " to " + overridePort) ;
}
InstanceInfo copy = new InstanceInfo ( ii) ;
if ( isSecure) {
ii = new InstanceInfo. Builder ( copy) .
setSecurePort ( overridePort) . build ( ) ;
} else {
ii = new InstanceInfo. Builder ( copy) . setPort ( overridePort) . build ( ) ;
}
}
DiscoveryEnabledServer des = new DiscoveryEnabledServer (
ii, isSecure, shouldUseIpAddr) ;
des. setZone ( DiscoveryClient. getZone ( ii) ) ;
serverList. add ( des) ;
}
}
if ( serverList. size ( ) > 0 && prioritizeVipAddressBasedServers) {
break ;
}
}
}
return serverList;
}
然后调用DomainExtractingServerList
类中的setZones
方法进行对象映射转换,转换成内部定义的DomainExtractingServer
对象,该类是DiscoveryEnabledServer
的子类。在该对象的构造函数中将为服务实例对象设置一些必要的属性,如id、zone、isAliveFalg、readyToServer
等信息。
ServerListUpdater
protected final ServerListUpdater. UpdateAction updateAction =
new ServerListUpdater. UpdateAction ( ) {
@Override
public void doUpdate ( ) {
updateListOfServers ( ) ;
}
} ;
protected volatile ServerListUpdater serverListUpdater;
ServerListUpdater
接口定义如下。该接口有两个具体实现类:
PollingServerListUpdater
:动态服务列表更新的默认策略,通过定时任务的方式进行服务列表的更新。EurekaNotificationServerListUpdater
:需要利用Eureka
的事件监听器来驱动服务列表的更新操作。
public interface ServerListUpdater {
public interface UpdateAction {
void doUpdate ( ) ;
}
void start ( UpdateAction updateAction) ;
void stop ( ) ;
String getLastUpdate ( ) ;
long getDurationSinceLastUpdateMs ( ) ;
int getNumberMissedCycles ( ) ;
int getCoreThreads ( ) ;
}
PollingServerListUpdater
部分源码如下:
public class PollingServerListUpdater implements ServerListUpdater {
private static final Logger logger = LoggerFactory. getLogger ( PollingServerListUpdater. class ) ;
private static long LISTOFSERVERS_CACHE_UPDATE_DELAY = 1000 ;
private static int LISTOFSERVERS_CACHE_REPEAT_INTERVAL = 30 * 1000 ;
@Override
public synchronized void start ( final UpdateAction updateAction) {
if ( isActive. compareAndSet ( false , true ) ) {
final Runnable wrapperRunnable = new Runnable ( ) {
@Override
public void run ( ) {
if ( ! isActive. get ( ) ) {
if ( scheduledFuture != null) {
scheduledFuture. cancel ( true ) ;
}
return ;
}
try {
updateAction. doUpdate ( ) ;
lastUpdated = System. currentTimeMillis ( ) ;
} catch ( Exception e) {
logger. warn ( "Failed one update cycle" , e) ;
}
}
} ;
scheduledFuture = getRefreshExecutor ( ) . scheduleWithFixedDelay (
wrapperRunnable,
initialDelayMs,
refreshIntervalMs,
TimeUnit. MILLISECONDS
) ;
} else {
logger. info ( "Already active, no-op" ) ;
}
}
}
ServerListFilter
在DynamicServerListLoadBalancer
中,它的实际实现委托给了updateListOfServers
函数执行。
@VisibleForTesting
public void updateListOfServers ( ) {
List< T> servers = new ArrayList < T> ( ) ;
if ( serverListImpl != null) {
servers = serverListImpl. getUpdatedListOfServers ( ) ;
LOGGER. debug ( "List of Servers for {} obtained from Discovery client: {}" ,
getIdentifier ( ) , servers) ;
if ( filter != null) {
servers = filter. getFilteredListOfServers ( servers) ;
LOGGER. debug ( "Filtered List of Servers for {} obtained from Discovery client: {}" ,
getIdentifier ( ) , servers) ;
}
}
updateAllServerList ( servers) ;
}
filter
,ServerListFilter
接口实现类的对象,主要用于对服务实例列表的过滤,通过传入的服务实例清单,根据一些规则返回过滤后的服务实例清单。该接口实现类如下:
AbstractServerListFilter
:一个抽象过滤器,定义过滤时需要的一个重要依据对象LoadBalancerStates
。 public abstract class AbstractServerListFilter < T extends Server >
implements ServerListFilter < T> {
private volatile LoadBalancerStats stats;
public void setLoadBalancerStats ( LoadBalancerStats stats) {
this . stats = stats;
}
public LoadBalancerStats getLoadBalancerStats ( ) {
return stats;
}
}
ZoneAffinityServerListFilter
:基于**区域感知(Zone Affinity)
**的方式实现服务实例的过滤。就是说,可以根据提供服务的实例所处的区域与消费者自身所处的区域进行比较,过滤掉那些不是同处一个区域的实例。
@Override
public List< T> getFilteredListOfServers ( List< T> servers) {
if ( zone != null && ( zoneAffinity || zoneExclusive) &&
servers != null && servers. size ( ) > 0 ) {
List< T> filteredServers = Lists. newArrayList ( Iterables. filter (
servers, this . zoneAffinityPredicate. getServerOnlyPredicate ( ) ) ) ;
if ( shouldEnableZoneAffinity ( filteredServers) ) {
return filteredServers;
} else if ( zoneAffinity) {
overrideCounter. increment ( ) ;
}
}
return servers;
}
blackOutServerPercentage:
故障实例百分比(断路器断开数/实例数量) >= 0.8
activeRequestsPerServer:
实例平均负载 >= 0.6
availableServers:
可用实例数(实例数量 - 断路器断开数) < 2
private boolean shouldEnableZoneAffinity ( List< T> 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) < availableServersThreshold. get ( ) ) {
logger. debug ( "zoneAffinity is overriden. blackOutServerPercentage: {}, activeReqeustsPerServer: {}, availableServers: {}" ,
new Object [ ] { ( double ) circuitBreakerTrippedCount / instanceCount, loadPerServer, instanceCount - circuitBreakerTrippedCount} )
return false ;
} else {
return true ;
}
}
}
DefaultNIWSServerListFilter:
完全继承自ZoneAffinityServerListFilter
,
默认的NIWS(Netflix Internal Web Service)
过滤器。 ServerListSubsetFilter:
也继承自ZoneAffinityServerListFilter
,非常适用于拥有大规模服务器集群的系统。ZonePreferenceServerListFilter:
也继承自ZoneAffinityServerListFilter
,Spring Cloud
整合时新增的过滤器。它实现了通过配置或者Eureka
实例元数据的所属区域(Zone)
来过滤出同区域的服务实例。 @Override
public List< Server> getFilteredListOfServers ( List< Server> servers) {
List< Server> output = super . getFilteredListOfServers ( servers) ;
if ( this . zone != null && output. size ( ) == servers. size ( ) ) {
List< Server> local = new ArrayList < Server> ( ) ;
for ( Server server : output) {
if ( this . zone. equalsIgnoreCase ( server. getZone ( ) ) ) {
local. add ( server) ;
}
}
if ( ! local. isEmpty ( ) ) {
return local;
}
}
return output;
}
ZoneAwareLoadBalancer
该负载均衡器是对DynamicServerListLoadBalancer
的一个扩展。在DynamicServerListLoadBalancer
中并没有重写选择具体服务实例的chooseServer
函数,所以它使用的是BaseLoadBalancer
父类中的chooseServer
方法,以线性轮询的方式来选择调用的服务实例。没有跨区域 的概念。 在DynamicServerListLoadBalancer
中,有如下两个方法:
@Override
public void setServersList ( List lsrv) {
super . setServersList ( lsrv) ;
List< T> serverList = ( List< T> ) lsrv;
Map< String, List< Server> > serversInZones = new HashMap < String, List< Server> > ( ) ;
for ( Server server : serverList) {
getLoadBalancerStats ( ) . getSingleServerStat ( server) ;
String zone = server. getZone ( ) ;
if ( zone != null) {
zone = zone. toLowerCase ( ) ;
List< Server> servers = serversInZones. get ( zone) ;
if ( servers == null) {
servers = new ArrayList < Server> ( ) ;
serversInZones. put ( zone, servers) ;
}
servers. add ( server) ;
}
}
setServerListForZones ( serversInZones) ;
}
protected void setServerListForZones (
Map< String, List< Server> > zoneServersMap) {
LOGGER. debug ( "Setting server list for zones: {}" , zoneServersMap) ;
getLoadBalancerStats ( ) . updateZoneServerMapping ( zoneServersMap) ;
}
在ZoneAwareLoadBalancer
中并没有重写setServerList
方法,但是重写了setServerListForZones
方法,如下:
@Override
protected void setServerListForZones ( Map< String, List< Server> > zoneServersMap) {
super . setServerListForZones ( zoneServersMap) ;
if ( balancers == null) {
balancers = new ConcurrentHashMap < String, BaseLoadBalancer> ( ) ;
}
for ( Map. Entry< String, List< Server> > entry: zoneServersMap. entrySet ( ) ) {
String zone = entry. getKey ( ) . toLowerCase ( ) ;
getLoadBalancer ( zone) . setServersList ( entry. getValue ( ) ) ;
}
for ( Map. Entry< String, BaseLoadBalancer> existingLBEntry: balancers. entrySet ( ) ) {
if ( ! zoneServersMap. keySet ( ) . contains ( existingLBEntry. getKey ( ) ) ) {
existingLBEntry. getValue ( ) . setServersList ( Collections. emptyList ( ) ) ;
}
}
}
@Override
public Server chooseServer ( Object key) {
if ( ! ENABLED. get ( ) || getLoadBalancerStats ( ) . getAvailableZones ( ) . size ( ) <= 1 ) {
logger. debug ( "Zone aware logic disabled or there is only one zone" ) ;
return super . chooseServer ( key) ;
}
Server server = null;
try {
LoadBalancerStats lbStats = getLoadBalancerStats ( ) ;
Map< String, ZoneSnapshot> zoneSnapshot = ZoneAvoidanceRule. createSnapshot ( lbStats) ;
logger. debug ( "Zone snapshots: {}" , zoneSnapshot) ;
if ( triggeringLoad == null) {
triggeringLoad = DynamicPropertyFactory. getInstance ( ) . getDoubleProperty (
"ZoneAwareNIWSDiscoveryLoadBalancer." + this . getName ( ) + ".triggeringLoadPerServerThreshold" , 0.2d ) ;
}
if ( triggeringBlackoutPercentage == null) {
triggeringBlackoutPercentage = DynamicPropertyFactory. getInstance ( ) . getDoubleProperty (
"ZoneAwareNIWSDiscoveryLoadBalancer." + this . getName ( ) + ".avoidZoneWithBlackoutPercetage" , 0.99999d ) ;
}
Set< String> availableZones = ZoneAvoidanceRule. getAvailableZones ( zoneSnapshot, triggeringLoad. get ( ) , triggeringBlackoutPercentage. get ( ) ) ;
logger. debug ( "Available zones: {}" , availableZones) ;
if ( availableZones != null && availableZones. size ( ) < zoneSnapshot. keySet ( ) . size ( ) ) {
String zone = ZoneAvoidanceRule. randomChooseZone ( zoneSnapshot, availableZones) ;
logger. debug ( "Zone chosen: {}" , zone) ;
if ( zone != null) {
BaseLoadBalancer zoneLoadBalancer = getLoadBalancer ( zone) ;
server = zoneLoadBalancer. chooseServer ( key) ;
}
}
} catch ( Throwable e) {
logger. error ( "Unexpected exception when choosing server using zone aware logic" , e) ;
}
if ( server != null) {
return server;
} else {
logger. debug ( "Zone avoidance logic is not invoked." ) ;
return super . chooseServer ( key) ;
}
}
负载均衡策略
AbstractLoadBalancerRule
获取到一些负载均衡器中维护的信息来作为分配依据,并以此来设计一些算法来实现针对特定场景的高效策略。
public abstract class AbstractLoadBalancerRule implements IRule , IClientConfigAware {
private ILoadBalancer lb;
@Override
public void setLoadBalancer ( ILoadBalancer lb) {
this . lb = lb;
}
@Override
public ILoadBalancer getLoadBalancer ( ) {
return lb;
}
}
RandomRule
实现了从服务实例清单中随机选择一个服务实例的功能。
public class RandomRule extends AbstractLoadBalancerRule {
Random rand;
public RandomRule ( ) {
rand = new Random ( ) ;
}
@Override
public Server choose ( Object key) {
return choose ( getLoadBalancer ( ) , key) ;
}
public Server choose ( ILoadBalancer lb, Object key) {
if ( lb == null) {
return null;
}
Server server = null;
while ( server == null) {
if ( Thread. interrupted ( ) ) {
return null;
}
List< Server> upList = lb. getReachableServers ( ) ;
List< Server> allList = lb. getAllServers ( ) ;
int serverCount = allList. size ( ) ;
if ( serverCount == 0 ) {
return null;
}
int index = rand. nextInt ( serverCount) ;
server = upList. get ( index) ;
if ( server == null) {
Thread. yield ( ) ;
continue ;
}
if ( server. isAlive ( ) ) {
return ( server) ;
}
server = null;
Thread. yield ( ) ;
}
return server;
}
@Override
public void initWithNiwsConfig ( IClientConfig clientConfig) {
}
}
RoundRobinRule
实现了按照线性轮询的方式一次选择每个服务实例的功能。
public class RoundRobinRule extends AbstractLoadBalancerRule {
private AtomicInteger nextServerCyclicCounter;
private static final boolean AVAILABLE_ONLY_SERVERS = true ;
private static final boolean ALL_SERVERS = false ;
private static Logger log = LoggerFactory. getLogger ( RoundRobinRule. class ) ;
public RoundRobinRule ( ) {
nextServerCyclicCounter = new AtomicInteger ( 0 ) ;
}
public RoundRobinRule ( ILoadBalancer lb) {
this ( ) ;
setLoadBalancer ( lb) ;
}
public Server choose ( ILoadBalancer lb, Object key) {
if ( lb == null) {
log. warn ( "no load balancer" ) ;
return null;
}
Server server = null;
int count = 0 ;
while ( server == null && count++ < 10 ) {
List< Server> reachableServers = lb. getReachableServers ( ) ;
List< Server> allServers = lb. getAllServers ( ) ;
int upCount = reachableServers. size ( ) ;
int serverCount = allServers. size ( ) ;
if ( ( upCount == 0 ) || ( serverCount == 0 ) ) {
log. warn ( "No up servers available from load balancer: " + lb) ;
return null;
}
int nextServerIndex = incrementAndGetModulo ( serverCount) ;
server = allServers. get ( nextServerIndex) ;
if ( server == null) {
Thread. yield ( ) ;
continue ;
}
if ( server. isAlive ( ) && ( server. isReadyToServe ( ) ) ) {
return ( server) ;
}
server = null;
}
if ( count >= 10 ) {
log. warn ( "No available alive servers after 10 tries from load balancer: " + lb) ;
}
return server;
}
private int incrementAndGetModulo ( int modulo) {
for ( ; ; ) {
int current = nextServerCyclicCounter. get ( ) ;
int next = ( current + 1 ) % modulo;
if ( nextServerCyclicCounter. compareAndSet ( current, next) )
return next;
}
}
@Override
public Server choose ( Object key) {
return choose ( getLoadBalancer ( ) , key) ;
}
@Override
public void initWithNiwsConfig ( IClientConfig clientConfig) {
}
}
RetryRule
public class RetryRule extends AbstractLoadBalancerRule {
IRule subRule = new RoundRobinRule ( ) ;
long maxRetryMillis = 500 ;
public RetryRule ( ) {
}
public RetryRule ( IRule subRule) {
this . subRule = ( subRule != null) ? subRule : new RoundRobinRule ( ) ;
}
public RetryRule ( IRule subRule, long maxRetryMillis) {
this . subRule = ( subRule != null) ? subRule : new RoundRobinRule ( ) ;
this . maxRetryMillis = ( maxRetryMillis > 0 ) ? maxRetryMillis : 500 ;
}
public void setRule ( IRule subRule) {
this . subRule = ( subRule != null) ? subRule : new RoundRobinRule ( ) ;
}
public IRule getRule ( ) {
return subRule;
}
public void setMaxRetryMillis ( long maxRetryMillis) {
if ( maxRetryMillis > 0 ) {
this . maxRetryMillis = maxRetryMillis;
} else {
this . maxRetryMillis = 500 ;
}
}
public long getMaxRetryMillis ( ) {
return maxRetryMillis;
}
@Override
public void setLoadBalancer ( ILoadBalancer lb) {
super . setLoadBalancer ( lb) ;
subRule. setLoadBalancer ( lb) ;
}
public Server choose ( ILoadBalancer lb, Object key) {
long requestTime = System. currentTimeMillis ( ) ;
long deadline = requestTime + maxRetryMillis;
Server answer = null;
answer = subRule. choose ( key) ;
if ( ( ( answer == null) || ( ! answer. isAlive ( ) ) ) && ( System. currentTimeMillis ( ) < deadline) ) {
InterruptTask task = new InterruptTask ( deadline - System. currentTimeMillis ( ) ) ;
while ( ! Thread. interrupted ( ) ) {
answer = subRule. choose ( key) ;
if ( ( ( answer == null) || ( ! answer. isAlive ( ) ) )
&& ( System. currentTimeMillis ( ) < deadline) ) {
Thread. yield ( ) ;
} else {
break ;
}
}
task. cancel ( ) ;
}
if ( ( answer == null) || ( ! answer. isAlive ( ) ) ) {
return null;
} else {
return answer;
}
}
@Override
public Server choose ( Object key) {
return choose ( getLoadBalancer ( ) , key) ;
}
@Override
public void initWithNiwsConfig ( IClientConfig clientConfig) {
}
}
WeightedResponseTimeRule
根据实例的运行情况计算权重,并根据权重来挑选实例,已达到更优的分配效果。 启动一个定时任务,为每个服务实例计算权重,默认30
秒执行一次。 权重计算分为两个步骤:
累加所有实例的平均响应时间,得到总平均响应时间totalResponseTime
。 为每个实例计算权重。计算规则weightSoFar + totalResponseTime - 实例平均响应时间
,其中weightSoFar
初始化值为零,并且每计算好一个权重需要累加给weightSoFar
,共下一个实例权重计算时使用。 实际上来说,就是平均响应时间越短,权重区间的宽度就越大,则被选中的概率就越高。
public void maintainWeights ( ) {
ILoadBalancer lb = getLoadBalancer ( ) ;
if ( lb == null) {
return ;
}
if ( serverWeightAssignmentInProgress. get ( ) ) {
return ;
} else {
serverWeightAssignmentInProgress. set ( true ) ;
}
try {
logger. info ( "Weight adjusting job started" ) ;
AbstractLoadBalancer nlb = ( AbstractLoadBalancer) lb;
LoadBalancerStats stats = nlb. getLoadBalancerStats ( ) ;
if ( stats == null) {
return ;
}
double totalResponseTime = 0 ;
for ( Server server : nlb. getAllServers ( ) ) {
ServerStats ss = stats. getSingleServerStat ( server) ;
totalResponseTime += ss. getResponseTimeAvg ( ) ;
}
Double weightSoFar = 0.0 ;
List< Double> finalWeights = new ArrayList < Double> ( ) ;
for ( Server server : nlb. getAllServers ( ) ) {
ServerStats ss = stats. getSingleServerStat ( server) ;
double weight = totalResponseTime - ss. getResponseTimeAvg ( ) ;
weightSoFar += weight;
finalWeights. add ( weightSoFar) ;
}
setWeights ( finalWeights) ;
} catch ( Throwable t) {
logger. error ( "Exception while dynamically calculating server weights" , t) ;
} finally {
serverWeightAssignmentInProgress. set ( false ) ;
}
}
@Override
public Server choose ( ILoadBalancer lb, Object key) {
if ( lb == null) {
return null;
}
Server server = null;
while ( server == null) {
List< Double> currentWeights = accumulatedWeights;
if ( Thread. interrupted ( ) ) {
return null;
}
List< Server> allList = lb. getAllServers ( ) ;
int serverCount = allList. size ( ) ;
if ( serverCount == 0 ) {
return null;
}
int serverIndex = 0 ;
double maxTotalWeight = currentWeights. size ( ) == 0 ? 0 : currentWeights. get ( currentWeights. size ( ) - 1 ) ;
if ( maxTotalWeight < 0.001d ) {
server = super . choose ( getLoadBalancer ( ) , key) ;
if ( server == null) {
return server;
}
} else {
double randomWeight = random. nextDouble ( ) * maxTotalWeight;
int n = 0 ;
for ( Double d : currentWeights) {
if ( d >= randomWeight) {
serverIndex = n;
break ;
} else {
n++ ;
}
}
server = allList. get ( serverIndex) ;
}
if ( server == null) {
Thread. yield ( ) ;
continue ;
}
if ( server. isAlive ( ) ) {
return ( server) ;
}
server = null;
}
return server;
}
ClientConfigEnabledRoundRobinRule
一般不直接使用它。 在它的内部定义了一个RoundRobinRule
策略,而choose
函数的实现则是RoundRobinRule
的线性轮询机制。 通过实现该类的子类,重写choose
方法,就可以做一些高级的策略。如果该策略无法实施,那么就调用父类的实现作为备选策略。
BestAvailableRule
通过遍历负载均衡器中维护的所有服务实例,过滤掉故障的实例,并找出发送请求数最小的一个。所以,该策略的特性是可以选出最空闲的实例。 该类的choose
函数的核心算法依据的是统计对象localBalancerState
,当其为空时该策略就无法执行。此时就会采用父类的轮询策略备用。
public class BestAvailableRule extends ClientConfigEnabledRoundRobinRule {
private LoadBalancerStats loadBalancerStats;
@Override
public Server choose ( Object key) {
if ( loadBalancerStats == null) {
return super . choose ( key) ;
}
List< Server> serverList = getLoadBalancer ( ) . getAllServers ( ) ;
int minimalConcurrentConnections = Integer. MAX_VALUE;
long currentTime = System. currentTimeMillis ( ) ;
Server chosen = null;
for ( Server server: serverList) {
ServerStats serverStats = loadBalancerStats. getSingleServerStat ( server) ;
if ( ! serverStats. isCircuitBreakerTripped ( currentTime) ) {
int concurrentConnections = serverStats. getActiveRequestsCount ( currentTime) ;
if ( concurrentConnections < minimalConcurrentConnections) {
minimalConcurrentConnections = concurrentConnections;
chosen = server;
}
}
}
if ( chosen == null) {
return super . choose ( key) ;
} else {
return chosen;
}
}
@Override
public void setLoadBalancer ( ILoadBalancer lb) {
super . setLoadBalancer ( lb) ;
if ( lb instanceof AbstractLoadBalancer ) {
loadBalancerStats = ( ( AbstractLoadBalancer) lb) . getLoadBalancerStats ( ) ;
}
}
}
PredicateBaseRule
这是一个抽象策略,基于Predicate
实现的策略。 先通过子类中实现的Predicate
逻辑来过滤一部分服务,然后再以线性轮询的方式从过滤后的实例清单中选出一个。 遵循的是先过滤清单,再轮询选择 。
AvailabilityFilteringRule
继承自抽象策略PredicateBaseRule
。也遵循先过滤清单, 再轮询选择 。它过滤判断的依据如下:
是否故障,即断路器是否生效已断开。 实例的并发请求数大于阈值,默认为2 ^ 32 -1
。 满足一个就返回false
。
ZoneAvoidanceRule
这是一个组合过滤条件。在其构造函数中,以ZoneAvoidancePredicate
为主过滤条件,AvailabilityPredicate
为次过滤条件。 它完全遵循先过滤清单,再轮询选择 。 每次过滤之后(主从都过滤完算一次),都需要判断如下两个条件是否成立,若有一个符合,则不再进行过滤。将当前结果返回供线性轮询算法选择。
过滤后的实例总数 ≥ 最小过滤实例数(默认为1)
过滤后的实例比例 > 最小过滤百分比(默认为0)