Robbin 是 Netflix 开发的实现客户端负载均衡的组件,通常和 Eureka 一起使用,前面的例子中 Eureka Consumer 已经使用了负载均衡
在前面的 Eureka 服务发现的基础上做一些修改
因为 Eureka 依赖已经包含了 Robbin,所以无需导入 Robbin
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
启动两个 Producer,只是 port 以及返回的内容不同
server.port=8762
@RequestMapping("/api")
public String index() {
return "Greetings from Eureka Producer 1!";
}
server.port=8763
@RequestMapping("/api")
public String index() {
return "Greetings from Eureka Producer 2!";
}
在 Consumer 加入 RestTemplate 的配置
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced // 实现 Ribbon 负载均衡的 RestTemplate
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public IRule loadbalanceRule(){
return new RandomRule(); // 随机策略
}
}
添加使用这个 RestTemplate 的接口
@RestController
public class Controller {
@Autowired
private LoadBalancerClient loadBalancer;
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private RestTemplate restTemplate; // 具有负载均衡的 restTemplate
@RequestMapping("/queryService")
public String query() {
List<ServiceInstance> instances = discoveryClient.getInstances("service-provider-1");
StringBuilder urls= new StringBuilder();
for(ServiceInstance instance : instances){
urls.append(instance.getHost()+":"+instance.getPort()).append(",");
}
return "service name : service-provider-1<br>" + "host : " + urls.toString();
}
@RequestMapping("/discover")
public Object discover() {
// 通过 LoadBalancerClient 获取 service-provider-1 服务的其中一个 host
// 可以看到有时返回 8762 端口,有时返回 8763 端口,这样就实现了负载均衡
return loadBalancer.choose("service-provider-1").getUri().toString();
}
@RequestMapping("/rest")
public String rest() {
// 这里直接使用注册在 Eureka 的 service id 也就是 service-provider-1
// 这样 RestTemplate 会自动实现负载均衡
String forObject = restTemplate.getForObject("http://service-provider-1/api", String.class);
return forObject;
}
}
Ribbon 的负载均衡策略可以用代码配置,也可以通过配置文件配置
@Bean
public IRule loadbalanceRule(){
return new RandomRule(); // 随机策略
}
@Configuration
@RibbonClient(name="service-provider-1",configuration=RestTemplateConfig.class)
public class NewRobbinConfig {
}
service-provider-1.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
Robbin 也可以和 Consul 集成,实际上前面的例子中 Consul Consumer 同样已经使用了负载均衡
在前面的 Consul 服务发现的基础上做一些修改
因为 Consul 依赖已经包含了 Ribbon,所以无需导入 Ribbon
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
启动两个 Producer,只是 port 以及返回的内容不同
# application.yml
server:
port: 8501
// Controller.java
@RequestMapping("/hello")
public String hello() {
return "consul-service-1 instance-1";
}
# application.yml
server:
port: 8502
@RequestMapping("/hello")
public String hello() {
return "consul-service-1 instance-2";
}
在 Consumer 端加入 RestTemplate 的配置
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced // 实现 Ribbon 负载均衡的 RestTemplate
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public IRule loadbalanceRule(){
return new RandomRule(); // 随机策略
}
}
添加使用这个 RestTemplate 的接口
public class Controller {
@Autowired
private LoadBalancerClient loadBalancer;
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private RestTemplate restTemplate; // 具有负载均衡的restTemplate
@RequestMapping("/services")
public Object services() {
// 获取 consul-service-1 服务的信息
// 这里会返回两个,因为有两个服务注册了这个名字
return discoveryClient.getInstances("consul-service-1");
}
@RequestMapping("/discover")
public Object discover() {
// 通过 LoadBalancerClient 获取 consul-service-1 服务的其中一个 host
// 可以看到有时返回 8501 端口,有时返回 8502 端口,这样就实现了负载均衡
return loadBalancer.choose("consul-service-1").getUri().toString();
}
@RequestMapping("/rest")
public String rest(){
// 这里直接使用注册在 Consul 的 service id 也就是 consul-service-1
// 这样 RestTemplate 会自动实现负载均衡
String forObject = restTemplate.getForObject("http://consul-service-1/hello", String.class);
return forObject;
}
}
Ribbon 的负载均衡策略可以用代码配置,也可以通过配置文件配置
@Bean
public IRule loadbalanceRule(){
return new RandomRule(); // 随机策略
}
@Configuration
@RibbonClient(name="consul-service-1",configuration=RestTemplateConfig.class)
public class NewRobbinConfig {
}
consul-service-1:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule