SpringCloud那些事-Ribbon

2019-12-02  本文已影响0人  Dane_404

目前主流的负载方案有两种:一种是集中式负载均衡,在消费者和服务者提供中间使用独立的代理方式进行负载,比如 Nginx,另一种就是客户端自己做负载均衡,Ribbon 就是其中一种。

使用 Ribbon

在 Eureka 的案例中,消费者 consumer 模块需要使用 DiscoveryClient 来获取服务实例信息,然后获取ip和端口来访问:

@Autowired
private DiscoveryClient discoveryClient;

@GetMapping("/callhello")
public String callHello(){

    List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
    ServiceInstance instance = instances.get(0);
    String url = "http://"+instance.getHost()+":"+instance.getPort()+"/user/hello";
    System.out.println(url);
   return restTemplate.getForObject(url,String.class);
}

这里有个问题,实际开发中,user-service 往往会开启很多个集群,这个时候我们获取了很多个实例,那么到底用哪个?一般情况下,我们需要编写均衡算法,而 Ribbon 已经帮我们实现了:

首先修改 RestConfig ,加入 @LoadBalanced 注解:

@Configuration
public class RestConfig {

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

修改 ConsumeController ,把 ip 和 端口替换成服务名就好了,这样就完成了。

@RestController
public class ConsumeController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/callhello")
    public String callHello(){
        String url = "http://user-service/user/hello";
       return restTemplate.getForObject(url,String.class);
    }
}

Ribbon 负载均衡策略

Ribbon 默认的负载均衡策略是轮询,修改均衡负载策略,也是在消费者 consume 配置加入:

user-service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule

然后测试,我注册了两个 user-service,一个端口 8081,一个是 8083。

@SpringBootTest
class ConsumeApplicationTests {

    @Autowired
    RibbonLoadBalancerClient client;

    @Test
    void contextLoads() {
        for (int i = 0; i < 100; i++) {
            ServiceInstance instance = this.client.choose("user-service");
            System.out.println(instance.getHost() + ":" + instance.getPort());
        }
    }

}

测试看到变成了随机了:


image.png

如果想自定义负载策略,可以实现 IRule ,Ribbon 的负载均衡策略有:

Ribbon 重试机制

由于 Eureka 是基于 AP 原则构建的,牺牲了数据的一致性,每个 Eureka 服务都会保存注册的服务信息,当注册的客户端与 Eureka 心跳无法保持时,有可能是网络原因,也有可能是服务挂了,在这种情况下,Eureka 还会在一段时间内保存注册信息,这个时候客户端就有可能拿到已经挂掉的服务信息,也就是 Ribbon 拿到了失效的服务信息,这样就导致请求失败了。Ribbon 重试机制可以解决这问题。

使用 RetryRule 重试
最简单的就是利用 Ribbon 自带的重试策略:

user-service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RetryRule

使用 Spring Retry 重试
添加 Spring Retry 依赖:

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

配置重试信息:

#当前实例的重试次数
user-service.ribbon.maxAutoRetries = 1
#切换实例的重试次数
user-service.ribbon.maxAutoRetriesNextServer = 1
#对所以操作请求都进行重试
user-service.ribbon.okToRetryOnAllOperations = true
上一篇下一篇

猜你喜欢

热点阅读