Ribbon负载均衡

因为在导入Eureka客户端依赖的时候,也会一并加载Ribbon的依赖,所以无需重新添加依赖

第一步:在服务消费方注入RestTemplate时添加LoadBalanced注解

package com.company;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@EnableDiscoveryClient
@SpringBootApplication
public class ConsumerApplication {

public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class);
}

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

第二步:改变使用服务ID的方式。这样会在这个注入的RestTemplate对象上添加拦截器,拦截器的名称叫LoadBalancerInterceptor,在使用的时候就很方便了。

package com.company.controller;

import com.company.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
@RequestMapping("/consumer")
public class ConsumerController {

@Autowired
private RestTemplate template;

@Autowired
private DiscoveryClient client;//ureka客户端

@GetMapping("/{id}")
public User getUserById(@PathVariable("id")Long id){
     //url变量中的user-service就是服务id
String url="http://user-service/user/"+id;
return template.getForObject(url,User.class);
}
}

拦截器

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.cloud.client.loadbalancer;

import java.io.IOException;
import java.net.URI;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.Assert;

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(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
URI originalUri = request.getURI();
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方法,将服务ID替换为IP:端口

追踪this.getServer(loadBalance,hint)追到BaseLoadBalancer

 

  

  

 

 可以看到默认使用的是轮询,debug的结果也是如此。

看一下自带的轮询规则实现类

可以通过配置来修改轮询规则,在服务消费方application.yaml文件添加

user-service:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
#格式是:{服务名称}.ribbon.NFLoadBalancerRuleClassName,值就是IRule的实现类。
posted @ 2020-03-27 16:13  荒野猛兽  阅读(203)  评论(0编辑  收藏  举报