ribbon实现负载均衡
ribbon中所有的loadbalancer都是通过继承AbstractLoalBalancerRule来实现负载均衡规则的实现
公司项目中使用的zookeeper注册节点地址为127.0.0.1,本机地址,在部署时不会发生错误,但在开发环境中,使用feign接口进行调用时会出现feign调用失败的错误
基于ribbon修复bug
原始的ribbon负载均衡调用 (轮询源码)
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();
int upCount = reachableServers.size();
int serverCount = allServers.size();
if (upCount != 0 && serverCount != 0) {
int nextServerIndex = this.incrementAndGetModulo(serverCount);
// 轮询nextServerIndex
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;
}
}
}
除了轮询策略,loadbalancer还内置了一些策略如下:
策略类 | 命名 | 描述 |
---|---|---|
RandomRule | 随机策略 | 随机选择 Server |
RoundRobinRule | 轮询策略 | 按照顺序循环选择 Server |
RetryRule | 重试策略 | 在一个配置时间段内,当选择的 Server 不成功,则一直尝试选择一个可用的 Server |
BestAvailableRule | 最低并发策略 | 逐个考察 Server,如果 Server 的断路器被打开,则忽略,在不被忽略的 Server 中选择并发连接最低的 Server |
AvailabilityFilteringRule | 可用过滤测试 | 过滤掉一直连接失败,并被标记未 circuit tripped(即不可用) 的 Server,过滤掉高并发的 Server |
ResponseTimeWeightedRule | 响应时间加权策略 | 根据 Server 的响应时间分配权重,响应时间越长,权重越低,被选择到的几率就越低 |
ZoneAvoidanceRule | 区域权衡策略 | 综合判断 Server 所在区域的性能和 Server 的可用性轮询选择 Server,并判定一个 AWS Zone 的运行性能是否可用,剔除不可用的 Zone 中的所有 Server |
Ribbon 默认的负载均衡策略是轮询策略。
解决项目问题,由于是单应用调用,使用自定义负载均衡调用:
public class LoadBalancerRule extends AbstractLoadBalancerRule {
private static int index = 0;
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
@Override
public Server choose(Object o) {
ILoadBalancer loadBalancer = getLoadBalancer();
if (loadBalancer == null){
return null;
}
List<Server> servers = loadBalancer.getAllServers();
// 修改server的host地址,将本机地址修改为zk地址
for (Server server : servers) {
server.setHost("host");
}
Server server = servers.get(index % servers.size());
index++;
return server;
}
}
修复完成。