【微服务 SpringCloud】实用篇 · Ribbon负载均衡

微服务(4)

文章目录

微服务(4)

在前面,我们添加了@LoadBalanced注解,即可实现负载均衡功能,这是什么原理、什么策略呢?

1. 负载均衡原理

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

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

2. 源码跟踪

为什么我们只输入了service名称就可以访问了呢?之前还要获取ip和端口。

Ribbon是怎么拦截这个请求,并将url进行处理的呢?

显然有人帮我们根据service名称,获取到了服务实例的ip和端口。它就是LoadBalancerInterceptor,这个类会在对RestTemplate的请求进行拦截,然后从Eureka根据服务id获取服务列表,随后利用负载均衡算法得到真实的服务地址信息,替换服务id。

我们进行源码跟踪(双击shift搜索):

1)LoadBalancerIntercepor

调试一下:

打个断点:

浏览器访问:

停在这了:

跳两步观察:

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

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

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

2)LoadBalancerClient

继续跟入execute方法,调用getLoadBalancer方法:

调用getServer方法:

这个就是我们的内网ip(命令行cmd,ipconfig查看)

代码是这样的:

  • getLoadBalancer(serviceId):根据服务id获取ILoadBalancer,而ILoadBalancer会拿着服务id去eureka中获取服务列表并保存起来。
  • getServer(loadBalancer):利用内置的负载均衡算法,从服务列表中选择一个。本例中,可以看到获取了8081端口的服务

放行后,再次访问并跟踪,发现获取的是8082:

果然实现了负载均衡。

3)负载均衡策略IRule

跟进getServer方法:

进入方法内部:

  • 通过规则选择

IRule,故名思意就是规则接口,想必就是负载均衡算法的规则取决于它

可见IRule接口有很多的实现

最明显的就是RandomRule,顾名思义就是随机;RoundRobinRule,顾名思义就是轮询调度

而现在的规则是:ZoneAvoidanceRule

key是default(其实就是尝试从配置文件里获取常量,没有配置就获取不到,就默认咯)

我们看看这个rule是谁:

这不就是轮询的意思嘛。

到这里,整个负载均衡的流程我们就清楚了,至于这些策略规则是什么,随后讲解~

4)总结

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

基本流程如下:

  • 拦截我们的RestTemplate请求http://userservice/user/1
  • RibbonLoadBalancerClient会从请求url中获取服务名称,也就是userservice
  • DynamicServerListLoadBalancer根据userservice到eureka拉取服务列表
  • eureka返回列表,localhost:8081、localhost:8082
  • IRule利用内置负载均衡规则,从列表中选择一个,例如localhost:8081
  • RibbonLoadBalancerClient修改请求地址,用localhost:8081替代userservice,得到http://localhost:8081/user/1,发起真实请求

3. 负载均衡策略

3.1 负载均衡策略

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

不同规则的含义如下:

内置负载均衡规则类 规则描述
RoundRobinRule 简单轮询服务列表来选择服务器。
AvailabilityFilteringRule 对以下两种服务器进行忽略: (1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为"短路"状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。 (2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上限,可以由客户端的..ActiveConnectionsLimit属性进行配置。
WeightedResponseTimeRule 为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。
ZoneAvoidanceRule 以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做轮询。(如果没有Zone的划分,其实就是跟普通轮询没啥区别)
BestAvailableRule 忽略那些短路的服务器,并选择并发数较低的服务器。
RandomRule 随机选择一个可用的服务器。
RetryRule 重试机制的选择逻辑

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

默认情况下,浏览器依次访问101、102、103、104,查看日志:(右侧栏有个垃圾桶,点击清空日志)

其实每次都这样(一个2 4;一个1 3),就是轮询策略~

3.2 自定义负载均衡策略

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

  1. 代码方式:在order-service中的OrderApplication类中,定义一个新的IRule:
    • 那么ribbon就会以这个bean的规则优先
java 复制代码
@Bean
public IRule randomRule(){
    return new RandomRule();
}

效果:

每次都不一样,甚至会出现有一个服务一个都没有,很明显是随机(次数多了还每个服务的调用次数是很均衡的)

  1. 配置文件方式:在order-service的application.yml文件中,添加新的配置也可以修改规则:
yaml 复制代码
userservice: # 给某个微服务配置负载均衡规则,这里是userservice服务
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则 

效果一致~

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

  1. 配置文件的设置优先级较高 ,如果代码方法设置的是A,配置方法设置的是B,则最终呈现是B
  2. 代码设置的是全局的方案,也就是说在order-service访问哪个微服务的都是这个规则
  3. 配置设置的是特定的微服务负载均衡规则(优先级高也正常了)
    • 从配置设置的键(userservice)可见,是针对一个微服务的

4. 饥饿加载

不知道你有没有发现,我们浏览器测试刚才的用例的时候,第一次要反应一会儿,后面的就很流畅:

我们通过浏览器开发者工具来看看第一次访问的时候的时间:

达到恐怖的744ms!

而之后就比较快了:

这是因为:

  • Ribbon默认是采用懒加载,即第一次访问时才会去创建LoadBalanceClient,请求时间会很长。
  • 严格来说是第一次用到这个服务的LoadBalanceClient才会加载
  • 加载之后就缓存下来了,可以直接用或者下一次拉取直接赋值给这个对象就行了
    • 当然,如果是别的服务的LoadBalanceClient,还需要加载

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

yaml 复制代码
ribbon:
  eager-load:
    enabled: true # 默认false为懒加载,这里设置为true为饥饿加载
    clients: userservice # 指定对哪个微服务饥饿加载
  • clients的值是一个集合,可以这么写:

重启

  • 可见已经加载

观察一下时间:

第一次访问快了不少了(第一次也要加载一些框架之类的,当然也可以设置为饥饿加载,不在这里演示)


文章到此结束!谢谢观看

可以叫我 小马 ,我可能写的不好或者有错误,但是一起加油鸭🦆

代码:cloud-demo · 游离态/云服务 - 码云 - 开源中国 (gitee.com)


相关推荐
阿里云云原生1 小时前
稳定支撑大规模模型调用,携程旅游的 AI 网关实践
微服务
不会聊天真君6471 小时前
ES(springcloud笔记第五期)
笔记·elasticsearch·spring cloud
叫我阿柒啊3 小时前
从Java全栈到前端框架的实战之路
java·数据库·微服务·typescript·前端框架·vue3·springboot
蒋星熠3 小时前
WebSocket网络编程深度实践:从协议原理到生产级应用
网络·数据库·redis·python·websocket·网络协议·微服务
草履虫建模4 小时前
在 RuoYi 中接入 3D「园区驾驶舱」:Vue2 + Three.js + Nginx
运维·开发语言·javascript·spring boot·nginx·spring cloud·微服务
remaindertime4 小时前
(九)Spring Cloud Alibaba 2023.x:微服务接口文档统一管理与聚合
后端·spring cloud·微服务
橘子在努力4 小时前
【橘子SpringCloud】OpenFegin源码分析
java·spring boot·spring·spring cloud
喂完待续5 小时前
【序列晋升】31 Spring Cloud App Broker 微服务时代的云服务代理框架
spring·spring cloud·微服务·云原生·架构·big data·序列晋升
thginWalker9 小时前
模块一 入门微服务
微服务
AAA修煤气灶刘哥9 小时前
别懵!从单机锁到 Redisson,分布式锁的坑我全帮你填了
java·redis·spring cloud