首页 > 其他分享 >面试官:说说Ribbon是如何实现负载均衡的?

面试官:说说Ribbon是如何实现负载均衡的?

时间:2024-11-14 16:46:53浏览次数:3  
标签:面试官 调用 负载 Server Ribbon 均衡 ribbon

Ribbon的作用是负载均衡,但是根据我面试他人的情况来看,很多人只忙于业务,而不清楚具体的底层原理,在面试中是很容易吃亏的。基于此,本文就来分析一下Ribbon的原理,如果看不惯的话,可以直接看最后的总结。

一、基础概念

1.什么是Ribbon

目前主流的负载方案分为以下两种:

  • 集中式负载均衡,在消费者和服务提供方中间使用独立的代理方式进行负载,有硬件的(比如 F5),也有软件的(比如 Nginx)。
  • 客户端根据自己的请求情况做负载均衡,Ribbon 就属于客户端自己做负载均衡。

Spring Cloud Ribbon是基于Netflix Ribbon 实现的一套客户端的负载均衡工具,Ribbon客户端组件提供一系列的完善的配置,如超时,重试等。通过Load Balancer获取到服务提供的所有机器实例,Ribbon会自动基于某种规则(轮询,随机)去调用这些服务。Ribbon也可以实现我们自己的负载均衡算法。

另外:
推荐一个程序员免费学习的编程网站:我爱编程网(www.love-coding.com
涵盖 Java几乎覆盖了所有主流技术面试题,还有市面上最全的技术精品系列教程,免费提供。
在这里插入图片描述

2.ribbon实现远程调用并负载均衡

1)模拟ribbon实现

以下代码体现了ribbon实现负载均衡的思路

@Autowired
private RestTemplate restTemplate;

@RequestMapping(value = "/findOrderByUserId/{id}")
public R findOrderByUserId(@PathVariable("id") Integer id) {
  // RestTemplate调用
  //String url = "http://localhost:8020/order/findOrderByUserId/"+id;
  //模拟ribbon实现
  String url = getUri("mall-order")+"/order/findOrderByUserId/"+id;
  // 添加@LoadBalanced
  //String url = "http://mall-order/order/findOrderByUserId/"+id;
  R result = restTemplate.getForObject(url,R.class);
  return result;
}

@Autowired
private DiscoveryClient discoveryClient;
public String getUri(String serviceName) {  // 拿到服务的所有实例  List<ServiceInstance> serviceInstances = discoveryClient.getInstances(serviceName);
  if (serviceInstances == null || serviceInstances.isEmpty()) {
      return null;
  }
  int serviceSize = serviceInstances.size();
  //轮询,获得其中的某一个实例节点
  int indexServer = incrementAndGetModulo(serviceSize);
  return serviceInstances.get(indexServer).getUri().toString();
}
private AtomicInteger nextIndex = new AtomicInteger(0);
// 轮询算法private int incrementAndGetModulo(int modulo) {
  for (;;) {
      int current = nextIndex.get();
      int next = (current + 1) % modulo;
      if (nextIndex.compareAndSet(current, next) && current < modulo){
          return current;
      }
  }
}
2)ribbon使用

编写一个客户端来调用接口

public class RibbonDemo {

  public static void main(String[] args) {

      // 服务列表
      List<Server> serverList = Lists.newArrayList(
              new Server("localhost", 8020),
              new Server("localhost", 8021));
      // 构建负载实例
      ILoadBalancer loadBalancer = LoadBalancerBuilder.newBuilder()
              .buildFixedServerListLoadBalancer(serverList);
      // 调用 5 次来测试效果
      for (int i = 0; i < 5; i++) {
          String result = LoadBalancerCommand.<String>builder()
                  .withLoadBalancer(loadBalancer).build()
                  .submit(new ServerOperation<String>() {
                      @Override
                      public Observable<String> call(Server server) {
                          String addr = "http://" + server.getHost() + ":" +
                                  server.getPort() + "/order/findOrderByUserId/1";
                              System.out.println(" 调用地址:" + addr);
                          URL url = null;
                          try {
                              url = new URL(addr);
                              HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                              conn.setRequestMethod("GET");
                              conn.connect();
                              InputStream in = conn.getInputStream();
                              byte[] data = new byte[in.available()];
                              in.read(data);
                              return Observable.just(new String(data));
                          } catch (Exception e) {
                              e.printStackTrace();
                          }
                          return null;
                      }
                  }).toBlocking().first();

          System.out.println(" 调用结果:" + result);
      }
  }

}

