美文网首页程序员
Spring Cloud — Ribbon 负载均衡

Spring Cloud — Ribbon 负载均衡

作者: 俞大仙_ | 来源:发表于2020-03-16 13:58 被阅读0次

    版本控制

    • Spring Cloud 基于 Hoxton.RELEASES
    • Spring Boot 基于 2.2.5.RELEASE

    介绍

    一般来说,为了服务的高可用,在生产环境中,每个微服务通常都会部署多个实例。因此服务消费者需要将请求合理的分摊到多个服务提供者实力上。Spring cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具

    Nginx & Ribbon

    Nginx

    Nginx是服务端负载均衡。Nginx存在于服务的前端。客户端所有的请求都会交给Nginx服务器,然后由Nginx实现请求的分发。属于服务端负载均衡。

    Ribbon

    Ribbon是客户端负载均衡。它可以存在于多个客户端中。在SpringCloud中,Ribbon可以配合Eureka使用,在调用接口时,会从Eureka Server中获取服务列表,并基于指定的负载策略请求其中的一个实例。

    LoadBalancerClient

    LoadBalancerClientRibbon的核心组件。它是定义客户端负载均衡的接口。

    • 定义了几个方法:
      • execute()方法:用于执行请求;
      • econstructURI()方法:重构URI。整合Eureka后可以直接通过服务名去访问其他服务,如:http://api/restTemplate/ 其中api是其他服务在Eureka中注册的服务名称,在实际调用的时候需要将服务名api转为换具体的IP和端口的形式;
    • 继承了ServiceInstanceChooser接口:
      • 定义了choose()方法,用来从LoadBalancer中获取指定服务的一个实例;
    • 实现类为RibbonLoadBalancerClient

    可以调用choose方法来获取服务实例:

    ServiceInstance instance = loadBalancerClient.choose("serviceId");
    

    RibbonLoadBalancerClientchoose()方法中,通过负载均衡器ILoadBalancer去获取实例信息:

        protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
            if (loadBalancer == null) {
                return null;
            }
            // 获取服务实例
            return loadBalancer.chooseServer(hint != null ? hint : "default");
        }
    

    ILoadBalancer

    定义负载均衡具体操作的接口。维护服务实例信息;

    public interface ILoadBalancer {
    
        /**
         * 初始化服务列表
         */
        public void addServers(List<Server> newServers);
        
        /**
         * 从负载均衡中获取一个服务实例
         */
        public Server chooseServer(Object key);
        
        /**
         * 标记指定服务已下线
         */
        public void markServerDown(Server server);
    
        /**
         * 获取可用的服务列表
         */
        public List<Server> getReachableServers();
    
        /**
         * 获取所有已知服务器,包括可用和不可用的
         */
        public List<Server> getAllServers();
    }
    

    IRule

    具体定义负载均衡策略的接口。ILoadBalancer会根据IRule的规则去选择一个符合条件的服务实例

    public interface IRule{
    
        public Server choose(Object key);
        
        public void setLoadBalancer(ILoadBalancer lb);
        
        public ILoadBalancer getLoadBalancer();    
    }
    

    IRule默认实现了一些策略,具体可以查看接口实现类:

    • RoundRobinRule:轮询方式(默认规则);
    • RandomRule:随机访问;
    • RetryRule:在轮询方式上加入重试机制;
    • BestAvailableRule:请求数最小的;
    • WeightedResponseTimeRule:根据响应时间加权
    • ...

    如果有特殊的需要可以自定义负载策略,只需要实现IRule`接口

    捋一捋

    整理一下负载均衡获取实例的流程:

    • loadBalancerClient调用choose方法;
    • ILoadBalancer调用chooseServer方法;
    • IRule调用choose方法;

    实战

    Ribbon的引入很简单,这里我们通过RestTemplate + Ribbon来实现服务的负载均衡。一个访问第三方RESTful API接口的网络请求框架,封装了常用的请求。首先创建一个Ribbon服务

    pom

        <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.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>
    

    yml文件

    server:
      port: 8081
    spring:
      application:
        name: ribbon
    eureka:
      instance:
        # 以IP地址注册到服务中心,相互注册使用IP地址
        prefer-ip-address: true
        instance-id: ${spring.cloud.client.ipaddress}:${server.port}
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/
    # 配置 Ribbon 饥饿加载
    ribbon:
      eager-load:
        enabled: true
        clients: api
    

    Ribbon默认是懒加载的,只有当第一次请求时才回去创建ILoadBalancer,这就导致第一次请求时消耗更多时间,可能会出现请求超时的情况。通过ribbon.eager-load.enabled=trueribbon.eager-load.clients=server1,server2的形式配置饥饿加载模式,在项目启动时就创建对应的ILoadBalancer

    config

    @Configuration
    public class RibbonConfig {
    
        /**
         * 通过RestTemplate来进行通信
         * 注解:@LoadBalanced 开启负载均衡
         */
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
        
        @Bean
        public IRule myRule() {
            // 随机方式,默认轮询:RoundRobinRule;也可以使用自己实现的
            return new RandomRule();
        }
    }
    

    通过@LoadBalanced注解表示在RestTemplate中使用Ribbon负载均衡;

    默认的负载策略为轮询,如果需要实现其他的负载策略,只需要引入对应的IRule实例;

    访问接口

    @RestController
    @RequestMapping("/ribbon")
    public class RibbonController {
    
        private final RestTemplate restTemplate;
    
        private final LoadBalancerClient loadBalancerClient;
    
        public RibbonController(RestTemplate restTemplate, LoadBalancerClient loadBalancerClient) {
            this.restTemplate = restTemplate;
            this.loadBalancerClient = loadBalancerClient;
        }
    
        /**
         * LoadBalancerClient 从 Eureka Client 获取服务注册列表信息的,并进行缓存
         * 调用choose()方法时,会根据负载策略选择一个实例
         */
        @GetMapping("/loadBalancer")
        public String loadBalancerTest() {
            ServiceInstance instance = loadBalancerClient.choose("api");
            return instance.getHost() + ":" + instance.getPort();
        }
    
        /**
         * 整合Eureka后可以直接通过微服务名称进行访问
         */
        @GetMapping("/restTemplate/{msg}")
        public String restTemplateTest(@PathVariable String msg) {
            return restTemplate.getForObject("http://api/api/restTemplate/" + msg, String.class);
        }
    }
    

    API服务

    新建一个API服务,注册到Eureka服务,创建对外接口类:

    @RestController
    @RequestMapping("/api")
    public class AipController {
    
        @Value("${server.port}")
        private String port;
    
        @GetMapping("/restTemplate/{msg}")
        public String forRestTemplate(@PathVariable String msg) {
            System.out.printf("get message %s with restTemplate\n", msg);
            return "[restTemplate] from port: " + port;
        }
    }
    

    测试

    启动Eureka服务,启动Ribbon服务,通过修改API服务端口号,多次启动服务。调用Ribbon服务的接口查看返回数据

    访问源码

    所有代码均上传至Github

    >>>>>> Ribbon 负载均衡 <<<<<<

    日常求赞

    创作不易,如果各位觉得有帮助,求点赞 支持


    求关注

    微信公众号: 俞大仙

    俞大仙

    相关文章

      网友评论

        本文标题:Spring Cloud — Ribbon 负载均衡

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