SpringCloud(三)学习笔记之Ribbon

spring Cloud Ribbon 是一个客户端的负载均衡器,它提供对大量的HTTP和TCP客户端的访问控制。

客户端负载均衡即是当浏览器向后台发出请求的时候,客户端会向 Eureka Server 读取注册到服务器的可用服务信息列表,然后根据设定的负载均衡策略(没有设置即用默认的),抉择出向哪台服务器发送请求

Eureka默认支持Ribbon 则不需要引入Ribbon 的依赖,后面会介绍单独使用ribbon的案例

一、构建Eureka Server

【基于第二章节创建的Eureka Server】

二、构建Eureka Client提供者集群项目

mhb-cloud-producer 【服务提供者1】
mhb-cloud-producer-extend【服务提供者2】

当两个项目的spring.application.name和eureka.instance.appname相同时,组成一个微服务集群

1:pom文件

加入Eureka Client依赖

mhb-cloud-producer、mhb-cloud-producer-extend

<!--eureka客户端环境支持-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

2:application.yml文件

mhb-cloud-producer 和 mhb-cloud-producer-extend 只有端口不同,其他一致

mhb-cloud-producer:端口 9904
mhb-cloud-producer-extend:端口9905

debug: false #关闭debug模式

spring:
  application:
    name: mhb-cloud-producer #应用的名称

server:
  port: 9904 #应用的端口号

eureka:
  instance:
    appname: producer #eureka application的名称
    prefer-ip-address: true #开启ip显示eureka的主机服务
    #eureka仪表盘的Instances格式
    instance-id: ${spring.application.name}:${spring.cloud.client.ipAddress}:${server.port}
  client:
    service-url:
     #eureka服务开启了认证,要加上用户名和密码
     defaultZone: http://admin:123456@localhost:8761/eureka/
    #从eureka服务器注册表中获取注册表信息的时间间隔,默认30s
    registry-fetch-interval-seconds: 30
    #客户端发送变化同步到eureka服务器的时间间隔 默认30s
    instance-info-replication-interval-seconds: 30
    #询问eureka服务url信息的变化的间隔时间 默认300s
    eureka-service-url-poll-interval-seconds: 300
    #最初同步到eureka服务器的时间 默认40s
    initial-instance-info-replication-interval-seconds: 40
    #注册表是否压缩
    g-zip-content: true
    #eureka等待超时时间 默认是5s
    eureka-server-connect-timeout-seconds: 5
    #eureka等待读取时间 默认是8s
    eureka-server-read-timeout-seconds: 8
    #eureka客户端允许的所有eureka服务器连接的总数 默认200
    eureka-server-total-connections: 200
    #eureka客户端允许的所有eureka服务器主机连接的总数 默认50
    eureka-server-total-connections-per-host: 50
    #心跳执行程序线程池的大小 默认是5
    heartbeat-executor-thread-pool-size: 5
    #心跳重试延迟的最大倍数值 默认是10
    heartbeat-executor-exponential-back-off-bound: 10
    #执行程序缓存刷新线程池的大小 默认是5
    cache-refresh-executor-thread-pool-size: 5
    #执行程序缓存刷新重试延迟的最大倍数值 默认是10
    cache-refresh-executor-exponential-back-off-bound: 10

3:启动类注解

mhb-cloud-producer、mhb-cloud-producer-extend

EnableEurekaClient/*eureka客户端注解*/

4:构建测试controller

mhb-cloud-producer、mhb-cloud-producer-extend

com\applesnt\controller\ProducerController.java

访问路径:http://localhost:端口/producer/get/123

/*类访问路径*/
@RequestMapping("/producer")

/*返回传递过来的id
* 请求路径:http://localhost:端口/producer/get/123
* */
@GetMapping("/get/{id}")
public String getId(@PathVariable("id") String id){
    System.out.println("-----"+id);
    return "我是提供者 端口是9904 传递的参数= "+id;
}

三、构建Eureka Client消费者项目

mhb-cloud-consumer :端口 8802

1:pom文件

Eureka 中已经自带Ribbon支持,所以不用单独引入Ribbon依赖

<!--eureka客户端环境支持-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

2:application.yml文件

包含Ribbon的属性配置

debug: false

spring:
  application:
    name: mhb-cloud-consumer #每一个微服务必须有这个应用名称

server:
  port: 8802 #端口

