Spring Cloud服务调用负载均衡是Ribbon提供的,在笔记(二)、(三)中我们使用了RestTemplate和Feign方式来做远程服务调用,RestTemplate方式我们还没引入负载均衡,而Feign方式默认就有了负载均衡,feign其实不是做负载均衡的,负载均衡是ribbon的功能,feign只是集成了ribbon而已,但是负载均衡的功能还是feign内置的ribbon在做,而不是feign。feign的作用的替代RestTemplate,性能比较低,但是可以使代码可读性很强。
该笔记在如下笔记的基础上进行:
- Spring Cloud入门笔记(一) Eureka 服务注册中心的搭建
- Spring Cloud入门笔记(二) 服务注册与消费
- Spring Cloud入门笔记(三) 声明式服务调用Feign的使用
在开始之前我门需要做如下准备工作:
参考前面的笔记来创建一个名为cloud的maven空项目,并在项目里面创建各Module子项目,一个Eureka服务注册中、一个Provider服务提供者(这里先创建一个,到时候通过运行jar包来启动多个不同服务端口的Provider)、一个Consumer服务消费者。创建好后项目结构如下:
先启动Eureka,然后在Provider中提供一个/sayHello接口,代码如下:
@RestController
class TestController {
@Value("${server.port}") //从配置文件中读取端口号
Integer port;
@RequestMapping("/sayHello")
public String sayHello(){
return "hello:"+port;
}
}
为了方便我们测试负载均衡的功能,每次请求到服务提供者都会输出自己的端口号。接下我们把Provider打包成jar包:
打包成功后在项目文件下的target目录会出现如下jar包:
接下来我们用三个cmd命令窗口切换到privader项目的target文件夹下分别运行:
cmd窗口1:java -jar provider-0.0.1-SNAPSHOT.jar --server.port=8001
cmd窗口2:java -jar provider-0.0.1-SNAPSHOT.jar --server.port=8002
cmd窗口3:java -jar provider-0.0.1-SNAPSHOT.jar --server.port=8003
这样我们就启动了三个服务提供者。 也可以同过Eureka可是化界面看到这三个服务已经注册到服务注册中心:
Ribbon 负载均衡
接下来开始使用@LoadBalanced注解来是实现负载均衡。我们先创建一个配置类,然后只需要在RestTemplate的bena上再添加一个@LoadBalanced注解即可或者在启动类中添加也行,代码如下:
@Configuration
public class ConsumerConfiguration {
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
}
然后再控制中注入RestTemplate来请求服务,代码如下:
@RestController
public class TestController {
@Autowired
RestTemplate restTemplate;
@RequestMapping("/sayHello")
public String sayHello(){
String result = restTemplate.getForObject("http://provider/sayHello",String.class);
System.out.println(result);
return result;
}
}
请求连接就用privider的配置的spring.application.name=Privider代替不不区分大小写,然后我们多请求几次接口,并查看日志输出情况:
可以看得出来我们的每一个请求Ribbon都会自动的帮我们选择一个远程provider来进行请求,而且还是轮询的,这就是负载均衡的一种轮询策略,接下来我们将记录一下Ribbon的几种负载均衡策略,以及指定使用哪一种策略。
负载均衡策略
通过上面这个小例子,了解到了默认的负载均衡策略实际上是轮询策略,那么还有哪几种策略呢,以及证明使用呢,请看下面的记录:
- RandomRule 表示随机策略
- RoundRobinRule 表示轮询策略
- AvailabilityFilteringRule: 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,以及并发的连接数量
超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问; - WeightedResponseTimeRule 表示加权策略(即将过期,功能和 ResponseTimeWeightedRule 一致)
- ResponseTimeWeightedRule 也是加权,它是根据每一个 Server 的平均响应时间动态加权,响应时间越长,权重越小,处理请求的机会也越小
- RetryRule 表示一个具备重试功能的负载均衡策略,内部默认使用了 RoundRobinRule 这个内部也可以自己传其他的负载均衡策略进去
- BestAvailableRule 策略表示使用并发数最小的服务
指定使用负载均衡策略
在刚才我们建立的ConsumerConfiguration配置类上提供对应负载均衡的IRule 实例即可,代码如下:
@Configuration
public class ConsumerConfiguration {
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
@Bean
IRule iRule(){
return new RandomRule();
}
}
这就代表使用了 RandomRule(随机策略),其他地方不变我们重启consumer项目继续多请求几次接口查看日志输出情况:
可以看出来,请求的服务都是随机的,那么使用其它策略也是一样的举一反三嘛。
Feign方式负载均衡
在开头也说了,feign内置的ribbon并默认开启了负载均衡,为了方便我直接在上面的这个项目进行改动,首先eureka和provider项目不变,在consumer项目中引入openfeign依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
然后在comsumer项目中的启动类上加上@EnableFeignClients来开启Feign,代码如下:
@SpringBootApplication
@EnableFeignClients
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
并添加一个名为RequestService的接口,并编辑如下
@FeignClient("provider")
public interface RequestService {
String sayHello();
}
我们添加了FeignClient("provider")注解,用来绑定我们的服务。
然后在控制类中注入这个接口并调用即可,代码如下:
@RestController
public class TestController {
@Autowired
RequestService requestService;
@RequestMapping("/sayHello")
public String sayHello(){
String result = requestService.sayHello();
System.out.println(result);
return result;
}
}
然后重启Consumer项目在浏览器中多请求几次/sayHello接口并查看日志输出:
可以看出实现了负载均衡,是随机策略,因为我们刚才在ConsumerConfiguration配置类中指定了,所以Feign方式的负载均衡指定的方式和我们刚才在上面说的那种指定方式是一致的,因为负载均衡的实现是Ribbon而不是Feign,是Feingn使用了它而已!