Eureka的负载均衡Ribbon学习笔记(二)

Netflix Ribbon、Spring Cloud Netflix Ribbon、应用服务这三者之间的关系以及核心入口如下所示:

Netflix Ribbon 基本架构

作为一款客户端负载均衡工具,要做的事情无非就是两件:第一件事情是获取注册中心中的服务器列表;第二件事情是在这个服务列表中选择一个服务进行调用。针对这两个问题,Netflix Ribbon 提供了自身的一套基本架构,并抽象了一批核心类:

Netflix Ribbon 的核心接口 ILoadBalancer 就是围绕着上述两个问题来设计的

ILoadBalancer 代码如下:

public interface ILoadBalancer {

  //添加后端服务

  public void addServers(List<Server> newServers);


  //选择一个后端服务

  public Server chooseServer(Object key); 


	//标记一个服务不可用

  public void markServerDown(Server server);


	//获取当前可用的服务列表

  public List<Server> getReachableServers();


	//获取所有后端服务列表

   public List<Server> getAllServers();

}

负载均衡的核心功能基本都由BaseLoadBalancer这个类来实现,BaseLoadBalancer 包含的作为一个负载均衡器应该具备的一些核心组件,比较重要的有以下三个:

1.IRule

IRule接口是对负载均衡的一种抽象,可以实现这个接口来实现负载均衡的各种算法

public interface IRule{

// 核心方法
    public Server choose(Object key);
    
    public void setLoadBalancer(ILoadBalancer lb);
    
    public ILoadBalancer getLoadBalancer();    
}

 

2.IPing

IPing 接口判断目标服务是否存活,定义如下

//定义我们如何“ ping”服务器以检查其是否存在的接口
public interface IPing {
    
    //检查给定Server是否为“活动”,即在负载平衡时应被视为候选Server

    public boolean isAlive(Server server);
}

只有一个isAlice()方法,通过ping来测试目标服务器是否可以用。

3.LoadBalancerStatsstats 统计

记录统计负载均衡实时运行信息数据,来为负载均衡策略做数据支撑。

BaseLoadBancer内部维护这AllServerList和UpServerList两个线程安全的列表,所以对ILoadBance的addServers、getReachableServers、getAllServers\接口的方法而言主要是维护和管理者两个列表.

public void addServers(List<Server> newServers) {

        if (newServers != null && newServers.size() > 0) {

            try {

                ArrayList<Server> newList = new ArrayList<Server>();

                newList.addAll(allServerList);

                newList.addAll(newServers);

                setServersList(newList);

            } catch (Exception e) {

                logger.error("LoadBalancer [{}]: Exception while adding Servers", name, e);

            }

        }

}

处理过程是将原来的服务实例列表allServerList和新增加的服务实例列表newServers都合并到newList列表里面。再调用setServersList方法覆盖原有的服务实例列表。

 

Netflix Ribbon 中的负载均衡策略

负载均衡算法可以分成两大类,即静态负载均衡算法和动态负载均衡算法。静态负载均衡算法比较容易理解和实现,典型的包括随机(Random)、轮询(Round Robin)和加权轮询(Weighted Round Robin)算法等。所有涉及权重的静态算法都可以转变为动态算法,因为权重可以在运行过程中动态更新

动态策略主要有:

1.BestAvailableRule 策略

选择活跃请求数量最小的服务器;

2.WeightedResponseTimeRule 策略

响应时间越长,动态分配的权重越小。权重计算依赖于ILoadBalancer 接口中的LoadBalancerStats为每个服务更新权重。

3.AvailabilityFilteringRule 策略

通过LoadBalancerStats 记录服务器的运行状态,过滤掉一直处于连接失败,一直处于高并发状态的服务器。

@LoadBalanced 一个注解是怎样实现负载均衡

在 Spring Cloud Netflix Ribbon 中存在一个自动配置类——LoadBalancerAutoConfiguration 类。在该类中,维护着一个被 @LoadBalanced 修饰的 RestTemplate 对象的列表。在初始化的过程中,对于所有被 @LoadBalanced 注解修饰的 RestTemplate,调用 RestTemplateCustomizer 的 customize 方法进行定制化,该定制化的过程就是对目标 RestTemplate 增加拦截器 LoadBalancerInterceptor,如下所示:

public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
        URI originalUri = request.getURI();
        String serviceName = originalUri.getHost();
        Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
        return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
    }

拦截方法调用了LoadBalancerClient的execute方法完成对负载均衡的执行。

LoadBalancerClient接口代码如下:

public interface LoadBalancerClient extends ServiceInstanceChooser {
    <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;

    <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException;

    URI reconstructURI(ServiceInstance instance, URI original);
}

 对于负载均衡重点是choose方法,如下两个就是实现了LoadBalancerClient接口的负载均衡

RibbonLoadBalancerClient类实现choose方法代码如下
    public ServiceInstance choose(String serviceId) {
        return this.choose(serviceId, (Object)null);
    }

    public ServiceInstance choose(String serviceId, Object hint) {
        Server server = this.getServer(this.getLoadBalancer(serviceId), hint);
        return server == null ? null : new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
    }

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值