美文网首页
SpringCloud那些事-Ribbon

SpringCloud那些事-Ribbon

作者: Dane_404 | 来源:发表于2019-12-02 21:09 被阅读0次

    目前主流的负载方案有两种:一种是集中式负载均衡,在消费者和服务者提供中间使用独立的代理方式进行负载,比如 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 的负载均衡策略有:

    • BestAvailabl:选择一个最小的并发请求的 Server,逐个考察 Server,如果 Server 被标记为错误则跳过,然后在选择 ActiveRequestCount 中最小的;
    • AvailabilityFilteringRule:过滤掉那些一直连接失败的且被标记为 circuit tripped 的后端 Server ,并过滤掉那些高并发的;
    • ZoneAvoidanceRule:根据运行性能和连接数选择 Server;
    • RandomRule:随机选择一个 Server;
    • RoundRobinRule:轮询选择;
    • RetryRule:对选定的负载均衡策略机上重试机制;
    • WeightedResponseTimeRule:根据响应时间分配一个weight,响应时间越长,weight越小,被选中的可能性越低。

    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
    

    相关文章

      网友评论

          本文标题:SpringCloud那些事-Ribbon

          本文链接:https://www.haomeiwen.com/subject/lgufgctx.html