4、深入理解ribbon

news2024/12/23 13:53:13

一、负载均衡的两种方式

  • 服务器端负载均衡

    传统的方式前端发送请求会到我们的的nginx上去,nginx作为反向代理,然后路由给后端的服务器,由于负载均衡算法是nginx提供的,而nginx是部署到服务器端的,所以这种方式又被称为服务器端负载均衡。

    image.png

  • 客户端侧负载均衡

现在有三个实例,内容中心可以通过discoveryClient 获取到用户中心的实例信息,如果我们再订单中心写一个负载均衡的规则计算请求那个实例,交给restTemplate进行请求,这样也可以实现负载均衡,这个算法里面,负载均衡是有订单中心提供的,而订单中心相对于用户中心是一个客户端,所以这种方式又称为客户端负负载均衡。

image.png

二、手写一个客户端侧负载均衡器

◆随机选择实例

@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/order/create")
public String createOrder(Integer productId,Integer userId){
    List<ServiceInstance> instances = discoveryClient.getInstances("msb-stock");
    List<String> targetUrls = instances.stream()
        // 数据变换
        .map(instance -> instance.getUri().toString() + "/stock/reduce")
        .collect(Collectors.toList());
    int i = ThreadLocalRandom.current().nextInt(targetUrls.size());
    String targetUrl = targetUrls.get(i);
    log.info("请求求目标地址:{}",targetUrl);
    String result = restTemplate.getForObject(targetUrl +"/"+ productId, String.class);
    log.info("进行减库存:{}",result);
    return "下单成功";
}

三、使用Ribbon实现负载均衡

Ribbon是什么?
Netflix开源的客户端侧负载均衡器

更加直观说就是ribbon就是简化我们这段代码的小组件,不过他比我们的代码要强大一些,他给他们提供了丰富的负载均衡算法。

image.png

引入ribbon :三步骤: 加依赖,启动注解,写配置

不需要加,nacosdiscovery,已经给添加了依赖,

image.png

写注解,需要写到RestTemplate上面。

image.png

第三步:写配置

没有配置。

改造我们的请求:

url:改为 下面 当请求发送的发送的时候ribbon会将nx-us进行转化为我们nacos里面中的地址。并且进行负载均衡算法,进行请求,

image.png

四、Ribbon的重要接口 以及内置负载均衡规则

1、Ribbon重要接口

接口作用默认值
IClientConfig读取配置DefaultclientConfigImpl
IRule负载均衡规则,选择实例ZoneAvoidanceRule
IPing筛选掉ping不通的实例默认采用DummyPing实现,该检查策略是一个特殊的实现,<br />实际上它并不会检查实例是否可用,而是始终返回true,默认认为所<br />有服务实例都是可用的.
ServerList<Server>交给Ribbon的实例列表Ribbon: ConfigurationBasedServerList<br /> Spring Cloud Alibaba: NacosServerList
ServerListFilter过滤掉不符合条件的实例ZonePreferenceServerListFilter
ILoadBalancerRibbon的入口ZoneAwareLoadBalancer
ServerListUpdater更新交给Ribbon的List的策略PollingServerListUpdater

2、Ribbon负载均衡规则

我们说一下常用的规则

规则名称特点
RandomRule随机选择一个Server
NacosRule同集群优先调用
RetryRule对选定的负责均衡策略机上充值机制,在一个配置时间段内当选择Server不成功,则一直尝试使用subRule的方式选择一个可用的Server
RoundRobinRule轮询选择,轮询index,选择index对应位置Server
WeightedResponseTimeRule根据相应时间加权,相应时间越长,权重越小,被选中的可能性越低
ZoneAvoidanceRule(默认是这个)该策略能够在多区域环境下选出最佳区域的实例进行访问。在没有Zone的环境下,类似于轮询(RoundRobinRule)

六、细粒度配置自定义

