05-Detailed explanation of load balancing configuration and principles when calling services

load balancing

负载均衡的原理(通用)

@LoadBalanced注解 is used to intercept http requests initiated by RestTemplate that it marks. The bottom layer uses a component named Ribbon to implement the load balancing function ( Cloud high version has been deprecated)

Insert image description here

LoadBalancerInterceptor的intercept方法Will intercept RestTemplate requests

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方法Obtain the service instance address list based on the service name, and then use the load balancing algorithm to obtain a real service address information

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: The getServer method of RibbonLoadBalancerClient finally calls the chooseServer method of the parent class BaseLoadBalancer

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;
            }
        }
    }
}

负载均衡策略

Load balancing rules are defined in the IRule interface, and IRule has many different implementation classes. The default implementation isZoneAvoidanceRule表示区域内轮询方案

Insert image description here

Insert image description here

自定义负载均衡规则

编程方式(全局): Register an IRule type Bean in the startup class in order-service模块 to the Spring container, which is valid for all microservices that order-service服务 wants to call< /span>

  • Advantages and Disadvantages: Flexible configuration but needs to be repackaged and released when modified
@Bean
public IRule randomRule(){
    
    
    // 创建负载均衡的实现类对象
    return new RandomRule();
}

配置文件方式(局部): Add configuration in the configuration file of order-service模块, which is only valid for a certain microservice calleduserservice.ribbon.NFLoadBalancerRuleClassName

  • Advantages and Disadvantages: Intuitive and convenient, there is no need to repackage and publish, but global configuration cannot be done, and the load balancing rules of a certain microservice can only be specified.
userservice: # 给user-service服务添加负载均衡规则
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则

饥饿加载(通用)

Ribbon默认是采用懒加载, only when the user visits for the first time 创建LoadBalanceClient负载均衡类做服务拉取的动作, which greatly increases the request time when the user visits for the first time

采用饥饿加载 is set when the project starts 创建LoadBalanceClient负载均衡类加载指定的服务, which greatly shortens the request time when the user visits for the first time

Add new configuration properties inorder-service模块’s application.yml configuration fileribbon.eager-load.enabled/clients

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

Guess you like

Origin blog.csdn.net/qq_57005976/article/details/134905387