Netflix Ribbon - @LoadBalanced注解

113 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。


定时判断服务器是否存活

负载均衡器里,就是ILoadBalancer里,有IRule负责负载均衡的规则,选择一个服务器;还有一个IPing负责定时ping每个服务器,判断其是否存活

ILoadBalancer balancer = new BaseLoadBalancer();

List<Server> serverList = Arrays.asList(8080, 8081).stream().map(port -> new Server(
        "localhost", port)).collect(Collectors.toList());

balancer.addServers(serverList);

// http://localhost:8080/
// 每隔1秒去请求【http://localhost:8080/】地址
((BaseLoadBalancer) balancer).setPing(new PingUrl());
((BaseLoadBalancer) balancer).setPingInterval(1);

Thread.sleep(5000);

for (int i = 0; i < 10; i++) {
    Server server = balancer.chooseServer(null);
    log.info("server : {}", server);
}

可以自定义一个Ping组件,结合业务逻辑实现具体的服务器判活策略。

class MyPing implements IPing{

    @Override
    public boolean isAlive(Server server) {
        return false;
    }
}

spring cloud netflix ribbon的使用以及工作原理

在一个服务里调用另外一个服务。

@LoadBalanced
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}

用RestTemplate来访问别的服务,RestTemplate,就是一个http请求的组件,本身没有负载均衡的功能。用@LoadBalanced注解之后,默认底层会用ribbon实现负载均衡。

RestTemplate底层会去基于ribbon来对一个服务的服务实例列表(List<Server>)进行负载均衡式的访问。ribbon和eureka整合,在ribbon里,从eureka client拿到服务实例列表(List<Server>

请求一个服务的时候,就找服务对应的服务实例列表(List<Server>),round robin轮询一下

Spring-Cloud-Netflix-Ribbon流程图.png

装配自定义的IRule和IPing

@Configuration
public class RibbonConfigForServiceB {

    @Bean
    public IRule iRuleForServiceB(){
        return new IRule() {
            @Override
            public Server choose(Object o) {
                return null;
            }

            @Override
            public void setLoadBalancer(ILoadBalancer iLoadBalancer) {

            }

            @Override
            public ILoadBalancer getLoadBalancer() {
                return null;
            }
        };
    }

    @Bean
    public IPing iPingForServiceB(){
        return new IPing() {
            @Override
            public boolean isAlive(Server server) {
                return false;
            }
        };
    }
}
@RibbonClient(value = "ServiceB", configuration = RibbonConfigForServiceB.class)
public class RibbonClientForServiceB {
}

Ribbon 源码流程图

Spring-Cloud-Netflix-Ribbon源码流程图.png

RestTemplate请求:http://ServiceA/product。

ServiceA是一个服务名称,不是ip地址和主机名,也没有端口号,RestTemplate无法请求。

ILoadBalancer里面包含IRule和IPing。

IRule负责从server list中根据负载均衡的算法,选择出来某个server。

IPing定时发送请求获取服务实例的状态。

服务实例通过Eureka模块获取,通过IRule策略选择确定的服务实例供服务调用者使用。

Ribbon源码 - @LoadBalanced

@LoadBalanced

将RestTemplate标志为底层采用LoadBalancerClient来执行实际的http请求,支持负载均衡。

根据@LoadBalanced 所在jar包的META-INF/spring.factories文件的自动配置机制找到LoadBalancerAutoConfiguration.class

restTemplates

@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();

SmartInitializingSingleton

SmartInitializingSingleton.afterSingletonsInstantiated()方法,就是在系统启动的时候,在spring singleton bean实例化完之后执行的。

遍历容器内所有的RestTemplate,用所有的Customizer定制所有的RestTemplate

public interface SmartInitializingSingleton {
    void afterSingletonsInstantiated();
}

RestTemplateCustomizer

为RestTemplate设置了一个拦截器。

@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
      final LoadBalancerInterceptor loadBalancerInterceptor) {
   return restTemplate -> {
      List<ClientHttpRequestInterceptor> list = new ArrayList<>(
            restTemplate.getInterceptors());
      list.add(loadBalancerInterceptor);
      restTemplate.setInterceptors(list);
   };
}

LoadBalancerInterceptor

@Bean
public LoadBalancerInterceptor ribbonInterceptor(
      LoadBalancerClient loadBalancerClient,
      LoadBalancerRequestFactory requestFactory) {
   return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}

ClientHttpRequestInterceptor拦截器

LoadBalancerInterceptor implements ClientHttpRequestInterceptor