Ribbion的七种负载均衡
Ribbion通过IRule接口调用AbstractLoadBalanceRule抽象类,这个抽象类实现了Ribbion的各种负载均衡的算法
轮询 RoundRobinRule
方法:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器的下表。
假设当前有两台机器组件集群,按照轮询算法:
当前请求个数 1:1 % 2 = 1 — 获得服务器地址 xxx.xxx.xxx.1:port
当前请求个数 2:2 % 2 = 0 — 获得服务器地址 xxx.xxx.xxx.1:port
当前请求个数 3:3 % 2 = 1 — 获得服务器地址 xxx.xxx.xxx.1:port
当前请求个数 4:4 % 2 = 0 — 获得服务器地址 xxx.xxx.xxx.1:port
…
源码:
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
log.warn("no load balancer");
return null;
} else {
Server server = null;
int count = 0;
while(true) {
if (server == null && count++ < 10) {
List<Server> reachableServers = lb.getReachableServers();
List<Server> allServers = lb.getAllServers(); //获取所有的server
int upCount = reachableServers.size();
int serverCount = allServers.size();
if (upCount != 0 && serverCount != 0) {
int nextServerIndex = this.incrementAndGetModulo(serverCount);//获取下次访问的server的下表----轮询方法就在这个方法中。
server = (Server)allServers.get(nextServerIndex);
if (server == null) {
Thread.yield();
} else {
if (server.isAlive() && server.isReadyToServe()) {
return server;
}
server = null;
}
continue;
}
log.warn("No up servers available from load balancer: " + lb);
return null;
}
if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: " + lb);
}
return server;
}
}
}
}
private int incrementAndGetModulo(int modulo) {
int current;
int next;
do {//此处就是一个自旋锁
current = this.nextServerCyclicCounter.get();
next = (current + 1) % modulo;//取余运算,轮询机制在这。
} while(!this.nextServerCyclicCounter.compareAndSet(current, next));//此处很明显是个CAS,底层就是个轻量级的自旋锁;返回的是compareAndSwapInt(this,valueOffset,expesct,updata),防止ABA问题。
return next;
}
自己写代码
@Component
public class MyLB implements LoadBalancer{
private AtomicInteger atomicInteger = new AtomicInteger(0);
public final int getAndIncrement(){
int current,next;
do {
current = this.atomicInteger.get();
next = current >= Integer.MAX_VALUE ? 0 : current + 1;
}while (!this.atomicInteger.compareAndSet(current,next));
System.out.println("next= "+next);
return next;
}
@Override
public ServiceInstance instances(List<ServiceInstance> serviceInstancess) {
int i = getAndIncrement() % serviceInstancess.size();
return serviceInstancess.get(i);
}
}
随机 RandomRule
调用Random函数随机返回一个服务器地址
代码
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
} else {
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 = this.chooseRandomInt(serverCount);//这里进行随机选择一个index
server = (Server)upList.get(index);
if (server == null) {
Thread.yield();
} else {
if (server.isAlive()) {
return server;
}
server = null;
Thread.yield();
}
}
return server;
}
}
protected int chooseRandomInt(int serverCount) {
return ThreadLocalRandom.current().nextInt(serverCount);//这里进行随机选择
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
重试 RetryRule
Retry规则会先按照轮询进行服务获取,获取失败后会在指定的响应时间内重试
public RetryRule(IRule subRule) {
this.subRule = (IRule)(subRule != null ? subRule : new RoundRobinRule());
}
public RetryRule(IRule subRule, long maxRetryMillis) {
this.subRule = (IRule)(subRule != null ? subRule : new RoundRobinRule());
this.maxRetryMillis = maxRetryMillis > 0L ? maxRetryMillis : 500L;
}
//默认是按照轮询方式进行选择
public Server choose(ILoadBalancer lb, Object key) {
long requestTime = System.currentTimeMillis();
long deadline = requestTime + this.maxRetryMillis;
Server answer = null;
answer = this.subRule.choose(key);
//默认通过上一行代码进行轮询选择,轮询如果失败进入下面的代码;下面的代码通过InterruptTask进行选择出requestTime + this.maxRetryMillis- System.currentTimeMillis()最小的服务器返回。也就是找响应时间最短的服务器。
if ((answer == null || !answer.isAlive()) && System.currentTimeMillis() < deadline) {
InterruptTask task = new InterruptTask(deadline - System.currentTimeMillis());
while(!Thread.interrupted()) {
answer = this.subRule.choose(key);
if (answer != null && answer.isAlive() || System.currentTimeMillis() >= deadline) {
break;
}
Thread.yield();
}
task.cancel();
}
return answer != null && answer.isAlive() ? answer : null;
}
加权响应 WeightedResponseTimeRule
获取响应速度最快的实例
代码
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
} else {
Server server = null;
while(server == null) {
List<Double> currentWeights = this.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.0D : (Double)currentWeights.get(currentWeights.size() - 1);
if (maxTotalWeight >= 0.001D && serverCount == currentWeights.size()) {
double randomWeight = this.random.nextDouble() * maxTotalWeight;
int n = 0;
for(Iterator var13 = currentWeights.iterator(); var13.hasNext(); ++n) {
Double d = (Double)var13.next();
if (d >= randomWeight) {
serverIndex = n;
break;
}
}
server = (Server)allList.get(serverIndex);
} else {
server = super.choose(this.getLoadBalancer(), key);
if (server == null) {
return server;
}
}
if (server == null) {
Thread.yield();
} else {
if (server.isAlive()) {
return server;
}
server = null;
}
}
return server;
}
}
最佳可用 BestAvailableRule
优先过滤掉由多次访问故障的服务器,选择并发量最小的服务器
代码
public Server choose(Object key) {
if (this.loadBalancerStats == null) {
return super.choose(key);
} else {
List<Server> serverList = this.getLoadBalancer().getAllServers();
int minimalConcurrentConnections = 2147483647;
long currentTime = System.currentTimeMillis();
Server chosen = null;
Iterator var7 = serverList.iterator();
while(var7.hasNext()) {
Server server = (Server)var7.next();
ServerStats serverStats = this.loadBalancerStats.getSingleServerStat(server);
if (!serverStats.isCircuitBreakerTripped(currentTime)) {
int concurrentConnections = serverStats.getActiveRequestsCount(currentTime);//获取连接数
if (concurrentConnections < minimalConcurrentConnections) {
minimalConcurrentConnections = concurrentConnections;//更新连接数,去掉不可用服务器
chosen = server;//在可用服务器中用next获取返回
}
}
}
if (chosen == null) {
return super.choose(key);
} else {
return chosen;
}
}
}
AvailabilityFilteringRule
先过滤到故障实例,再选择并发较小的实例
代码
public class AvailabilityFilteringRule extends PredicateBasedRule {
private AbstractServerPredicate predicate = CompositePredicate.withPredicate(new AvailabilityPredicate(this, (IClientConfig)null)).addFallbackPredicate(AbstractServerPredicate.alwaysTrue()).build();
public AvailabilityFilteringRule() {
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
this.predicate = CompositePredicate.withPredicate(new AvailabilityPredicate(this, clientConfig)).addFallbackPredicate(AbstractServerPredicate.alwaysTrue()).build();
}
@Monitor(
name = "AvailableServersCount",
type = DataSourceType.GAUGE
)
public int getAvailableServersCount() {
ILoadBalancer lb = this.getLoadBalancer();
List<Server> servers = lb.getAllServers();
return servers == null ? 0 : Collections2.filter(servers, this.predicate.getServerOnlyPredicate()).size();
}
public Server choose(Object key) {
int count = 0;
for(Server server = this.roundRobinRule.choose(key); count++ <= 10; server = this.roundRobinRule.choose(key)) {
if (this.predicate.apply(new PredicateKey(server))) {
return server;
}
}
return super.choose(key);
}
public AbstractServerPredicate getPredicate() {
return this.predicate;
}
}
ZoneAvoidanceRule
public class ZoneAvoidanceRule extends PredicateBasedRule {
private static final Random random = new Random();
private CompositePredicate compositePredicate;
public ZoneAvoidanceRule() {
ZoneAvoidancePredicate zonePredicate = new ZoneAvoidancePredicate(this);
AvailabilityPredicate availabilityPredicate = new AvailabilityPredicate(this);
this.compositePredicate = this.createCompositePredicate(zonePredicate, availabilityPredicate);
}
private CompositePredicate createCompositePredicate(ZoneAvoidancePredicate p1, AvailabilityPredicate p2) {
return CompositePredicate.withPredicates(new AbstractServerPredicate[]{p1, p2}).addFallbackPredicate(p2).addFallbackPredicate(AbstractServerPredicate.alwaysTrue()).build();
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
ZoneAvoidancePredicate zonePredicate = new ZoneAvoidancePredicate(this, clientConfig);
AvailabilityPredicate availabilityPredicate = new AvailabilityPredicate(this, clientConfig);
this.compositePredicate = this.createCompositePredicate(zonePredicate, availabilityPredicate);
}
static Map<String, ZoneSnapshot> createSnapshot(LoadBalancerStats lbStats) {
Map<String, ZoneSnapshot> map = new HashMap();
Iterator var2 = lbStats.getAvailableZones().iterator();
while(var2.hasNext()) {
String zone = (String)var2.next();
ZoneSnapshot snapshot = lbStats.getZoneSnapshot(zone);
map.put(zone, snapshot);
}
return map;
}
static String randomChooseZone(Map<String, ZoneSnapshot> snapshot, Set<String> chooseFrom) {
if (chooseFrom != null && chooseFrom.size() != 0) {
String selectedZone = (String)chooseFrom.iterator().next();
if (chooseFrom.size() == 1) {
return selectedZone;
} else {
int totalServerCount = 0;
String zone;
for(Iterator var4 = chooseFrom.iterator(); var4.hasNext(); totalServerCount += ((ZoneSnapshot)snapshot.get(zone)).getInstanceCount()) {
zone = (String)var4.next();
}
int index = random.nextInt(totalServerCount) + 1;
int sum = 0;
Iterator var6 = chooseFrom.iterator();
while(var6.hasNext()) {
String zone = (String)var6.next();
sum += ((ZoneSnapshot)snapshot.get(zone)).getInstanceCount();
if (index <= sum) {
selectedZone = zone;
break;
}
}
return selectedZone;
}
} else {
return null;
}
}
public static Set<String> getAvailableZones(Map<String, ZoneSnapshot> snapshot, double triggeringLoad, double triggeringBlackoutPercentage) {
if (snapshot.isEmpty()) {
return null;
} else {
Set<String> availableZones = new HashSet(snapshot.keySet());
if (availableZones.size() == 1) {
return availableZones;
} else {
Set<String> worstZones = new HashSet();
double maxLoadPerServer = 0.0D;
boolean limitedZoneAvailability = false;
Iterator var10 = snapshot.entrySet().iterator();
while(true) {
while(var10.hasNext()) {
Entry<String, ZoneSnapshot> zoneEntry = (Entry)var10.next();
String zone = (String)zoneEntry.getKey();
ZoneSnapshot zoneSnapshot = (ZoneSnapshot)zoneEntry.getValue();
int instanceCount = zoneSnapshot.getInstanceCount();
if (instanceCount == 0) {
availableZones.remove(zone);
limitedZoneAvailability = true;
} else {
double loadPerServer = zoneSnapshot.getLoadPerServer();
if ((double)zoneSnapshot.getCircuitTrippedCount() / (double)instanceCount < triggeringBlackoutPercentage && loadPerServer >= 0.0D) {
if (Math.abs(loadPerServer - maxLoadPerServer) < 1.0E-6D) {
worstZones.add(zone);
} else if (loadPerServer > maxLoadPerServer) {
maxLoadPerServer = loadPerServer;
worstZones.clear();
worstZones.add(zone);
}
} else {
availableZones.remove(zone);
limitedZoneAvailability = true;
}
}
}
if (maxLoadPerServer < triggeringLoad && !limitedZoneAvailability) {
return availableZones;
}
String zoneToAvoid = randomChooseZone(snapshot, worstZones);
if (zoneToAvoid != null) {
availableZones.remove(zoneToAvoid);
}
return availableZones;
}
}
}
}
public static Set<String> getAvailableZones(LoadBalancerStats lbStats, double triggeringLoad, double triggeringBlackoutPercentage) {
if (lbStats == null) {
return null;
} else {
Map<String, ZoneSnapshot> snapshot = createSnapshot(lbStats);
return getAvailableZones(snapshot, triggeringLoad, triggeringBlackoutPercentage);
}
}
public AbstractServerPredicate getPredicate() {
return this.compositePredicate;
}
}