Spring Cloud调用Ribbon的步骤

一、简介

1. 是什么

  • Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。
  • 简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。
  • 官方文档
  • 目前已进入维护状态,以后可以通过Open Feign作为替代方案
  • 负载均衡+RestTemplate,实现负载均衡调用

2. 负载均衡

  • 负载均衡(Load Balance,LB),即将用户的请求平摊到多个服务上,从而达到系统的高可用(HA)
  • 负载均衡分为两种方案:集中式LB、进程内LB

2.1 集中式LB

  • 即服务方和消费方之间使用独立的LB设施,由该设备负责把访问请求通过某种策略转发至服务提供方。
  • 比如说Nginx、Gateway、zuul等

2.2 进程内LB

  • 负载均衡的算法集成到消费方,消费方在注册中心中获取可用地址,然后通过LB算法选择出一个合适的服务器。
  • Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务方提供的地址。

二、实验

Ribbon集成在spring-cloud-starter-netflix-eureka-client中,可以参考eureka的使用。在此基础上简单修改一下,就可以完成服务调用及负载均衡

1. RestTemplate

  • 官网
  • 通过RestTemplate,可以实现HttpClient的功能,只需要给它提供一个url及返回类型,即可实现远程方法调用。

1.1 加入到IOC容器

首先,将其加入到IOC容器中。@LoadBalanced表示开启负载均衡。

@Configuration
public class ApplicationContextConfig {
  @Bean
  @LoadBalanced
  public RestTemplate restTemplate() {
    return new RestTemplate();
  }
}

1.2 RestTemplate 远程调用

@Slf4j
@RestController
@RequestMapping("/order")
public class OrderController {
  @Autowired
  RestTemplate restTemplate;  // 在ioc容器中获取
  @Value("${payment.url}")
  String paymentUrl;  // 远程调用的URL,保存在配置文件中,解耦

  @GetMapping("/payment/get/{id}")
  public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
    CommonResult<Payment> result = restTemplate.getForObject(paymentUrl + "/payment/get/" + id, CommonResult.class);  // get方法调用,并且返回封装成 CommonResult 类型
    log.info("Order 查询 Payment,id:" + id);
    return result;
  }
}

也可以使用getForEntity()方法,获取整个响应,自己在响应中获取想要的内容。

  @GetMapping("/payment/getEntity/{id}")
  public CommonResult<Payment> getPaymentEntityById(@PathVariable("id") Long id) {
    ResponseEntity<CommonResult> entity = restTemplate.getForEntity(paymentUrl + "/payment/get/" + id, CommonResult.class);
    log.info("获取到的信息是:" + entity.toString());
    log.info("获取到的StatusCode是:" + entity.getStatusCode());
    log.info("获取到的StatusCodeValue是:" + entity.getStatusCodeValue());
    log.info("获取到的Headers是:" + entity.getHeaders());

    if (entity.getStatusCode().is2xxSuccessful()) {
      log.info("查询成功:" + id);
      return entity.getBody();
    } else {
      log.info("查询失败:" + id);
      return new CommonResult<>(CommonResult.FAIlURE, "查询失败");
    }
  }

如果使用post方法,就将get改成post就好了。

1.3 配置文件

url,可以写具体的地址,表示直接调用该地址;也可以写在eureka的服务名,首先在eureka中获取该服务的所有地址,再通过LB选择一个。

payment:
  url: "http://CLOUD-PAYMENT-SERVICE"

2. LoadBalancer

上面通过@LoadBalanced开启了负载均衡。默认使用轮询算法,也可以修改成其他算法。

Class 算法
com.netflix.loadbalancer.RoundRobinRule 轮询,默认算法
com.netflix.loadbalancer.RandomRule 随机算法,通过产生随机数选择服务器
com.netflix.loadbalancer.RetryRule 先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务
WeightedResponseTimeRule 对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择
BestAvailableRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
AvailabilityFilteringRule 先过滤掉故障实例,再选择并发较小的实例
ZoneAvoidanceRule 默认规则,复合判断server所在区域的性能和server的可用性选择服务器

2.1 修改负载均衡算法

如果想让该算法只针对某个服务,则不能将其放在ComponentScan够得到的地方,否则会修改所有服务的负载均衡算法。因此,最好在外面再新建一个package,用来放这个LB

@Configuration
public class MyRule {
  @Bean
  public IRule rule() {
    return new RandomRule();
  }
}

在主启动类上,标识一下服务与算法直接的映射关系

@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MyRule.class)
public class OrderApplication80 {
  public static void main(String[] args) {
    SpringApplication.run(OrderApplication80.class, args);
  }
}

如果嫌这种方法麻烦,也可以使用配置文件的方法

CLOUD-PAYMENT-SERVICE:  # 服务名称
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule  # 算法选择

3. 负载均衡算法源码

以默认的RoundRobinRule作为阅读的源码,其他的源码基本上很类似,只是修改的选择服务器的代码。

  • RoundRobinRule父类为AbstractLoadBalancerRule,AbstractLoadBalancerRule实现了接口IRule

