【SpringCloud总结】6. Ribbon负载均衡

    xiaoxiao2022-07-13  161

    一、简介

    Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。   简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。  

    二、Ribbon配置

    1. 修改 microservicecloud-consumer-dept-80 工程

    2. 修改pom.xml文件

    <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">   <modelVersion>4.0.0</modelVersion>     <parent>    <groupId>com.atguigu.springcloud</groupId>    <artifactId>microservicecloud</artifactId>    <version>0.0.1-SNAPSHOT</version>   </parent>     <artifactId>microservicecloud-consumer-dept-80</artifactId>   <description>部门微服务消费者</description>     <dependencies>    <dependency><!-- 自己定义的api -->      <groupId>com.atguigu.springcloud</groupId>      <artifactId>microservicecloud-api</artifactId>      <version>${project.version}</version>    </dependency>    <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-web</artifactId>    </dependency>    <!-- Ribbon相关 -->    <dependency>      <groupId>org.springframework.cloud</groupId>      <artifactId>spring-cloud-starter-eureka</artifactId>    </dependency>    <dependency>      <groupId>org.springframework.cloud</groupId>      <artifactId>spring-cloud-starter-ribbon</artifactId>    </dependency>    <dependency>      <groupId>org.springframework.cloud</groupId>      <artifactId>spring-cloud-starter-config</artifactId>    </dependency>   </dependencies> </project>

    3. 修改application.yml   追加eureka的服务注册地址

    server:   port: 80 #下面是新加的配置 eureka:   client:     register-with-eureka: false     service-url:        defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

     

    4. 对ConfigBean进行新注解@LoadBalanced    获得Rest时加入Ribbon的配置

    package com.atguigu.springcloud.cfgbeans;   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 ConfigBean {   @Bean   @LoadBalanced //新加的注解   public RestTemplate getRestTemplate()   {    return new RestTemplate();   } }

    5. 主启动类DeptConsumer80_App添加@EnableEurekaClient

    package com.atguigu.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient //新加的注解 public class DeptConsumer80_App {   public static void main(String[] args)   {    SpringApplication.run(DeptConsumer80_App.class, args);   } }

    6. 修改DeptController_Consumer客户端访问类

    package com.atguigu.springcloud.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import com.atguigu.springcloud.entities.Dept; @RestController public class DeptController_Consumer {   /*private static final String REST_URL_PREFIX = "http://localhost:8001"; 把该部分注释掉,使用微服务的名称!注意不是微服务的实例的名称! Ribbon和Eureka整合后Consumer可以直接调用服务而不用再关心地址和端口号 */   private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT";      @Autowired   private RestTemplate restTemplate;      @RequestMapping(value="/consumer/dept/add")   public boolean add(Dept dept)   {    return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add", dept, Boolean.class);   }      @RequestMapping(value="/consumer/dept/get/{id}")   public Dept get(@PathVariable("id") Long id)   {    return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id, Dept.class);   }      @SuppressWarnings("unchecked")   @RequestMapping(value="/consumer/dept/list")   public List<Dept> list()   {    return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list", List.class);   }       //测试@EnableDiscoveryClient,消费端可以调用服务发现   @RequestMapping(value="/consumer/dept/discovery")    public Object discovery()   {    return restTemplate.getForObject(REST_URL_PREFIX+"/dept/discovery", Object.class);   }      }  

    7. 启动服务

        启动服务器集群:3个eureka

        启动provider: microservicecloud-provider-dept-8001

        启动consumer:microservicecloud-consumer-dept-80

     

    8. 测试

          http://localhost/consumer/dept/get/1

          http://localhost/consumer/dept/list

          http://localhost/consumer/dept/add?dname=大数据部

     

    三、Ribbon负载均衡

     1.架构说明

        Ribbon在工作时分成两步:        第一步先选择 EurekaServer ,它优先选择在同一个区域内负载较少的server.        第二步再根据用户指定的策略,在从server取到的服务注册列表中选择一个地址。     其中Ribbon提供了多种策略:比如轮询、随机和根据响应时间加权。

    2. 具体步骤

    (1)参考 microservicecloud-provider-dept-8001,新建两份,分别命名为8002,8003

    (2)新建8002/8003数据库,各自微服务分别连各自的数据库

    #8002 DROP DATABASE IF EXISTS cloudDB02;   CREATE DATABASE cloudDB02 CHARACTER SET UTF8; USE cloudDB02; CREATE TABLE dept (   deptno BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,   dname VARCHAR(60),   db_source   VARCHAR(60) );   INSERT INTO dept(dname,db_source) VALUES('开发部',DATABASE()); INSERT INTO dept(dname,db_source) VALUES('人事部',DATABASE()); INSERT INTO dept(dname,db_source) VALUES('财务部',DATABASE()); INSERT INTO dept(dname,db_source) VALUES('市场部',DATABASE()); INSERT INTO dept(dname,db_source) VALUES('运维部',DATABASE()); #8003 DROP DATABASE IF EXISTS cloudDB03; CREATE DATABASE cloudDB03 CHARACTER SET UTF8; USE cloudDB03; CREATE TABLE dept (   deptno BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,   dname VARCHAR(60),   db_source   VARCHAR(60) ); INSERT INTO dept(dname,db_source) VALUES('开发部',DATABASE()); INSERT INTO dept(dname,db_source) VALUES('人事部',DATABASE()); INSERT INTO dept(dname,db_source) VALUES('财务部',DATABASE()); INSERT INTO dept(dname,db_source) VALUES('市场部',DATABASE()); INSERT INTO dept(dname,db_source) VALUES('运维部',DATABASE());

    (3)修改8002/8003各自YML

            8002yml文件

    server:   port: 8002    mybatis:   config-location: classpath:mybatis/mybatis.cfg.xml  #mybatis所在路径   type-aliases-package: com.atguigu.springcloud.entities #entity别名类   mapper-locations:   - classpath:mybatis/mapper/**/*.xml #mapper映射文件      spring:    application:     name: microservicecloud-dept     datasource:     type: com.alibaba.druid.pool.DruidDataSource     driver-class-name: org.gjt.mm.mysql.Driver     url: jdbc:mysql://localhost:3306/cloudDB02     username: root     password: 123456     dbcp2:       min-idle: 5       initial-size: 5       max-total: 5       max-wait-millis: 200        eureka:   client: #客户端注册进eureka服务列表内     service-url:        defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/   instance:     instance-id: microservicecloud-dept8002   #自定义服务名称信息     prefer-ip-address: true     #访问路径可以显示IP地址        info:   app.name: atguigu-microservicecloud   company.name: www.atguigu.com   build.artifactId: $project.artifactId$   build.version: $project.version$

             8003yml文件

    server:   port: 8003    mybatis:   config-location: classpath:mybatis/mybatis.cfg.xml  #mybatis所在路径   type-aliases-package: com.atguigu.springcloud.entities #entity别名类   mapper-locations:   - classpath:mybatis/mapper/**/*.xml #mapper映射文件      spring:    application:     name: microservicecloud-dept     datasource:     type: com.alibaba.druid.pool.DruidDataSource     driver-class-name: org.gjt.mm.mysql.Driver     url: jdbc:mysql://localhost:3306/cloudDB03     username: root     password: 123456     dbcp2:       min-idle: 5       initial-size: 5       max-total: 5       max-wait-millis: 200        eureka:   client: #客户端注册进eureka服务列表内     service-url:        defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/   instance:     instance-id: microservicecloud-dept8003   #自定义服务名称信息     prefer-ip-address: true     #访问路径可以显示IP地址        info:   app.name: atguigu-microservicecloud   company.name: www.atguigu.com   build.artifactId: $project.artifactId$   build.version: $project.version$       

              【提示】修改的部分:端口、数据库名!同时注意对外暴露的统一的微服务名microservicecloud-dept!可以把                                            8001,8002,8003理解为一个微服务的3个实例。

    (4)启动3个eureka集群配置区

    (5)启动3个Dept微服务并各自测试通过

             http://localhost:8001/dept/list

             http://localhost:8002/dept/list

             http://localhost:8003/dept/list

    (6)启动microservicecloud-consumer-dept-80

    (7)客户端通过Ribbo完成负载均衡并访问上一步的Dept微服务

              http://localhost/consumer/dept/list

              注意观察看到返回的数据库名字,各不相同,负载均衡实现

    (8)Ribbon其实就是一个软负载均衡的客户端组件,他可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例。

              

    四、Ribbon核心组件IRule

     IRule:根据特定算法中从服务列表中选取一个要访问的服务

    (1)RoundRobinRule 轮询

    (2)RandomRule 随机

    (3)AvailabilityFilteringRule 

             会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数量超过阈值的服务,然后对剩余的服务列             表按照轮询策略进行访问。

    (4)WeightedResponseTimeRule 

             根据平均响应时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越高。刚启动时如果统计信息不足,则             使用RoundRobinRule策略,等统计信息足够,会切换到WeightedResponseTimeRule

    (5)RetryRule

             先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务

    (6)BestAvailableRule

             会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务

    (7) ZoneAvoidanceRule

             默认规则,复合判断server所在区域的性能和server的可用性选择服务器

    microservicecloud-consumer-dept-80的com.atguigu.springcloud.cfgbeans包下ConfigBean的编写

    package com.atguigu.springcloud.cfgbeans;   import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate;   @Configuration public class ConfigBean {     @Bean @LoadBalanced     public RestTemplate getRestTemplate()     {          return new RestTemplate();     }    @Bean    public IRule myRule()    {     return new RandomRule();//Ribbon默认是轮询,我自定义为随机    } }

     

    最新回复(0)