ribbon支持非常灵活的配置,用的最多的就是配置他的负载均衡规则,比如:默认ZoneAvoidanceRule 满足不了我们的要求,我们想把这个规则改为随机,ribbon支持细粒度的配置,加入内容中心同时调用两个微服务,那么调用第一个微服务的时候我们可以用随机方式,第二种我们用默认的配置,好这样我们围着这个场景来看一下怎样配置。

先看Java代码的配置。

1、类配置方式

这里的配置类需要放到springboot扫描路径之外,这个需要注意的点。

public class RibbonConfiguration {
    @Bean
    public IRule ribbonRule(){
        //随机选择
        return new RandomRule();
    }
}
/**
* 指定配置
**/
@Configuration
@RibbonClient(name = "nx-user",configuration = RibbonConfiguration.class)
public class UserRibbonConfiguration {
}

image.png

讲解我们这里配置类并没有增加配置类注解

如果放到springboot能扫描的地方就会成为全局配置文件。对所有的调用都会用这个规则。

2、属性配置方式

将前面的配置注释掉:

如下进行配置:

msb-stock:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

3、优先级高低

java配置的要高, 我们可以类配置的路由规则为随机(RandomRule),然后属性配置为轮训(RoundRobinRule);

测试是随机则java配置高于属性配置

4、全局配置