二、架构设计

1.客户端的负载均衡

例如spring cloud中的ribbon,客户端会有一个服务器地址列表,在发送请求前通过负载均衡算法选择一个服务器,然后进行访问,这是客户端负载均衡;即在客户端就进行负载均衡算法分配。

图片

2 服务端的负载均衡

例如Nginx,通过Nginx进行负载均衡,先发送请求,然后通过负载均衡算法,在多个服务器之间选择一个进行访问;即在服务器端再进行负载均衡算法分配

图片

3.Ribbon实现原理

图片

Ribbon 通过在客户端发起请求前选择目标服务实例的方式实现负载均衡。它维护了服务实例的列表,通过一定的策略选择实例,将请求发送到选定的服务。

三、内部核心实现原理

1.@LoadBalanced 注解原理

参考源码:LoadBalancerAutoConfiguration

@LoadBalanced利用@Qualifier作为restTemplates注入的筛选条件,筛选出具有负载均衡标识的RestTemplate。

图片

被@LoadBalanced注解的restTemplate会被定制,添加LoadBalancerInterceptor拦截器。

图片

2.Ribbon负载均衡策略

图片

1、RandomRule:随机选择一个Server。

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

3、RoundRobinRule:轮询选择, 轮询index,选择index对应位置的Server。4、AvailabilityFilteringRule:过滤掉一直连接失败的被标记为circuit tripped的后端Server,并过滤掉那些高并发的后端Server或者使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就是检查status里记录的各个Server的运行状态。5、BestAvailableRule:选择一个最小的并发请求的Server,逐个考察Server,如果Server被tripped了,则跳过。

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

7、ZoneAvoidanceRule:默认的负载均衡策略,即复合判断Server所在区域的性能和Server的可用性选择Server,在没有区域的环境下,类似于轮询(RandomRule)

8、NacosRule: 同集群优先调用

1.修改默认负载均衡策略

全局配置:调用其他微服务,一律使用指定的负载均衡算法

@Configuration
public class RibbonConfig {

  /**
    * 全局配置
    * 指定负载均衡策略
    * @return
    */
  @Bean
  public IRule() {
      // 指定使用Nacos提供的负载均衡策略(优先调用同一集群的实例,基于随机权重)
      return new NacosRule();
  }

局部配置:调用指定微服务提供的服务时,使用对应的负载均衡算法

修改application.yml

# 被调用的微服务名
mall-order:
ribbon:
  # 指定使用Nacos提供的负载均衡策略(优先调用同一集群的实例,基于随机&权重)
  NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
2.自定义负载均衡策略

通过实现 IRule 接口可以自定义负载策略,主要的选择服务逻辑在 choose 方法中。

@Slf4j
public class NacosRandomWithWeightRule extends AbstractLoadBalancerRule {

  @Autowired
  private NacosDiscoveryProperties nacosDiscoveryProperties;

  @Override
  public Server choose(Object key) {
      DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
      String serviceName = loadBalancer.getName();
      NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
      try {
          //nacos基于权重的算法
          Instance instance = namingService.selectOneHealthyInstance(serviceName);
          return new NacosServer(instance);
      } catch (NacosException e) {
          log.error("获取服务实例异常:{}", e.getMessage());
          e.printStackTrace();
      }
      return null;
  }
  @Override
  public void initWithNiwsConfig(IClientConfig clientConfig) {

  }

3.加载策略懒加载和饿加载

在进行服务调用的时候,如果网络情况不好,第一次调用会超时。

Ribbon默认懒加载,意味着只有在发起调用的时候才会创建客户端。

图片

开启饥饿加载,解决第一次调用慢的问题

ribbon:
  eager-load:
      # 开启ribbon饥饿加载
     enabled: true
     # 配置mall-order使用ribbon饥饿加载,多个使用逗号分隔
     clients: mall-order

源码对应属性配置类:RibbonEagerLoadProperties

测试:

图片

四、总结

图片

通过这张图来总结一下整个ribbon负载均衡的流程。

1、发送请求,被LoadBalancerInterceptor拦截器拦截,请求被交给ribbon来处理

2、拦截器拦截请求,交给了RibbonLoadBalancerClient的execute方法(下面的逻辑都是包含在这个方法中)

3、在进行负载均衡之前首先得知道有哪些服务实例信息,所以通过DynamicServerListLoadBalancer的updateListOfServers方法从注册中心(Eureka)那里获取到了所有的服务实例信息,并且会定时更新

4、使用负载均衡算法(默认轮询算法)从所有的服务实例信息中选择一台机器出来

5、将请求发送给负载均衡选择出来的服务实例上去

标签:面试官,调用,负载,Server,Ribbon,均衡,ribbon
From: https://blog.csdn.net/u010020088/article/details/143775197

相关文章

