05-详解调用服务时负载均衡的配置及其原理

负载均衡

负载均衡的原理(通用)

@LoadBalanced注解用来拦截它所标记的RestTemplate发起的http请求, 底层是利用了一个名为Ribbon的组件来实现负载均衡功能(Cloud高版本已经弃用)

在这里插入图片描述

LoadBalancerInterceptor的intercept方法会对RestTemplate的请求进行拦截

public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
   
    private LoadBalancerClient loadBalancer;
    private LoadBalancerRequestFactory requestFactory;

    public LoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) {
   
        this.loadBalancer = loadBalancer;
        this.requestFactory = requestFactory;
    }

    public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
   
        this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
    }

    public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
   
        // 获取请求uri,如http://userservice/user/1
        URI originalUri = request.getURI()
        // 获取uri路径的主机名,其实就是服务名称userservice
        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 <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
   
    // 根据服务名称得到去Eureka服务端中获取服务的实例地址列表并保存DynamicServerListLoadBalancer到的allServeList属性当中
    ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId);
    // 利用内置的负载均衡算法,从服务的实例地址列表中选择一个实例地址
    Server server = this.getServer(loadBalancer, hint);
    if (server == null) {
   
        throw new IllegalStateException("No instances available for " + serviceId);
    } else {
   
        RibbonServer ribbonServer = new RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
        return this.execute(serviceId, (ServiceInstance)ribbonServer, (LoadBalancerRequest)request);
    }
}

负载均衡规则IRule: RibbonLoadBalancerClient的getServer方法最终调用父类BaseLoadBalancer的chooseServer方法

public class BaseLoadBalancer extends AbstractLoadBalancer implements PrimeConnectionListener, IClientConfigAware {
   
    private static Logger logger = LoggerFactory.getLogger(BaseLoadBalancer.class);
    // IRule的实现类不同表示负载均衡的策略不同,RoundRobinRule表示轮循调度
    private static final IRule DEFAULT_RULE = new RoundRobinRule();
    private static final BaseLoadBalancer.SerialPingStrategy DEFAULT_PING_STRATEGY = new BaseLoadBalancer.SerialPingStrategy((SyntheticClass_1)null);
    private static final String DEFAULT_NAME = "default";
    private static final String PREFIX = "LoadBalancer_";
    protected IRule rule;
    protected IPingStrategy pingStrategy;
    protected IPing ping;

    public Server chooseServer(Object key) {
   
        if (this.counter == null) {
   
            this.counter = this.createCounter();
        }

        this.counter.increment();
        if (this.rule == null) {
   
            return null;
        } else {
   
            try {
   
                // 选出一个负载均衡的策略
                return this.rule.choose(key);
            } catch (Exception var3) {
   
                logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", new Object[]{
   this.name, key, var3});
                return null;
            }
        }
    }
}

负载均衡策略

负载均衡的规则都定义在IRule接口中,而IRule有很多不同的实现类,默认的实现就是ZoneAvoidanceRule表示区域内轮询方案

在这里插入图片描述

在这里插入图片描述

自定义负载均衡规则

编程方式(全局):在order-service模块中启动类中注册一个IRule类型的Bean到Spring容器中,对order-service服务想要调用的微服务均有效

  • 优缺点: 配置灵活但修改时需要重新打包发布
@Bean
public IRule randomRule(){
   
    // 创建负载均衡的实现类对象
    return new RandomRule();
}

配置文件方式(局部):在order-service模块的配置文件中添加userservice.ribbon.NFLoadBalancerRuleClassName配置,只针对调用的某个微服务有效

  • 优缺点: 直观方便无需重新打包发布,但是无法做全局配置,只能指定调用的某一个微服务的负载均衡规则
userservice: # 给user-service服务添加负载均衡规则
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则

饥饿加载(通用)

Ribbon默认是采用懒加载,只有在用户第一次访问时才会创建LoadBalanceClient负载均衡类做服务拉取的动作,这样用户第一次访问时就大大增加了请求时间

采用饥饿加载是在项目启动时就创建LoadBalanceClient负载均衡类加载指定的服务, 这样用户第一次访问时就大大缩短了请求时间

order-service模块的application.yml配置文件中添加新的配置属性ribbon.eager-load.enabled/clients

ribbon:
  eager-load:
    enabled: true # 开启饥饿加载
    # 指定对userservice单个服务进行饥饿加载
    clients: userservice  
    
    # 指定对多个服务进行饥饿加载
    clients: 
    	- userservice
    	- xxxservice

相关推荐

  1. 负载均衡原理及其算法详解

    2023-12-14 14:40:04       28 阅读
  2. nginx 负载均衡配置详解

    2023-12-14 14:40:04       34 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2023-12-14 14:40:04       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2023-12-14 14:40:04       106 阅读
  3. 在Django里面运行非项目文件

    2023-12-14 14:40:04       87 阅读
  4. Python语言-面向对象

    2023-12-14 14:40:04       96 阅读

热门阅读

  1. 【已解决】No module named ‘sklearn‘

    2023-12-14 14:40:04       65 阅读
  2. HTTPS加密协议:保护你的网络安全

    2023-12-14 14:40:04       60 阅读
  3. LeetCode 每日一题 Day 11||贪心

    2023-12-14 14:40:04       61 阅读
  4. Android Kotlin Viewbinding封装

    2023-12-14 14:40:04       52 阅读
  5. android 逆向工程(待续)

    2023-12-14 14:40:04       59 阅读
  6. PHP中如何防止SQL注入攻击?

    2023-12-14 14:40:04       64 阅读
  7. 如何使用std::function 和std::bind取代继承

    2023-12-14 14:40:04       52 阅读
  8. 计算机网络链路层(期末、考研)

    2023-12-14 14:40:04       76 阅读