1. 负载均衡Ribbon
在刚才的案例中,我们启动了一个zwwnb-provider,然后通过DiscoveryClient来获取服务实例信息,然后获取ip和端口来访问。
但是实际环境中,我们往往会开启很多个zwwnb-provider的集群。此时我们获取的服务列表中就会有多个,到底该访问哪一个呢?
一般这种情况下我们就需要编写负载均衡算法,在多个实例列表中进行选择。
不过Eureka中已经帮我们集成了负载均衡组件:Ribbon,简单修改代码即可使用。
什么是Ribbon:
接下来,我们就来使用Ribbon实现负载均衡。
2. 启动两个服务实例
首先参照zwwnb-eureka启动两个ProviderApplication实例,一个8081,一个8082。
Eureka监控面板:
3. 开启负载均衡
因为Eureka中已经集成了Ribbon,所以我们无需引入新的依赖,直接修改代码。
修改zwwnb-user的引导类,在RestTemplate的配置方法上添加@LoadBalanced
注解:
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
修改调用方式,不再手动获取ip和端口,而是直接通过服务名称调用:
@Controller
@RequestMapping("test/user")
public class UserController {
@Autowired
private RestTemplate restTemplate;
/* @Autowired
private DiscoveryClient discoveryClient; // eureka客户端,可以获取到eureka中服务的信息*/
@GetMapping
@ResponseBody
public User queryUserById(@RequestParam("id") Long id){
/*// 根据服务名称,获取服务实例。有可能是集群,所以是service实例集合
List<ServiceInstance> instances = discoveryClient.getInstances("provider-server");
// 因为只有一个Service-provider。所以获取第一个实例
ServiceInstance instance = instances.get(0);
// 获取ip和端口信息,拼接成服务地址
String baseUrl = "http://" + instance.getHost() + ":" + instance.getPort() + "/user/" + id;
User user = this.restTemplate.getForObject(baseUrl, User.class);*/
return this.restTemplate.getForObject("http://provider-service/user/" + id, User.class);
}
}
访问页面,查看结果:
4. 负载均衡策略
Ribbon默认的负载均衡策略是简单的轮询,我们可以测试一下:
编写测试类,在刚才的源码中我们看到拦截中是使用RibbonLoadBalanceClient来进行负载均衡的,其中有一个choose方法,找到choose方法的接口方法,是这样介绍的:
现在这个就是负载均衡获取实例的方法。
需要添加两个测试依赖才能进行测试:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>1.5.9.RELEASE</version>
<scope>test</scope>
</dependency>
我们注入这个类的对象,然后对其测试:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = UserApplication.class)
public class LoadBalanceTest {
@Autowired
private RibbonLoadBalancerClient client;
@Test
public void testLoadBalance(){
for (int i = 0; i < 100; i++) {
ServiceInstance instance = this.client.choose("provider-service");
System.out.println(instance.getHost() + ":" +instance.getPort());
}
}
}
结果:
符合了我们的预期推测,确实是轮询方式。
我们也可以修改负载均衡的策略:
SpringBoot帮我们提供了修改负载均衡规则的配置入口,在zwwnb-user的application.yml中添加配置:
server:
port: 8085
spring:
application:
name: user-service # 应用名称,注册到eureka后的服务名称
eureka:
client:
service-url: # EurekaServer地址,多个地址以','隔开
defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka
registry-fetch-interval-seconds: 5
provider-service: # 服务名
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
格式是:{服务名称}.ribbon.NFLoadBalancerRuleClassName
,值就是IRule的实现类。
再次测试,发现结果变成了随机:
完美!!!Ribbon负载均衡就到这了。