【微服务】2、一篇文章详解 Ribbon 负载均衡

简介: 【微服务】2、一篇文章详解 Ribbon 负载均衡


一、负载均衡原理(debug 源码)

(1) 基本介绍

📖 @LoadBalanced 注解表示:将来 RestTemplate 发起的请求要被 ribbon 拦截

📖 这个拦截操作是通过 LoadBalancerInterceptor 完成的

📖 它是 SpringCloud 中的拦截器org.springframework.cloud.client.loadbalancer

📖 LoadBalancerInterceptorClientHttpRequestInterceptor 接口的实现类



(2) 打断点

① LoadBalancerInterceptor.java - intercept()

public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
    final ClientHttpRequestExecution execution) throws IOException {
  // 获取请求地址
  final URI originalUri = request.getURI();
  // 获取主机名(微服务的服务名)
  String serviceName = originalUri.getHost();
  // 判断服务名是否为空
  Assert.state(serviceName != null,
      "Request URI does not contain a valid hostname: " + originalUri);
  // this.loadBalancer: RibbonLoadBalancerClient
  // 进入 this.loadBalancer.execute 方法
  return this.loadBalancer.execute(serviceName,
      this.requestFactory.createRequest(request, body, execution));
}

② RibbonLoadBalancerClient.java - execute()

public <T> T execute(String serviceId, LoadBalancerRequest<T> request)
    throws IOException {
  // serviceId: 服务名
  return execute(serviceId, request, null);
}

③ RibbonLoadBalancerClient.java - execute()

🔋 调用 RibbonLoadBalancerClient 重载的另一个 execute() 方法

public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
    throws IOException {
  // 通过服务名获取负载均衡器
  // loadBalancer 的 allServerList 中包含服务地址信息
  ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
  // 负载均衡, 获取某个服务地址信息
  Server server = getServer(loadBalancer, hint);
  if (server == null) {
    throw new IllegalStateException("No instances available for " + serviceId);
  }
  RibbonServer ribbonServer = new RibbonServer(serviceId, server,
      isSecure(server, serviceId),
      serverIntrospector(serviceId).getMetadata(server));
  return execute(serviceId, ribbonServer, request);
}

④ RibbonLoadBalancerClient.java - getServer()

protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
  if (loadBalancer == null) {
    return null;
  }
  // Use 'default' on a null hint, or just pass it on?
  return loadBalancer.chooseServer(hint != null ? hint : "default");
}

⑤ ZoneAwareLoadBalancer.java - chooseServer()

🔋 调用父类的 chooseServer()

⑥ BaseLoadBalancer.java - chooseServer()

public Server chooseServer(Object key) {
    if (counter == null) {
        counter = createCounter();
    }
    counter.increment();
    // rule 默认是 ZoneAvoidanceRule 类型, 不为 null
    if (rule == null) {
        return null;
    } else {
        try {
            // 根据 key 选择一个活着的的服务
            return rule.choose(key);
        } catch (Exception e) {
            logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", name, key, e);
            return null;
        }
    }
}

⑦ RibbonLoadBalancerClient.java - execute()

🔋 拿真实的服务地址替换服务名

(3) 流程

二、负载均衡策略

(1) 负载均衡策略

📝 Ribbon 的负载均衡策略是通过一个叫做 IRule 的接口来定义的,每个实现类是一种策略

(2) 调整负载均衡策略

📝 有种方式指定 IRule 实现,进而修改负载均衡规则

① 注入(@Bean)自己需要的负载均衡策略(IRule)

全局:整个微服务

@Bean
  public IRule iRule() {
      return new RandomRule();
  }

📝 整个微服务发送的请求都通过【随机】方式负载均衡

② yaml 文件指定对某个指定微服务发送请求的使用采用指定的负载均衡策略

局部:只对某个微服务有作用

userservice: # 该微服务向 userservice 发送的请求使用【随机】负载均衡
  ribbon:
   NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

(3) 饥饿加载