eureka:
  instance:
    appname: consumer #eureka application的名称
    prefer-ip-address: true #开启ip显示eureka的主机服务
    #eureka仪表盘的Instances格式
    instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}
  client:
    service-url:
     defaultZone: http://admin:123456@eureka1.com:8762/eureka/,http://admin:123456@eureka2.com:8762/eureka/,http://admin:123456@eureka3.com:8763/eureka/
    #从eureka服务器注册表中获取注册表信息的时间间隔,默认30s
    registry-fetch-interval-seconds: 30
    #客户端发送变化同步到eureka服务器的时间间隔 默认30s
    instance-info-replication-interval-seconds: 30
    #询问eureka服务url信息的变化的间隔时间 默认300s
    eureka-service-url-poll-interval-seconds: 300
    #最初同步到eureka服务器的时间 默认40s
    initial-instance-info-replication-interval-seconds: 40
    #注册表是否压缩
    g-zip-content: true
    #eureka等待超时时间 默认是5s
    eureka-server-connect-timeout-seconds: 5
    #eureka等待读取时间 默认是8s
    eureka-server-read-timeout-seconds: 8
    #eureka客户端允许的所有eureka服务器连接的总数 默认200
    eureka-server-total-connections: 200

#ribbon预加载
ribbon:
  eager-load:
    enabled: true #预加载 服务器启动的时候就加载服务列表 建议开启
    clients: mhb-cloud-producer #预加载哪个微服务  多个话用逗号隔开

#ribbon需要负载均衡的服务属性配置
mhb-cloud-producer: #配置的哪个实例
  ribbon:
    # 代表Ribbon使用的负载均衡策略(轮询)
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
    # 每台服务器最多重试次数,但是首次调用不包括在内
    MaxAutoRetries: 1
    # 最多重试多少台服务器
    MaxAutoRetriesNextServer: 1
    # 无论是请求超时或者socket read timeout都进行重试
    OkToRetryOnAllOperations: true
    # 服务列表的更新频率 毫秒
    ServerListRefreshInterval: 2000
    # 连接超时时间
    ConnectTimeout: 3000
    # 读取超时时间
    ReadTimeout: 3000

Ribbon负载均衡策略包括:

[1]BestAvailableRule:选择一个最小的并发请求的server:

[2]AvailabilityFilteringRule:过滤掉那些因为一直连接失败的被标记为circuittripped的后端server,并过滤掉那些高并发的的后端server

[3]WeightedResponseTimeRule:根据响应时间分配一个weight,响应时间越长,weight越小,被选中的可能性越低。

[4]RetryRule:对选定的负载均衡策略机上重试机制

[5]RoundRobinRule:roundRobin方式轮询选择server

[6]RandomRule:随机选择一个server

[7]ZoneAvoidanceRule:复合判断server所在区域的性能和server的可用性选择server

3:启动类配置RestTemplate

@@EnableEurekaClient
balanceRestTemplate:是带负载均衡的RestTemplate
noBalanceRestTemplate:是不带负载均衡的RestTemplate

package com.applesnt;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableEurekaClient
public class MhbCloudConsumerApplication {

	public static void main(String[] args) {
		SpringApplication.run(MhbCloudConsumerApplication.class, args);
	}

	@Bean
	@LoadBalanced/*微服务通讯时需要负载均衡 相同的spring.applincatin.name*/
	public RestTemplate balanceRestTemplate(){
		return new RestTemplate();
	}

	@Primary
	@Bean/*微服务通讯时不需要负载均衡*/
	public RestTemplate noBalanceRestTemplate(){
		return new RestTemplate();
	}
}

4:编写消费者远程调用controller

com\applesnt\controller\RibbonConsumerController.java

注入使用负载均衡和不使用负载均衡的RestTemplate,用@Qualifier来加以区分引入的对象

如果不使用负载均衡的RestTemplate,支持http://localhost:9904这种请求格式,不支持http://mhb-cloud-producer这种请求格式

如果使用负载均衡的RestTemplate, 支持http://mhb-cloud-producer这种请求格式,不支持http://localhost:9904这种请求格式

访问路径:http://localhost:8802/ribbon/get/123

package com.applesnt.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
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;

@RestController
@RequestMapping("/ribbon")
@Slf4j
public class RibbonConsumerController {

    /*注入 RestTemplate  在启动类中已初始化 不使用负载均衡*/
    @Autowired
    @Qualifier("noBalanceRestTemplate")
    private RestTemplate noBalanceRestTemplate;

