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)
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表示区域内轮询方案
自定义负载均衡规则
编程方式(全局)
: 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