3.1 IRule

public interface IRule {
  Server choose(Object var1);  // 选择服务器,最重要的方法

  void setLoadBalancer(ILoadBalancer var1);

  ILoadBalancer getLoadBalancer();
}

3.2 AbstractLoadBalancerRule

基本没什么作用,只是将公共的部分提取了出来进行实现。

public abstract class AbstractLoadBalancerRule implements IRule, IClientConfigAware {
  private ILoadBalancer lb;  // ILoadBalancer接口,主要的功能就是获取当前服务器的状态、数量等,为负载均衡算法提供计算的参数

  public AbstractLoadBalancerRule() {
  }

  public void setLoadBalancer(ILoadBalancer lb) {
    this.lb = lb;
  }

  public ILoadBalancer getLoadBalancer() {
    return this.lb;
  }
}

3.3 RoundRobinRule

简单来说,就是通过一个计数器,实现了轮询

public class RoundRobinRule extends AbstractLoadBalancerRule {
  private AtomicInteger nextServerCyclicCounter;  // 原子类,用来保存一个计数,记录现在轮询到哪了
  private static final boolean AVAILABLE_ONLY_SERVERS = true;
  private static final boolean ALL_SERVERS = false;
  private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);

  public RoundRobinRule() {
    this.nextServerCyclicCounter = new AtomicInteger(0);  // 初始化
  }

  public RoundRobinRule(ILoadBalancer lb) {  // 设置LoadBalancer
    this();
    this.setLoadBalancer(lb);
  }

  public Server choose(ILoadBalancer lb, Object key) {  // 最重要的方法,选择服务器并返回
  // 下面贴出来
  }

  private int incrementAndGetModulo(int modulo) {  // 对计数器进行修改,并返回一个选择值,是轮询算法的实现
  // 下面贴出来
  }

  public Server choose(Object key) {   // 接口的方法,在该类中调用了另一个方法实现
    return this.choose(this.getLoadBalancer(), key);
  }

  public void initWithNiwsConfig(IClientConfig clientConfig) {}
}

简单来说,该方法就是根据目前的状态,选择一个服务器返回。

public Server choose(ILoadBalancer lb, Object key) {
    if (lb == null) {  // 如果没有LoadBalancer,那就不白费功夫了
      log.warn("no load balancer");
      return null;
    } else {
      Server server = null;
      int count = 0;

      while(true) {
        if (server == null && count++ < 10) {  // 尝试十次,如果还找不到server就放弃了
          List<Server> reachableServers = lb.getReachableServers();  // 通过LB获取目前所有可获取的服务器
          List<Server> allServers = lb.getAllServers();  // 获取实际上的所有服务器
          int upCount = reachableServers.size();  // 获取目前可获得的服务器数量
          int serverCount = allServers.size();  // 所有服务器的数量,这是取余的除数
          if (upCount != 0 && serverCount != 0) {  // 如果目前有服务器且服务器可用
            int nextServerIndex = this.incrementAndGetModulo(serverCount);  // 最关键的选择算法,将目前的的服务器数量放进去,返回一个选择的号码
            server = (Server)allServers.get(nextServerIndex);   // 根据下标将服务器取出来
            if (server == null) {  // 如果取出来为空,表示目前不可用,则进入下一个循环
              Thread.yield();
            } else {
              if (server.isAlive() && server.isReadyToServe()) {  // 如果该服务器活着且可以被使用,则直接将其返回
                return server;
              }

              server = null;
            }
            continue;
          }

          log.warn("No up servers available from load balancer: " + lb);
          return null;
        }

        if (count >= 10) {
          log.warn("No available alive servers after 10 tries from load balancer: " + lb);
        }

        return server;
      }
    }
  }

简单来说,就是将目前的计数器+1取余,获取一个下标,并返回。为了避免高并发的危险,采用CAS的方法进行设置。

  private int incrementAndGetModulo(int modulo) {
    int current;
    int next;
    do {
      current = this.nextServerCyclicCounter.get();  // 获取当前值
      next = (current + 1) % modulo;  // +1取余
    } while(!this.nextServerCyclicCounter.compareAndSet(current, next));  // CAS,如果成功就返回,失败就再来

    return next;
  }

以上就是Spring Cloud调用Ribbon的步骤的详细内容,更多关于Spring Cloud调用Ribbon的资料请关注我们其它相关文章!

(0)