    /*注入 RestTemplate  在启动类中已初始化 使用负载均衡*/
    @Autowired
    @Qualifier("balanceRestTemplate")
    private RestTemplate balanceRestTemplate;


    @GetMapping("/get/{id}")
    public String old(@PathVariable("id") String id){
        /*
        * 如果不使用负载均衡的RestTemplate,支持http://localhost:9904这种请求格式
        * 如果使用负载均衡的RestTemplate 则不支持http://localhost:9904这种请求格式
        * */
        String result="";

        /*正确输出*/
        result = noBalanceRestTemplate.getForObject("http://localhost:9904/producer/get/"+id,String.class);
        log.info("不使用负载均衡noBalanceRestTemplate==result:"+result);

        result = balanceRestTemplate.getForObject("http://mhb-cloud-producer/producer/get/"+id,String.class);
        log.info("使用负载均衡-url为微服务的balanceRestTemplate==result:"+result);

        return  result;
    }

}

5:服务启动

分别启动eureka服务集群、mhb-cloud-producer、mhb-cloud-producer-extend、mhb-cloud-consumer六个服务
http://eureka1.com:8761/

6:Ribbon负载测试

Ribbon使用的是轮询方式

访问路径:http://localhost:8802/ribbon/get/123

第一次访问结果:

第二次访问结果:

四、LoadBalancerClient对象

/*ribbon 注入操作对象*/
@Autowired
private LoadBalancerClient loadBalancerClient;

@GetMapping("/get/lbc/{id}")
public void ribbon(@PathVariable("id") String id){

    /*负载均衡得到当前连接的是集群中的哪一个微服务*/
    ServiceInstance instance = loadBalancerClient.choose("mhb-cloud-producer");
    log.info("ServiceId="+instance.getServiceId()+"  url="+instance.getUri()+" 端口="+instance.getPort());

    try {
        /*根据负载均衡后的服务构建url路径*/
        URI uri1 = loadBalancerClient.reconstructURI(instance,new URI(""));
        log.info("uri1="+uri1);

        /*构建url路径 默认是http*/
        URI uri2 = loadBalancerClient.reconstructURI(instance,new URI("/producer/get/"+id));
        log.info("uri2="+uri2);

        /*构建https url路径*/
        URI uri3 = loadBalancerClient.reconstructURI(instance,new URI("https:/producer/get/"+id));
        log.info("uri3="+uri3);

    }catch (Exception e){

    }
}

五:Ribbon脱离Eureka的使用

Eureka之外的服务调用 比如第三方

mhb-cloud-consumer-ribbon【端口:8803】

1:pom文件【不在引入eureka的依赖】

<!--引入ribbon的依赖-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

2:application.yml文件

debug: false

spring:
  application:
    name: mhb-cloud-consumer-ribbon #每一个微服务必须有这个应用名称

server:
  port: 8803 #端口

mhb-cloud-producer: #配置的哪个实例
  ribbon:
    listOfServers: 127.0.0.1:9904,127.0.0.1:9905
    # 代表Ribbon使用的负载均衡策略
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule

3:启动类:【不在使用@EnableEurekaClient注解】

package com.applesnt;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class MhbCloudConsumerRibbonApplication {

	public static void main(String[] args) {
		SpringApplication.run(MhbCloudConsumerRibbonApplication.class, args);
	}

	@Bean
	@LoadBalanced/*微服务通讯时需要负载均衡 相同的spring.applincatin.name*/
	public RestTemplate balanceRestTemplate(){
		return new RestTemplate();
	}

}

4:业务测试类:

com\applesnt\controller\RibbonConsumerController.java

package com.applesnt.controller;

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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

/**
 * @author: menghaibin
 * @create: 2020-03-08 20:15
 * @description: Ribbon消费者控制层
 **/
@RestController
@RequestMapping("/ribbon")
public class RibbonConsumerController {

    /*注入 RestTemplate  在启动类中已初始化 使用负载均衡*/
    @Autowired
    private RestTemplate balanceRestTemplate;

    @GetMapping("/get/{id}")
    public String old(@PathVariable("id") String id){

        String result = null;
        /*获取配置文件中mhb-cloud-producer的服务列表*/
        result = balanceRestTemplate.getForObject("http://mhb-cloud-producer/producer/get/"+id,String.class);

        return  result;
    }
}

测试:
http://127.0.0.1:8803/ribbon/get/123

第一次访问:

第二次访问:

posted @ 2020-04-01 16:01  努力的校长  阅读(425)  评论(0编辑  收藏  举报