美文网首页
Ribbon使用心得

Ribbon使用心得

作者: 逍遥白亦 | 来源:发表于2020-12-24 22:12 被阅读0次

    Ribbon使用心得

    简单使用

    先整理思路,写一个生产端和一个消费端,启动两个生产端,然后消费端通过Ribbon的负载均衡功能访问生产端。

    生产端

    1. 引入依赖
    2. 写配置文件
    3. 启动类
    4. controller类

    项目结构

    整体项目结构如下图

    image

    引入依赖

    在父项目中引入依赖,参考前文Nacos使用心得,子项目pom.xml文件为

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>Learn</artifactId>
            <groupId>zyz.springCloudAlibaba</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>ribbon-produce</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>
    

    写配置文件

    编写配置文件application.yml

    spring:
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848
      application:
        name: ribbon-provider
    server:
      port: 8081
    

    新建启动类

    新建启动类RibbonProvider

    package com.zyz;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
    @SpringBootApplication
    @EnableDiscoveryClient
    public class RibbonProvider {
    
        public static void main(String[] args) {
            SpringApplication.run(RibbonProvider.class, args);
        }
    
    }
    

    新建Controller类

    package com.zyz.controller;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RestController;
    
    @Slf4j
    @RestController
    public class ProviderController {
    
        @GetMapping(value = "/ribbon/provider/{string}")
        public String echo(@PathVariable String string){
            log.info("Receive this request");
            return "Hello Ribbon provider Discovery " + string;
        }
    
    }
    

    引入日志注解@Slf4j

    参考

    消费端

    1. 引入依赖
    2. 写配置文件
    3. 启动类
    4. 配置类
    5. controller类

    整体项目结构

    整体项目结构如下图

    image

    引入依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>Learn</artifactId>
            <groupId>zyz.springCloudAlibaba</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>ribbon-consumer</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
        </dependencies>
    
    </project>
    

    写配置文件

    spring:
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848
      application:
        name: ribbon-consumer
    server:
      port: 8083
    

    启动类

    package com.zyz;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
    @SpringBootApplication
    @EnableDiscoveryClient
    public class RibbonConsumer {
    
        public static void main(String[] args) {
            SpringApplication.run(RibbonConsumer.class,args);
        }
    
    }
    

    配置类

    package com.zyz.config;
    
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.client.RestTemplate;
    
    @Configuration
    public class WebConfig {
    
        @LoadBalanced
        @Bean
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
    }
    

    controller类

    package com.zyz.contorller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    @RestController
    public class ConsumerController {
    
        @Autowired
        private RestTemplate restTemplate;
    
        @GetMapping(value = "/ribbon/consumer/{str}")
        public String rest(@PathVariable String str){
            return restTemplate.getForObject("http://ribbon-provider/ribbon/provider/" + str, String.class);
        }
    
    }
    

    启动项目

    启动两个生产端,用消费端进行访问,验证结果

    启动技巧

    生产端的端口是8081,我们用8081启动一个服务后,然后修改端口为8082,然后修改下图,那么就可以同一个工程启动两个实例

    Mac端:选中Allow parallel run


    image

    验证成功

    Ribbon的内置的负载均衡算法

    RandomRule

    随机选择一个Server

    RetryRule

    对选定的负载均衡策略加上重试机制,在一个配置时间段内当选择Server不成功, 则一直尝试使用subRule的方式选择一个可用的server

    RoundRobinRule

    轮询选择, 轮询index,选择index对应位置的Server

    AvailabilityFilteringRule

    过滤掉一直连接失败的被标记为circuit tripped的后端Server,并过滤掉那些高并发的后端 Server或者使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就就是检查 status里记录的各个Server的运行状态

    BestAvailableRule

    选择一个最小的并发请求的Server,逐个考察Server,如果Server被tripped了,则跳过。

    WeightedResponseTimeRule

    根据响应时间加权,响应时间越长,权重越小,被选中的可能性越低

    ZoneAvoidanceRule(默认是这个)

    复合判断Server所在Zone的性能和Server的可用性选择Server,在没有Zone的情况下类是轮询。

    Ribbon的负载均衡策略自定义配置

    Ribbon还支持自定义配置负载均衡策略,假设有订单中心要采用随机算法调用,库存中心要采用轮询算法调用。

    要建立三个服务,第一个是订单中心、第二个是库存中心,第三个是调用方。

    订单中心

    1. 引入依赖
    2. 写配置文件
    3. 启动类
    4. controller类

    整体结构

    引入依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>Learn</artifactId>
            <groupId>zyz.springCloudAlibaba</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>ribbon-product</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    

    写配置文件

    spring:
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848
      application:
        name: ribbon-product
    server:
      port: 8081
    

    启动类

    package com.zyz;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
    @SpringBootApplication
    @EnableDiscoveryClient
    public class RibbonProduct {
    
        public static void main(String[] args) {
            SpringApplication.run(RibbonProduct.class, args);
        }
    
    }
    

    controlelr类

    package com.zyz.controller;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @Slf4j
    public class ProductController {
    
        @GetMapping(value = "/ribbon/product/{string}")
        public String echo(@PathVariable String string){
            log.info("Receive this request");
            return "Hello Ribbon product Discovery " + string;
        }
    
    }
    

    库存中心

    1. 引入依赖
    2. 写配置文件
    3. 启动类
    4. controller类

    引入依赖

    <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    

    写配置文件

    spring:
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848
      application:
        name: ribbon-order
    server:
      port: 8083
    

    启动类

    package com.zyz;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
    @SpringBootApplication
    @EnableDiscoveryClient
    public class RibbonOrder {
        public static void main(String[] args) {
            SpringApplication.run(RibbonOrder.class, args);
        }
    }
    

    controller类

    package com.zyz.controller;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @Slf4j
    public class OrderController {
        @GetMapping(value = "/ribbon/order/{str}")
        public String order(@PathVariable String string){
            log.info("Receive this request");
            return "Hello Ribbon order Discovery " + string;
        }
    }
    

    客户端

    1. 引入依赖
    2. 写配置文件(包含负载均衡的配置策略)
    3. 启动类
    4. controller类
    5. 配置类

    整体结构

    image

    引入依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>Learn</artifactId>
            <groupId>zyz.springCloudAlibaba</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>ribbon-app</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>
    

    写配置文件

    spring:
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848
      application:
        name: ribbon-app
    server:
      port: 8088
    
    ribbon-order:
      ribbon:
        NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
    
    ribbon-product:
      ribbon:
        NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
    
    #开启ribbon饥饿加载,解决微服务调用第一次很慢的情况下
    ribbon:
      eager-load:
        enabled: true
        #可以指定多个微服务用逗号分隔
        clients: ribbon-order,ribbon-product
    

    启动类

    package com.zyz;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
    @SpringBootApplication
    @EnableDiscoveryClient
    public class RibbonApp {
    
        public static void main(String[] args) {
            SpringApplication.run(RibbonApp.class, args);
        }
    
    }
    

    controller类

    package com.zyz.controller;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    @Slf4j
    @RestController
    public class RibbonController {
    
        @Autowired
        private RestTemplate restTemplate;
    
        @GetMapping(value = "/ribbon/app/product/{str}")
        public String product(@PathVariable String str){
            return restTemplate.getForObject("http://ribbon-product/ribbon/product/" + str, String.class);
        }
    
        @GetMapping(value = "/ribbon/app/order/{str}")
        public String order(@PathVariable String str){
            return restTemplate.getForObject("http://ribbon-order/ribbon/order/" + str, String.class);
        }
    
    }
    

    配置类

    package com.zyz.config;
    
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.client.RestTemplate;
    
    @Configuration
    public class WebConfig {
    
        @LoadBalanced
        @Bean
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
    }
    

    Ribbon常用参数详解

    常用参数

    Ribbon自定义负载均衡策略

    Nacos支持权重配置,这是个比较实用的功能,例如:

    1. 把性能差的机器权重设低,性能好的机器权重设高,让请求优先打到性能高的机器上去
    2. 某个实例出现异常时,把权重设低,排查问题,问题排查完再把权重恢复
    3. 想要下线某个实例时,可先将该实例的权重设为0,这样流量就不会打到该实例上了——此时再去关停该实例,这样就能实现优雅下线

    下面就对Ribbon进行扩展,让其支持Nacos的权重配置

    自定义权重规则类

    package com.zyz.rule;
    
    import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
    import com.alibaba.cloud.nacos.ribbon.NacosServer;
    import com.alibaba.nacos.api.exception.NacosException;
    import com.alibaba.nacos.api.naming.NamingService;
    import com.alibaba.nacos.api.naming.pojo.Instance;
    import com.netflix.client.config.IClientConfig;
    import com.netflix.loadbalancer.AbstractLoadBalancerRule;
    import com.netflix.loadbalancer.BaseLoadBalancer;
    import com.netflix.loadbalancer.Server;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    
    @Slf4j
    public class WeightRule extends AbstractLoadBalancerRule {
    
        @Autowired
        private NacosDiscoveryProperties discoveryProperties;
    
        @Override
        public void initWithNiwsConfig(IClientConfig iClientConfig) {
            //读取配置文件并且初始化,ribbon内部的 几乎用不上
        }
    
        @Override
        public Server choose(Object key) {
            try {
                log.info("key:{}",key);
                BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer) this.getLoadBalancer();
                log.info("baseLoadBalancer--->:{}",baseLoadBalancer);
    
                //获取微服务的名称
                String serviceName = baseLoadBalancer.getName();
    
                //获取Nacos服务发现的相关组件API
                NamingService namingService = discoveryProperties.namingServiceInstance();
    
                //获取一个基于nacos client实现权重的负载均衡算法
                Instance instance = namingService.selectOneHealthyInstance(serviceName);
    
                //返回一个server
                return new NacosServer(instance);
            }catch (NacosException e){
                log.error("权重算法错误");
            }
            return null;
        }
    }
    

    添加配置

    ribbon-product:
      ribbon:
        NFLoadBalancerRuleClassName: com.zyz.rule.WeightRule
    

    相关文章

      网友评论

          本文标题:Ribbon使用心得

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