相关推荐

  • SpringCloud Ribbon 负载均衡的实现

    前言 Ribbon是一个客户端负载均衡器,它提供了对HTTP和TCP客户端的行为的大量控制.我们在上篇(猛戳:SpringCloud系列--Feign 服务调用)已经实现了多个服务之间的Feign调用,服务消费者调用服务提供者,本文记录Feign调用Ribbon负载均衡的服务提供者 GitHub地址:https://github.com/Netflix/ribbon 官方文档:https://cloud.spring.io/spring-cloud-static/spring-cloud-net

  • springcloud中Ribbon和RestTemplate实现服务调用与负载均衡

    文件目录结构 文件目录结构很重要,特别注意的是rule文件要放在主启动类上一级位置,才能够扫描. 写pom <dependencies> <!--springboot 2.2.2--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependenc

  • 详解SpringCloud Ribbon 负载均衡通过服务器名无法连接的神坑

    一,问题 采取eureka集群.客户端通过Ribbon调用服务,Ribbon端报下列异常 java.net.UnknownHostException: SERVICE-HI java.lang.IllegalStateException: No instances available for SERVICE-HI java.lang.IllegalStateException: Request URI does not contain a valid hostname: http://SERVI

  • Spring Cloud Ribbon配置详解

    本节我们主要介绍 Ribbon 的一些常用配置和配置 Ribbon 的两种方式. 常用配置 1. 禁用 Eureka 当我们在 RestTemplate 上添加 @LoadBalanced 注解后,就可以用服务名称来调用接口了,当有多个服务的时候,还能做负载均衡. 这是因为 Eureka 中的服务信息已经被拉取到了客户端本地,如果我们不想和 Eureka 集成,可以通过下面的配置方法将其禁用. # 禁用 Eureka ribbon.eureka.enabled=false 当我们禁用了 Eure

  • 浅谈SpringCloud之Ribbon详解

    一.什么是负载均衡 负载均衡:建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽.增加吞吐量.加强网络数据处理能力.提高网络的灵活性和可用性. 现在网站的架构已经从C/S模式转变为B/S模式,C/S模式是有一个专门的客户端,而B/S模式是将浏览器作为客户端.当用户在浏览器上输入一个网址按下回车键后,就会产生一个请求,在远方的服务器会处理这个请求,根据这个请求来生成用户想要的页面,然后将这个页面响应给浏览器,这样用户就能看到他想要看到的东西.我们知道,一台服务器处理数

  • 深入学习Spring Cloud-Ribbon

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

  • 浅谈Spring Cloud Netflix-Ribbon灰度方案之Zuul网关灰度

    Eureka默认集成了Ribbon,所以Ribbon的灰度实现原理就是借助服务注册到Eureka中的eureka.instance.metadata-map的内容来进行匹配的. Zuul网关的灰度实现也是借助了一个Ribbon的插件来实现,相对比较简单. 项目环境说明:有两个eureka的服务端(eureka-server),有两个相同的后端服务(service-sms),有一个网关服务(cloud-zuul). 1.网关的依赖: <?xml version="1.0" enco

  • SpringCloud Netflix Ribbon源码解析(推荐)

    SpringCloud Netflix Ribbon源码解析 首先会介绍Ribbon 相关的配置和实例的初始化过程,然后讲解Ribbon 是如何与OpenFeign 集成的,接着讲解负载均衡器LoadBalancerCli ent , 最后依次讲解ILoadB alancer的实现和负载均衡策略Rule 的实现. 配置和实例初始化 @RibbonClient 注解可以声明Ribbon 客户端,设置Ribbon 客户端的名称和配置类,configuration 属性可以指定@Configurati

  • SpringCloud 2020-Ribbon负载均衡服务调用的实现

    1.概述 官网:https://github.com/Netflix/ribbon/wiki/Getting-Started Ribbon目前也进入维护模式,未来替换方案: LB(负载均衡) 集中式LB 进程内LB Ribbon就是负载均衡+RestTemplate调用 2.Ribbon负载均衡演示 1.架构说明 总结:Ribbon其实就是一个软负载均衡的客户端组件,他可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例. 2. 3.二说RestTemplate的使用 官网

  • SpringCloud 服务负载均衡和调用 Ribbon、OpenFeign的方法

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

  • SpringCloud手写Ribbon实现负载均衡

    前言 前面我们学习了 SpringCloud整合Consul,在此基础上我们手写本地客户端实现类似Ribbon负载均衡的效果. 注: order 模块调用者 记得关闭 @LoadBalanced 注解. 我们这里只演示 注册中心 consul,至于 zookeeper 也是一模一样. 生产者 member模块 member 服务需要集群,所以我们copy application-consul.yml 文件命名为 application-consul2.yml 服务别名一致,只需要修改端口号即可.

  • Springcloud ribbon负载均衡算法实现

    一 前言 经过几篇的cloud系列文章,我想大家都有一个坚实的基础,后续的学习就会轻松很多,如果是刚刚来看的读者需要有eureka基础知识,或者查阅知识追寻者的cloud系列专栏:这篇文章主要讲解如何使用ribbon实现web service客户端调用,ribbon默认算法实现负载均衡等! 二 ribbon简介 ribbon是一个客户端负载均衡器,其能够整合不同的协议工具进行web service API 调用: 主要特色如下: 提供可插拔式的负载均衡整合服务发现故障弹性恢复cloud支持客户端

随机推荐