  • 通过 AWR报告查看oracle 数据库服务器的负载(load average)异常高的原因
    要诊断Oracle数据库服务器的负载(loadaverage)异常高的原因,通过AWR(AutomaticWorkloadRepository)报告可以帮助你识别潜在的瓶颈或负载源。AWR报告提供了数据库的详细性能数据,涵盖了系统负载、SQL执行、I/O性能、内存使用等多方面的信息。以下是通过AWR报告查看和诊断高负......
  • CFS任务的负载均衡(概述)
    CFS任务的负载均衡(概述)我们描述负载均衡的系列文章一共三篇,第一篇是框架部分,即本文,主要描述了负载均衡相关的原理、场景和框架。后面的两篇是对均衡代码的情景分析,通过对tickbalance、newidlebalance和taskplacement等几个典型的负载均衡来呈现其实现细节,稍后发布,敬请期待。......
  • NGINX负载均衡实战教程:打造高可用性架构 转载
    nginx负载均衡nginx负载均衡介绍反向代理与负载均衡nginx负载均衡配置Keepalived高可用nginx负载均衡器修改Web服务器的默认主页开启nginx负载均衡和反向代理安装Keepalived配置Keepalived编写脚本监控Keepalived和nginx的状态配置keepalived......
  • 将 2平方毫米的电线用于承载 大功率家电(如空调、冰箱、电热水器、洗衣机等)是非常不安
    将2平方毫米的电线用于承载大功率家电(如空调、冰箱、电热水器、洗衣机等)是非常不安全的,因为电线的规格和电流负载能力是根据家电的功率来确定的。若电线规格不合适,会带来一系列严重的安全隐患。以下是详细说明这种不匹配电线规格可能带来的影响和危害。1. 电线过热过载运......
  • CFS任务的负载均衡(概述)
    CFS任务的负载均衡(概述)我们描述负载均衡的系列文章一共三篇,第一篇是框架部分,即本文,主要描述了负载均衡相关的原理、场景和框架。后面的两篇是对均衡代码的情景分析,通过对tickbalance、newidlebalance和taskplacement等几个典型的负载均衡来呈现其实现细节,稍后发布,敬请期待。......
  • 负载均衡策略有哪几种?
    在当今数字化的时代,随着网络应用和服务的规模不断扩大,负载均衡成为保障系统高性能、高可用性的关键技术。负载均衡策略多种多样,它们在不同的场景下发挥着重要作用。1、轮询策略轮询是一种简单而直接的负载均衡策略。在这种策略下,服务器集群中的服务器按照顺序依次接收请求。例如......
  • 多通道负载测试和性能评估?
    多通道负载测试和性能评估是软件质量保证的重要组成部分,它们可以帮助我们发现和解决系统的性能瓶颈,提高系统的可用性和稳定性。多通道负载测试是一种模拟多个用户同时访问系统的方法,以检查系统在高并发情况下的性能。这种测试通常用于评估系统的最大处理能力,以及确定系统在何种负......
  • 如何延长便携式负载箱使用寿命?
    便携式负载箱是一种用于测试和校准电力设备的设备,它能够模拟实际的负载情况,帮助用户确保设备的性能和安全性。然而,这种设备的价格通常较高,因此,延长其使用寿命对于用户来说是非常重要的。以下是一些可以帮助你延长便携式负载箱使用寿命的建议:正确使用:首先,你需要正确使用便携式负......
  • 揭秘MySQL数据一致性:从原理到实践,助你征服大厂面试官
    ......
  • 如何评估焊机测试负载均衡性能
    评估焊机测试负载均衡性能的方法有很多,以下是一些建议:确定测试目标:首先,需要明确评估焊机测试负载均衡性能的目标。这可能包括提高生产效率、降低能耗、减少设备故障率等。明确目标有助于选择合适的评估方法和指标。选择合适的测试方法:根据测试目标和焊机的实际情况,选择合适的测......