📝 Ribbon 默认是采用懒加载 【第一次访问时才会创建 LoadBalanceClient,请求时间会很长】

📝 饥饿加载会让 LoadBalanceClient 在项目启动时被创建,进而降低第一次访问的耗时

ribbon:
  eager-load:
    enabled: true # 开启饥饿加载
    clients:
      - userservice # 指定对哪些微服务进行饥饿加载

📖 根据 Bilibili 黑马程序员进行学习

📖 如有错误,请不吝赐教哦

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
相关文章
|
11月前
|
NoSQL MongoDB 微服务
微服务——MongoDB实战演练——文章评论的基本增删改查
本节介绍了文章评论的基本增删改查功能实现。首先,在`cn.itcast.article.dao`包下创建数据访问接口`CommentRepository`,继承`MongoRepository`以支持MongoDB操作。接着,在`cn.itcast.article.service`包下创建业务逻辑类`CommentService`,通过注入`CommentRepository`实现保存、更新、删除及查询评论的功能。最后,新建Junit测试类`CommentServiceTest`,对保存和查询功能进行测试,并展示测试结果截图,验证功能的正确性。
258 2
|
11月前
|
NoSQL Java MongoDB
微服务——MongoDB实战演练——文章评论实体类的编写
本节主要介绍文章评论实体类的编写,创建了包`cn.itcast.article.po`用于存放实体类。具体实现中,`Comment`类通过`@Document`注解映射到MongoDB的`comment`集合,包含主键、内容、发布时间、用户ID、昵称等属性,并通过`@Indexed`和`@CompoundIndex`注解添加单字段及复合索引,以提升查询效率。同时提供了Mongo命令示例,便于理解和操作。
191 2
|
11月前
|
NoSQL 测试技术 MongoDB
微服务——MongoDB实战演练——根据上级ID查询文章评论的分页列表
本节介绍如何根据上级ID查询文章评论的分页列表,主要包括以下内容:(1)在CommentRepository中新增`findByParentid`方法,用于按父ID查询子评论分页列表;(2)在CommentService中新增`findCommentListPageByParentid`方法,封装分页逻辑;(3)提供JUnit测试用例,验证功能正确性;(4)使用Compass插入测试数据并执行测试,展示查询结果。通过这些步骤,实现对评论的高效分页查询。
195 0
|
11月前
|
NoSQL MongoDB 微服务
微服务——MongoDB实战演练——文章微服务模块搭建
本节介绍文章微服务模块的搭建过程,主要包括以下步骤:(1)创建项目工程 *article*,并在 *pom.xml* 中引入依赖;(2)配置 *application.yml* 文件;(3)创建启动类 *cn.itcast.article.ArticleApplication*;(4)启动项目,确保控制台无错误提示。通过以上步骤,完成文章微服务模块的基础构建与验证。
166 0
|
负载均衡 Java Nacos
Ribbon负载均衡
Ribbon负载均衡
166 1
Ribbon负载均衡
|
负载均衡 算法 架构师
Ribbon负载均衡
上一节就已经实现的负载均衡笔者并未深入探讨,本节通过分析负载均衡算法、Ribbon实现负载均衡的底层原理和实现过程,让大家对负载均衡有了一个大体认识,同时针对Ribbon自定义负载均衡策略,饥饿加载让大家对于Ribbon的了解又多一些。Ribbon实现的负载均衡只是方案之一,我们可以尽量多了解但不要局限于此。
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
1215 61
|
负载均衡 Java 持续交付
深入解析微服务架构中的服务发现与负载均衡
深入解析微服务架构中的服务发现与负载均衡
729 7
|
负载均衡 Java Nacos
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
微服务介绍、SpringCloud、服务拆分和远程调用、Eureka注册中心、Ribbon负载均衡、Nacos注册中心
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
|
负载均衡 算法 网络协议
Ribbon 负载均衡源码解读
Ribbon 负载均衡源码解读
201 15
Ribbon 负载均衡源码解读