微服务【Ribbon负载均衡&源码解析&饥饿加载】第2章

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
注册配置 MSE Nacos/ZooKeeper,118元/月
云原生网关 MSE Higress,422元/月
简介: 本文主要介绍:1,Ribbon负载均衡原理 2,源码跟踪 3,负载均衡策略 4,饥饿加载

1,负载均衡原理

1.1:负载均衡原理

SpringCloud底层其实是利用了一个名为Ribbon的组件,来实现负载均衡功能的

负载均衡流程图:

image.gif编辑

那么我们发出的请求明明是http://userservice/user/1,怎么变成了http://localhost:8081的呢?

具体Ribbon什么时候拦截下来的请求?什么时候从注册中心拉取下来的?什么时候做的负载均衡呢?下面我们进入idea中分析源码

1.2:源码跟踪

首先看到restTemplate被LoadBalanced进行标记,意思就是说

通过restTemplate发起的请求会被LoadBalanced进行处理拦截

image.gif编辑

那么这个拦截的动作在底层中是通过谁进行完成的呢?就是:LoadBalancerInterceptor

1)LoadBalancerInterceptor

首先在编辑器中Ctrl+Shift+N搜索 LoadBalancerInterceptor 该实现类

image.gif编辑

点进去查看一下源码:该实现类实现了ClientHttpRequestInterceptor接口,那么这个接口是干嘛的呢?

image.gif编辑

 该接口是客户端请求拦截器,那么restTemplate不就是一个发Http请求的客户端嘛!被拦截image.gif编辑

既然实现类实现了ClientHttpRequestInterceptor接口,也实现了接口中的intercept方法,下面看一下这个方法具体在干嘛!(打个断点演示一下,图片放大更清楚)

image.gif编辑

