SpringCloud实践系列:Ribbon负载均衡

2023-03-08  本文已影响0人  分布式与微服务

一、概述

1.1、什么是Ribbon

Ribbon是负载均衡器,用于解决服务集群的负载均衡

1.2、常见负载均衡

1.3、Ribbon工作流程

二、快速使用

```
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
    <version>2.2.0.RELEASE</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-dependencies</artifactId>
    <version>Hoxton.RELEASE</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

```

三、源码简单追踪

3.1、源码简单追踪

LoadBalancerAutoConfiguration类中有个ribbonInterceptor方法,该方法调了LoadBalancerInterceptor类

public class LoadBalancerAutoConfiguration {
    ......
    static class LoadBalancerInterceptorConfig {
        ......
        @Bean
        public LoadBalancerInterceptor ribbonInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) {
            return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
        }
        ......
    }    
}

LoadBalancerInterceptor类中有个关键的方法intercept,调用RibbonLoadBalancerClient的execute方法,获取实例列表

public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
    ......

    public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
        // 获得url
        URI originalUri = request.getURI();
        // 拿到serviceName
        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));
    }
}

RibbonLoadBalancerClient类的execute方法中,获取实例列表,实现负载均衡

public class RibbonLoadBalancerClient implements LoadBalancerClient {
    public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
        // 获取实例列表(先从本地缓存取,没有则从注册中心取)
        ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId);
        // 实现负载均衡(选取负载均衡策略)
        Server server = this.getServer(loadBalancer, hint);
        if (server == null) {
            throw new IllegalStateException("No instances available for " + serviceId);
        } else {
            RibbonLoadBalancerClient.RibbonServer ribbonServer = new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
            return this.execute(serviceId, (ServiceInstance)ribbonServer, (LoadBalancerRequest)request);
        }
    }
}

3.2、Ribbon核心组件

接口 作用 默认值
IClientConfig 读取配置 DefaultClientConfigImpl
IRule 负载均衡规则,选择实例 ZoneAvoidanceRule
IPing 筛选掉ping不通的实例 DummyPing
ServerList 交给Ribbon的实例列表 Ribbon:ConfigurationBasedServerList Spring Cloud Alibaba:NacosServerList
ServerListFilter 过滤掉不符合条件的实例 ZonePreferenceServerListFilter
ILoadBalance Ribbon的入口 ZoneAwareLoadBalance
ServerListUpdater 更新交给Ribbon的List的策略 PollingServerListUpdater

四、负载均衡策略

4.1、内置的负载均衡策略

Ribbon核心组件IRule: 根据特定算法从服务列表中选取一个需要访问的服务

IRule是一个接口,有7个自带的实现类,可以实现不同的负载均衡算法规则

规则名称 特点
AvailabilityFilteringRule 过滤掉一直连接失败的被标记为circuit tripped的后端Server,并 过滤掉那些高并发的后端Server或者使用一个AvailabilityPredicate 来包含过滤server的逻辑,其实就是检查status里记录的各个server 的运行状态
BestAvailableRule 选择一个最小的并发请求的server,逐个考察server, 如果Server被tripped了,则跳过
RandomRule 随机选择一个Server
ResponseTimeWeightedRule 已废弃,作用同WeightedResponseTimeRule
WeightedResponseTimeRule 根据响应时间加权,响应时间越长,权重越小,被选中的可能性越低
RetryRule 对选定的负载均衡策略加上重试机制,在一个配置时间段内当 选择Server不成功,则一直尝试使用subRule的方式选择一个 可用的Server
RoundRobinRule 轮询选择,轮询index,选择index对应位置的Server
ZoneAvoidanceRule(默认) 默认的负载均衡策略,即复合判断Server所在区域的性能和Server的可用性 选择Server,在没有区域的环境下,类似于轮询(RandomRule)【优中选优,再轮询】

4.2、切换ribbon负载均衡策略

4.3、自定义策略(使用Nacos权重)

直接在页面上修改权重,是无效的。因为负载均衡中引入了ribbon,没有改ribbon配置,还是使用的ribbon的默认负载均衡策略。

使用nacos的权重,需要自定义负载均衡策略

*   在代码中配置

    ```
    spring:
      application:
        name: cloud-goods # 服务名
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848 # 指定nacos-server的地址
            username: nacos
            password: nacos
            weight: 10
    server:
      port: 9001
    
    ```
上一篇 下一篇

猜你喜欢

热点阅读