Ribbon使用及其客户端负载均衡实现原理分析

1、ribbon负载均衡测试

(1)consumer工程添加依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
        </dependency>

 说明:

①由于spring-cloud-starter-eureka已经依赖了spring-cloud-starter-ribbon,所以不用再添加spring-cloud-starter-ribbon依赖了   

②Spring cloud 引入ribbon 配合restTemplate 实现客户端负载均衡、此处需要引入Okhttp依赖 (也可以使用ApacheClient等其他远程调用技术)

(2)配置ribbon参数

#配置ribbon
ribbon: 
  MaxAutoRetries: 2 #最大重试次数,当Eureka中可以找到服务,但是连接不上时将会重试
  MaxAutoRetriesNextServer: 3 #切换实例的重试次数、高可用场景
  OkToRetryOnAllOperation: false #对所有操作请求都进行重试,如果是get则可以,如果是post、put有重复提交的危险,建议设置为false
  ConnectTimeout: 5000 #请求连接的超时时间
  ReadTimeout: 6000 #请求处理的超时时间    

(3)定义RestTemplate

    @Bean
    @LoadBalanced //使用该注解表示实现客户端负载均衡
    public RestTemplate restTemplate(){
        return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
    }

(4)启动两各Producer工程,注意端口不同,注册到Eureka中

(5)测试代码

@SpringBootTest
@RunWith(SpringRunner.class)
public class TestRibbon {
    
    @Autowired
    private RestTemplate restTemplate;

    @Test
    public void testRibbon(){
        
        String serviceId = "Producer";
        for(int i=0;i<10;i++){
            //通过服务id调用
            ResponseEntity<User> user= restTemplate.getForEntity("http://"+serviceId+"/user/get/5a754adf6abb500ad05688d9", User.class);
            System.out.println(JSONObject.toJSONString(user));
        }
    }
}

2、客户端负载均衡实现原理

(1)区别服务端负载均衡和客户端负载均衡

向Nginx 、F5 等在请求发出之后,被负载均衡服务器拦截再分发到具体服务的方式是服务端负载均衡,而Ribbon是客户端先从Eureka Server获取服务列表,自己维护服务列表,根据负载均衡算法直接请求资源服务器的方式叫服务端负载均衡

(2)Ribbon 实现客户端负载均衡细节

在定义RestTempalte时加@LoadBalanced注解后、restTemplate会走LoadbanlanceInterceptor拦截器 

LoadbanlanceInterceptor.class

@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) throws IOException {
  final URI originalUri = request.getURI();
      String serviceName = originalUri.getHost();
      Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
      //调用RibbonLoadBalancerClient
      return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
}
 


RibbonLoadBalancerClient.class
@Override
    public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
        //获取服务列表
        ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
        //根据负载均衡算法从服务列表中获取本次调用服务的地址
        Server server = getServer(loadBalancer);
        if (server == null) {
            throw new IllegalStateException("No instances available for " + serviceId);
        }
        RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
                serviceId), serverIntrospector(serviceId).getMetadata(server));
        return execute(serviceId, ribbonServer, request);
    }
原文地址:https://www.cnblogs.com/dehigher/p/10134524.html