可以看到这里的intercept方法,拦截了用户的HttpRequest请求,然后做了几件事:

    • request.getURI()获取请求uri,本例中就是http://service-provide/echo/love
    • originalUri.getHost()获取uri路径的主机名,其实就是服务id,service-provide
    • this.loadBalancer.execute()处理服务id,和用户请求

    这里的this.loadBalancerLoadBalancerClient类型,我们继续跟入。  

    2)LoadBalancerClient

    继续跟入execute方法:

    image.gif编辑

    跟入到此接口中:

    image.gif编辑

    跟入到接口的实现类中:

    image.gif编辑

    总结:

    跟踪到execute方法中,将参数服务Id传递进来交给Load Balancer函数进行处理,

    返回出:动态服务列表负载均衡器。

    这个负载均衡器是干嘛的?

    通过服务Id获取到服务注册中心的服务列表,现在这一步已经把服务拉取到了

    image.gif编辑  

    下一步进行负载均衡

    3)负载均衡策略IRule

    在刚才的代码中,可以看到获取服务使通过一个getServer方法来做负载均衡:

    image.gif编辑

    我们继续跟入:

    image.gif编辑

    继续跟踪源码chooseServer方法,发现这么一段代码:  

    image.gif编辑

    我们看看这个rule是谁:

    image.gif编辑

    对象是IRule对象,我们知道I是接口,Rule是规则,那么就是规则接口,那接口有实现类,咱们Ctrl+H查看一下继承树

    image.gif编辑

    image.gif编辑到这里,整个负载均衡的流程我们就清楚了。

    4)总结

    SpringCloudRibbon的底层采用了一个拦截器,拦截了RestTemplate发出的请求,对地址做了修改。用一幅图来总结一下:

    image.gif编辑

    基本流程如下:

      • 拦截我们的RestTemplate请求http://localhost:8071/fangwen/love
      • RibbonLoadBalancerClient会从请求url中获取服务名称
      • DynamicServerListLoadBalancer根据user-service到nacos拉取服务列表
      • nacos返回列表
      • IRule利用内置负载均衡规则,从列表中选择一个,
      • RibbonLoadBalancerClient修改请求地址,发起真实请求

      1.3:负载均衡策略

      1.3.1:负载均衡策略

      负载均衡的规则都定义在IRule接口中,而IRule有很多不同的实现类:

      image.gif编辑

      不同规则的含义如下:

      image.gif编辑

      默认的实现就是ZoneAvoidanceRule,是一种轮询方案  

      1.3.2:自定义负载均衡策略

      通过定义IRule实现可以修改负载均衡规则,有两种方式

        1. 代码方式:在order-service中的OrderApplication类中,定义一个新的IRule:
        @Bean
        public IRule randomRule(){
            return new RandomRule();
        }

        image.gif

            2. 配置文件方式:在application.yml文件中,添加新的配置也可以修改规则:

        userservice: # 给某个微服务配置负载均衡规则,这里是userservice服务
          ribbon:
            NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则

        image.gif

        注意,一般用默认的负载均衡规则,不做修改。

        1.4:饥饿加载

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

        什么意思呢?(访问监测一下)

        第一次请求:请求耗时如此之长

        image.gif编辑

        第二次请求:请求耗时很短

        image.gif编辑

        为什么会有这种变化呢?

        当然导致请求耗时过长的因素有很多,在这里最重要的一个因素是Ribbon采用了懒加载。

        那么何为懒加载?

        即第一次访问时才会去创建LoadBalanceClient,去服务注册中心拉取服务,导致时间加载过长。

        为了解决第一次访问才创建LoadBalanceClient导致耗时过长,可以采用饥饿加载。

        何为饥饿加载?

        饥饿加载则会在项目启动时进行创建,降低第一次访问的耗时,通过下面配置yml文件开启饥饿加载:

        ribbon:

         eager-load:

           enabled: true   # 开启饥饿加载

           clients: userservice   # 指定对userservice这个服务饥饿加载

        相关实践学习
        SLB负载均衡实践
        本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
        负载均衡入门与产品使用指南
        负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
        相关文章
        |
        7天前
        |
        监控 Java 应用服务中间件
        高级java面试---spring.factories文件的解析源码API机制
        【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
        23 2
        |
        7天前
        |
        存储 安全 Linux
        Golang的GMP调度模型与源码解析
        【11月更文挑战第11天】GMP 调度模型是 Go 语言运行时系统的核心部分,用于高效管理和调度大量协程(goroutine)。它通过少量的操作系统线程(M)和逻辑处理器(P)来调度大量的轻量级协程(G),从而实现高性能的并发处理。GMP 模型通过本地队列和全局队列来减少锁竞争,提高调度效率。在 Go 源码中,`runtime.h` 文件定义了关键数据结构,`schedule()` 和 `findrunnable()` 函数实现了核心调度逻辑。通过深入研究 GMP 模型,可以更好地理解 Go 语言的并发机制。
        |
        20天前
        |
        消息中间件 缓存 安全
        Future与FutureTask源码解析,接口阻塞问题及解决方案
        【11月更文挑战第5天】在Java开发中,多线程编程是提高系统并发性能和资源利用率的重要手段。然而,多线程编程也带来了诸如线程安全、死锁、接口阻塞等一系列复杂问题。本文将深度剖析多线程优化技巧、Future与FutureTask的源码、接口阻塞问题及解决方案,并通过具体业务场景和Java代码示例进行实战演示。
        39 3
        |
        1月前
        |
        存储
        让星星⭐月亮告诉你,HashMap的put方法源码解析及其中两种会触发扩容的场景(足够详尽,有问题欢迎指正~)
        `HashMap`的`put`方法通过调用`putVal`实现,主要涉及两个场景下的扩容操作:1. 初始化时,链表数组的初始容量设为16,阈值设为12;2. 当存储的元素个数超过阈值时,链表数组的容量和阈值均翻倍。`putVal`方法处理键值对的插入,包括链表和红黑树的转换,确保高效的数据存取。
        56 5
        |
        1月前
        |
        Java Spring
        Spring底层架构源码解析(三)
        Spring底层架构源码解析(三)
        111 5
        |
        6月前
        |
        负载均衡 算法 应用服务中间件
        面试题:Nginx有哪些负载均衡算法?Nginx位于七层网络结构中的哪一层?
        字节跳动面试题:Nginx有哪些负载均衡算法?Nginx位于七层网络结构中的哪一层?
        130 0
        |
        5月前
        |
        缓存 负载均衡 算法
        解读 Nginx:构建高效反向代理和负载均衡的秘密
        解读 Nginx:构建高效反向代理和负载均衡的秘密
        122 2
        |
        4月前
        |
        负载均衡 算法 应用服务中间件
        nginx自定义负载均衡及根据cpu运行自定义负载均衡
        nginx自定义负载均衡及根据cpu运行自定义负载均衡
        85 1
        |
        4月前
        |
        运维 负载均衡 算法
        SLB与NGINX的异同是什么
        SLB与NGINX的异同是什么
        448 2
        |
        6月前
        |
        负载均衡 应用服务中间件 nginx
        解决nginx配置负载均衡时invalid host in upstream报错
        在Windows环境下,配置Nginx 1.11.5进行负载均衡时遇到问题,服务无法启动。错误日志显示“invalid host in upstream”。检查发现上游服务器列表中,192.168.29.128的主机地址无效。负载均衡配置中,两个服务器地址前误加了"http://"。修正方法是删除上游服务器列表和proxy_pass中的"http://"。问题解决后,Nginx服务应能正常启动。
        504 4
        解决nginx配置负载均衡时invalid host in upstream报错

        推荐镜像

        更多
        下一篇
        无影云桌面