◆方式一︰让ComponentScan上下文重叠(强烈不建议使用

image.png

◆方式二【唯正确的途径】:
@RibbonClients(defaultConfiguration=xxx.class)

就是将RibbonClient改为RibbonClients 将configuration改为defaultConfiguration

image.png

七、支持的配置项

那ribbon那些是支持自定义呢? 下面都支持自定义。

接口作用默认值
IRule负载均衡规则,选择实例ZoneAvoidanceRule
IPing筛选掉ping不通的实例DumyPing(该类什么不干,认为每个实例都可用,都能ping通)
ServerList<Server>交给Ribbon的实例列表Ribbon: ConfigurationBasedServerList<br /> Spring Cloud Alibaba: NacosServerList
ServerListFilter过滤掉不符合条件的实例ZonePreferenceServerListFilter
ILoadBalancerRibbon的入口ZoneAwareLoadBalancer

ServerListUpdaterClassName

  • NFLoadBalancerClassName : ILoadBalancer 实现类
  • NFLoadBalancerRuleClassName : IRule实现类
  • NFLoadBalancerPingClassName : IPing 实现类
  • NIWSServerListClassName : ServerList实现类
  • NIWSServerListFilterClassName : ServerListFilter实现类

八、饥饿加载

ribbon默认是懒加载的,只有第一层调用的时候才会生成userCenter的ribbonClient,这就会导致首次调用的会很慢的问题。

ribbon:
  eager-load:
    enabled: true
      clients: msb-stock

九、源码分析

1、猜测源码的实现

我们在看源码的时候我们可以根据功能先想一下,他是怎样实现的,如果让我们来实现我们会怎么做,我们想ribbon不过就是替换nx-stock,为ip+端口我们会怎样做,大家想一下 ? 是不是我们可以增加加一个拦截器, 如下,你这样有这样一个思维再去看源码就应该容易一点:我们RestTemplate有一个扩展点是

ClientHttpRequestInterceptor 我们Ribbon通过LoadBalancerInterceptor实现了这个扩展早点,将nx-stock替换为 192.168.0.3:8003

image.png

image.png

2、初始化的过程

我们首先进入我们的注解@LoadBalanced,我们学spring源码的时候一般是注解中增加一个@Import,引入一个对象此时他没有,所以我们想它是和springboot整合的,所以我们可以找到同包下的spring.factories中,看一下,自动装配类。

我们先进入spring-cloud-starter-netflix-ribbon.2.2.6

.Release 里面乜有对应spring.factories,他是空的,这和我们讲springboot时候说mybatis一样,starter是空的但是他能引用一些自动配置的jar,我们进去看

image.png

image.png

导入了RibbonAutoConfiguration

image.png

image.png

我们可以全文搜索一下哪里加载了LoadBalancerAutoConfiguration,

image.png

这样应该和我们的LoadBalanced注解有关

image.png

AsyncLoadBalancerAutoConfiguration和LoadBalancerAutoConfiguration应该和我们对应的注解有关系,那么我们想Async是应该和异步有关系应该是更高级的作用,所以我们进入LoadBalancerAutoConfiguration这个类。 我们进入配置类中发现

好这里面就应该是我们找的类,这里应该是获取容器中所有标注@LoadBalanced注解的所有类。

image.png

我们进入LoadBalancerAutoConfiguration 里面初始化一些对象,

我们这里初始化一个对象是LoadBalanceInterceptor,这就是一个拦截器,然后后面是一个RestTemplateCustomizer,我们从名字可以看出他就是一个自定义的RestTemplate,我们可以看一下里面内容就有一个customize方法,我们这里用哪个lambda表达式来处理,就是穿进去一个restTemplate然后给里面增加一个拦截器。这个拦截器里面就是上面弄的LoadBalancerInterceptor。

image.png

image.png

接着还有一个对象就是:SmartInitializingSingleton

image.png

这一部分就是给我们的restTemplate增加了拦截器。

image.png

接下来我们就可以进入拦截器查看一下,进入拦截器是不是就查看intercept,写过拦截器一个知道他最重要的方法就是intercept

3、负载均衡的过程

request.getURI(), 这个不用我多解释了吧,restTemplate就是发送http请求,这里获取他的请求链接,然后获取他的host,他的host是什么就是nx-stock,就是serviceName,然后将这serviceName传递到我们的execute里面,我们推想这里很可能对我们serviceName进行解析,从我们的nacos注册中心获取注册列表,然后通过负均衡选择一个合适的地址,进行调用。

image.png

这里我么可以一个看到第一个应该是获取负载均衡器,第一个是根据负载均衡器来获取对应的一个服务

image.png

那我们简单看一下怎样获取负载均衡器:

image.png

image.png

image.png

AnnotationConfigApplicationContext 就是我们注解配置的上下文,我们则是从容器中获取对应的对象,ILoadBalancer对应的负载均衡器。

image.png

我们可以看出是从一个Map里获得,如果没有我们需要创建他createContext

image.png

image.png

获取配置然后注册刷新容器,这里和我们的spring容器一样。

image.png

所以我们一定有一个地方是创建这个对象,然后注入容器的,那一定是一个配置类,其实他是在RibbonClientConfiguration这个类中。在这里其实就是我们对应ribbon可配置类的默认配置是在这里配置,看这里每个注入类对应的注解@ConditionalOnMissingBean,从这里我们能知道我们配置了我们自己的类就用我们自己的类,如果没有配置我们自己的类,就会用到默认的配置类。

从这里我们能验证一个事情,@ConditionOnMissingBean中是查看容器中是否有对应的ILoadBalancer如果有则使用,如果没有则调用这个方法,然后我们看一下这个方法propertiesFactory是查看property中是否设置了我们的配置,如果有则获取到,没有则是获取默认的,

所以这里证明一个前面的结论: java配置高于属性配置

image.png

好,看到这里就可以,当然我们也可以查看一下这个负载均衡器,但里面对应的内容很复杂,我们知道我们获取一个负载均衡器就可以了,后面可以不看。等我们后面用的时候再看。

好我们回到刚才的位置:

通过这个名称getServer我们就应该知道,这个应该是通过负载均衡器中的算法获取对应一个服务

image.png

这里是调用这个负载均衡器的chooseServer,通过名称我们就知道这里是选择一个服务,这里肯定是从nacos中获取对应的服务列表,然后选择一个进行调用。

image.png

在这里我们可以看到我们应该调用ZoneAvoidanceRule

image.png

image.png

进入后我们看到一个关键方法就是role.choose,这里面我们发现他有很多实现,刚才我们说过RibbonClientConfiguration初始化了我们一些默认的对应的类,

image.png

我们可以发现这里创建了一个默认的规则ZoneAvoidanceRule,所以就会调用他方法,同时我们也要看一下他的集成关系,因为我们调用的方法可能是他的父类中的方法,

image.png

image.png

这里没有对应的ZoneAvoidanceRule 但是有PredicateBasedRule,所以会调用这个方法。

image.png

首先获取一个负载均衡器,然后这里chooseRoundRobinAfterFiltering 从这个方法我们就知道,这里使用轮训方法,ZoneAvoidanceRule如果没有设置时钟就会才用轮训算法,接着这里通过负载均衡器获取对应所有的server,我们可以推算这里是应该是从nacos中获取对应的服务列表,当然我们先不考虑他是怎样获取的,我们先知道他这里获取对应的服务列表就可以。

image.png

image.png

下面就轮训机制获取对应有效的服务,首先看一下 nextIndex他是AtomicInteger类型,我们首先获取对应的值,然后加一求余,得到next值,然后

nextIndex.compareAndSet方法,判断是否是current这个值,如果是则返回,并且将next值设置进去,方便下一次的获取,这就是轮训机制,大家能不能明白,

好,那我们看这里用掉了cas方式,这样大大提高了他的性能,如果不用cas的话就需要用到lock,这样性能就会降低,当然如果设置返回false,他还会进入下一次循环处理是吧, 这就是并发编程中的应用,我们可能在工作中做业务用不到,但是你写一些中间件或者上大厂这些就用到的很多了,所以并发编程的基本功一定要搞好。

image.png

好,负载均衡我们说完了,我们看一下我们的server是怎么样获取的。

4、获取服务列表

我们要从我们的负载均衡器中看起,因为我们前面就是从负载均衡器中获取对应的server列表

image.png

image.png

我们可以进入我们的配置类中RibbonClientConfiguration中查看对应的创建。从这里构造方法我们可以看到对应的serverList,所以说他是在创建构造方法的时候就已经获取到对应的服务列表,好我们看他的服务列表是怎么获取的。

image.png

好,我们来全文搜索一下 , 这里是从配置文件中获取对应的配置server,因为我们的ribbon可以独立使用的,所以我们这里获取的serverlist应该是空的。

image.png

好,这里我们进入负载均衡器的构造方法里面。

这里面有个restofInit方法,好这里的init方法我们可以进去看看,看到这个init或者start方式都是重要方法,我们可以进去看一下

image.png

看这个方法,我们可以翻译一下 这里 了开启并初始化学习新服务的特点, 这是什么意思我们可以看一下

image.png

image.png

他们最后会调用这个updateListOfServers方法,这个是重点后面我们会看到。

=image.png

image.png

image.png

image.png

获取实例

image.png

这里就和nacos中获取数据

image.png

image.png

5、更新服务列表

image.png

image.png

image.png

进行服务赋值,后面就可以使用了

image.png

6、重构请求的URL

image.png

此时我们需要debug进入这个容器中:

image.png

image.png

路跟下来发现在⼀个匿名内部类中,发现了很可疑的地点:ServiceRequestWrapper,服务请求的⼀个

包装类,难不成在这⾥重构请求,有点接近了,进去看下:

image.png

image.png

debug进入就会发现里面对host的替换

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/767397.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】多线程(二)

文章目录 生产者消费者模型为何要使用生产者消费者模型生产者消费者模型优点基于BlockingQueue的生产者消费者模型条件变量条件变量代码 POSIX信号量基于环形队列的生产消费模型 生产者消费者模型 为何要使用生产者消费者模型 生产者消费者模式就是通过一个容器来解决生产者和…

qt与opencv学习记录

qtopencv开发入门&#xff1a;4步搞定环境配置-1_哔哩哔哩_bilibili qtopencv开发入门&#xff1a;4步搞定opencv环境配置2_哔哩哔哩_bilibili 文章内容来自上面两个视频&#xff0c;感谢创作者。 ps&#xff1a;配置环境的过程中&#xff0c;遇到了很多问题&#xff0c;我…

UML 图

统一建模语言&#xff08;Unified Modeling Language&#xff0c;UML&#xff09;是用来设计软件的可视化建模语言。它的特点是简单、统一、图形化、能表达软件设计中的动态与静态信息。 UML 从目标系统的不同角度出发&#xff0c;定义了用例图、类图、对象图、状态图、活动图…

网络流量监控分析

网络管理员是维护健全网络基础设施的关键&#xff0c;这通常是一项艰巨的任务&#xff0c;因为管理员需要 24x7 全天候监控和管理网络和服务器。但是&#xff0c;即使进行全天候监控&#xff0c;每个网络也容易受到带宽占用的影响&#xff0c;如果导致关键业务应用程序变慢&…

CSS 实现 Turbo 官网 3D 网格线背景动画

转载请注明出处&#xff0c;点击此处 查看更多精彩内容 查看 Turbo 官网 时发现它的背景动画挺有意思&#xff0c;就自己动手实现了一下。下面对关键点进行解释说明&#xff0c;查看完整代码及预览效果请 点击这里。 简单说明原理&#xff1a;使用 mask-image 遮罩绘制网格&a…

二叉树--C语言实现数据结构

本期带大家一起用C语言实现二叉树&#x1f308;&#x1f308;&#x1f308; 1、二叉树的定义 二叉树是一种特殊的树状数据结构&#xff0c;它由节点组成&#xff0c;每个节点最多有两个子节点&#xff0c;分别称为左子节点和右子节点 二叉树的链式存储结构是指用 链表 来表示…

公司私服Maven踩坑,项目配置都OK但是包就是下载不下来【已解决】

我的问题是公司的私服Maven下载不下来&#xff0c;因为公司保密协议&#xff0c;这里用阿里云为例&#xff01; 具体的至少参考&#xff1a;(32条消息) 这篇博文只讲MirrorOf_Java软件工程师的博客-CSDN博客 1&#xff1a;Java的Maven爆红了就找到资源库&#xff0c;然后把对于…

2.10messagebox弹窗

2.10messagebox弹窗 messagebox部件 其实这里的messagebox就是我们平时看到的弹窗。 我们首先需要定义一个触发功能&#xff0c;来触发这个弹窗 这里我们就放上以前学过的button按钮 tk.Button(window, texthit me, commandhit_me).pack()通过触发功能&#xff0c;调用messa…

超高性能协议框架fury完爆protostuff(附性能测试对比)

简单介绍: 序列化框架是系统通信的基础组件&#xff0c;在大数据、AI 框架和云原生等分布式系统中广泛使用。当对象需要跨进程、跨语言、跨节点传输、持久化、状态读写、复制时&#xff0c;都需要进行序列化&#xff0c;其性能和易用性影响运行效率和开发效率。 Fury 是一个基于…

3.2.18 DIR函数的补充说明

【分享成果&#xff0c;随喜正能量】人与人之间都是相互的&#xff0c;你给人搭桥&#xff0c;别人为你铺路&#xff1b;你让人难堪&#xff0c;别人给你添堵。。 我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的劳动效…

【小梦C嘎嘎——启航篇】C++ 基础中的精华(二)

【小梦C嘎嘎——启航篇】C 基础中的精华&#xff08;二&#xff09;&#x1f60e; 前言&#x1f64c;1、引用的使用场景1.1 做参数1.2 做返回值 2、const修饰 的引用2.1 权限上的探讨2.1.1权限放大2.1.2 权限平移2.1.3 全新缩小 4、函数重载的延伸条件编译&#xff1a; 条件编译…

自定义类型详解(C语言)

自定义类型 一. 结构体1.1 什么是结构体1.2 结构体的声明1.3 特殊的声明1.4 结构体的自引用1.5 结构体变量的定义和初始化1.5.1 结构体变量的定义1.5.2 结构体变量的初始化 1.6 结构体内存对齐1.6.1 为什么存在内存对齐 1.7 修改默认对齐数1.8 结构体传参 二. 位段2.1 什么是位…

PVE安装好后拔显卡后连接不了网络

目录 前因 原因 解决办法 前因 前几天装了个​Proxmox​ ve当做一个服务器7*24开机 但是由于转好系统后&#xff0c;显卡就不需要了 加上它耗电的原因&#xff08;我的gtx650平时空载有10w左右的功耗&#xff09; 我在想拔显卡拔了&#xff0c;我用xshell进行ssh连接不就…

MVCC:多版本并发控制

MVCC 1. MVCC是什么2. 快照读和当前读2.1 快照读2.2 当前读 3. Read View3.1 Read View中含有什么内容3.2 ReadView的规则 4. MVCC整体操作流程 1. MVCC是什么 MVCC&#xff08;Multi Version Concurrency Control&#xff09;&#xff0c;多版本并发控制&#xff1b;MVCC用于…

【数学建模】——相关系数

第一部分&#xff1a;皮尔逊相关系数的计算以及数据的描述性统计 本讲我们将介绍两种最为常见的相关系数&#xff1a;皮尔逊person相关系数和斯皮尔曼spearman等级相关系数。它们可以用来衡量两个变量之间的相关性的大小&#xff0c;根据数组满足的不同条件&#xff0c;我们要选…

linux图形界面总结——X、Xorg、WM、QT、GTK、KDE、GNOME的区别与联系

文章目录 一、 linux图形界面二、X协议三、Xfree86 Xorg四、WM(window manager:窗口管理器)五、X协议的Client端实现六、KDE、GNOME、QT和GTK直接关系七、参考&#xff1a; 一、 linux图形界面 linux本身没有图形界面&#xff0c;linux现在的图形界面的实现只是linux下的应用程…

网络类型及数据链路层协议

目录 网络类型的分类 数据链路层协议 MA网络以太网协议 P2P网络 HDLC ---高级数据链路控制协议 更改链路协议的方法 HDLC数据帧封装结构 PPP---点到点协议 PPP协议的优点 PPP数据帧封装结构 PPP会话的搭建 链路建立阶段---LCP建立 认证阶段 网络层协议协商阶段--- NCP协商 网络…

大型风电叶片研发项目管理体系建设实践︱中车时代新材PMO负责人姚运帅

中车株洲时代新材料科技股份有限公司风电运维事业部总经理、PMO负责人姚运帅先生受邀为由PMO评论主办的2023第十二届中国PMO大会演讲嘉宾&#xff0c;演讲议题&#xff1a;大型风电叶片研发项目管理体系建设实践。大会将于8月12-13日在北京举办&#xff0c;敬请关注&#xff01…

sqlserver 存储过程当中如何实现增删改查

--声明存储过程 新增编辑 ALTER procedure [dbo].[Eng_MyAddOrEdtADPro] My_Cocode int, Type int, -- --1 新增 2 编辑 My_KeyId uniqueidentifier, My_PCode int, My_SCode int, My_PName nvarchar(36), My_SName nvarchar(36), My_Orde…

IPUU的小工具拍了拍你(下)

IPUU是埃文科技旗下的综合性IP查询网站&#xff0c;提供多维度的IP数据信息。通过在线查询&#xff0c;用户可以获取目标IP地址的详尽信息&#xff0c;包括位置属性、网络属性、风险属性以及业务属性等&#xff0c;同时还可以查询域名信息。无论您是需要查看某个IP地址归属地&a…