SpringCloud极简入门-客户端负载均衡Ribbon

本文涉及的产品
应用型负载均衡 ALB,每月750个小时 15LCU
传统型负载均衡 CLB,每月750个小时 15LCU
网络型负载均衡 NLB,每月750个小时 15LCU
简介: 我们知道,为了防止应用出现单节点故障问题,同时为了提高应用的作业能力,我们需要对应用做集群 ,如果我们对user-server(用户服务)做了集群 ,那么这个时候回衍生出一些问题:现在有两个user-server(用户服务)就意味着有两个user-server(用户服务)的通信地址,我的order-server(订单服务)在向user-server(用户服务)发起调用的时候该访问哪个?如何访问?这个时候就需要有一个组件帮我们做请求的分发,即:负载均衡器,而Ribbon就是一个客户端负载均衡器。

六.客户端负载均衡Ribbon+RestTemplate

1.基本概念

1.1.为什么要Ribbon

我们知道,为了防止应用出现单节点故障问题,同时为了提高应用的作业能力,我们需要对应用做集群 ,如果我们对user-server(用户服务)做了集群 ,那么这个时候回衍生出一些问题:现在有两个user-server(用户服务)就意味着有两个user-server(用户服务)的通信地址,我的order-server(订单服务)在向user-server(用户服务)发起调用的时候该访问哪个?如何访问?这个时候就需要有一个组件帮我们做请求的分发,即:负载均衡器,而Ribbon就是一个客户端负载均衡器。

1.2.什么是Ribbon

Ribbon是Netflix发布的云中间层服务开源项目,主要功能是提供客户端负载均衡算法。Ribbon客户端组件提供一系列完善的配置项,如,连接超时,重试等。简单的说,Ribbon是一个客户端负载均衡器,Ribbon可以按照负载均衡算法(如简单轮询,随机连接等)向多个服务发起调用(正好可以解决上面的问题),我们也很容易使用Ribbon实现自定义的负载均衡算法。

1.3.Ribbon的工作机制

如下图,我们将user-server(用户服务)做集群处理,增加到2个节点(注意:两个user-server(用户服务)的服务名要一样,ip和端口不一样),在注册中心的服务通信地址清单中user-server(用户服务)这个服务下面会挂载两个通信地址 。 order-server(订单服务)会定时把服务通信地址清单拉取到本地进行缓存, 那么当order-server(订单服务)在向user-server(用户服务)发起调用时,需要指定服务名为 user-server(用户服务);那么这个时候,ribbon会根据user-server(用户服务)这个服务名找到两个order-server的通信地址 , 然后ribbon会按照负载均衡算法(默认轮询)选择其中的某一个通信地址,发起http请求实现服务的调用,如下图:

在理解了Ribbon工作机制之后,我们就来编码实战上图描述的场景。

2.提供者user-server(用户服务)集群

2.1.服务集群方案

使用SpringBoot多环境配置方式集群,一个配置文件配置多个order-server环境 ,需要注意的是集群中的多个服务名(spring.application.name)应该一样,我们把相同的东西提取到最上面,不同的东西配置在各自的环境中

2.2.用户服务集群配置

修改 application.yml 如下:

#注册到EurekaServereureka:  client:    serviceUrl:      defaultZone: http://peer1:1010/eureka/,http://peer2:1011/eureka/,http://peer3:1012/eureka/
#使用ip地址进行注册  instance:    prefer-ip-address: truespring:  application:    name: user-server  #服务名都叫user-server  profiles:    active: user-server1
---server:  port: 1020eureka:  instance:    instance-id: user-server:1020spring:  profiles: user-server1
---server:  port: 1021eureka:  instance:    instance-id: user-server:1021spring:  profiles: user-server2

用户服务集群配置成功,启动方式同注册中心集群一样。需要配置服务运行多实例启动,启动时需要注意修改spring.profiles.active的值来切换不同的实例。

2.3.修改Controller

为了后续测试的时候方便区分不同的用户服务实例,这里我们在Controller中读取应用的端口随User返回,在启动不同的用户服务实例的时候端口是不同的,修改后的代码如下:

//用户服务:暴露接口给订单访问@RestControllerpublicclassUserController {
//加载端口@Value("${server.port}")
privateintport;
//订单服务来调用这个方法      http://localhost:1020/user/10// @GetMapping(value = "/user/{id}" )@RequestMapping(value="/user/{id}",method=RequestMethod.GET)
publicUsergetById(@PathVariable("id")Longid){
//根据id去数据库查询UserSystem.out.println(port);
returnnewUser(id,"zs:"+id,"我是zs,port:"+port);    //端口随User返回    }
}

3.消费者Order-server集成Ribbon

Ribbon集成官方文档:https://cloud.spring.io/spring-cloud-static/Greenwich.SR5/multi/multi_spring-cloud-ribbon.html#netflix-ribbon-starter

修改springcloud-order-server-1030工程,集成Ribbon

3.1.导入依赖

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-ribbon</artifactId></dependency>

3.2.开启负载均衡

修改RestTemplate的Bean的定义方法,加上Ribbon的负载均衡注解@LoadBalanced赋予RestTemplate有负债均衡的能力。

/*** 订单的启动类*/@SpringBootApplication@EnableEurekaClientpublicclassOrderServerApplication1030{
//配置一个RestTemplate ,Spring封装的一个机遇Restful风格的http客户端 工具//@LoadBalanced :让RestTemplate有负载均衡的功能@Bean@LoadBalancedpublicRestTemplaterestTemplate(){
returnnewRestTemplate();
    }
//省略...

3.3.修改Controller调用方式

在之前的案例中,我们调用用户服务是通过用户服务的主机加上端口“localhost:1020”的调用方式,现在我们把 “localhost:1020” 修改为 用户服务的服务名 。底层会通过服务发现的方式使用Ribbin进行负载均衡调用。

@RestControllerpublicclassOrderController {
//需要配置成Bean@AutowiredprivateRestTemplaterestTemplate ;
//浏览器调用该方法@RequestMapping(value="/order/{id}",method=RequestMethod.GET)
publicUsergetById(@PathVariable("id")Longid){
//发送http请求调用 user的服务,获取user对象 : RestTemplate//user的ip,user的端口,user的Controller路径//String url = "http://localhost:1020/user/"+id;Stringurl="http://user-server/user/"+id;
//发送http请求returnrestTemplate.getForObject(url, User.class);
    }
}

3.4.测试Ribbon

分别启动EurekaServer注册中心 ,启动两个UserServer用户服务,启动OrderServer订单消费者服务,浏览器访问订单服务:http://localhost:1030/order/1 ,发送多次请求。

观察响应的结果中的端口变化 - 端口会交替出现1020,,1021我们可以推断出Ribbon默认使用的是轮询策略。

4.负载均衡算法

4.1.Ribbon内置算法

Ribbon内置7种负载均衡算法,每种算法对应了一个算法类如下:

内置负载均衡规则类 规则描述
RoundRobinRule(默认) 简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。
AvailabilityFilteringRule 对以下两种服务器进行忽略:(1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。可以通过修改配置loadbalancer..connectionFailureCountThreshold来修改连接失败多少次之后被设置为短路状态。默认是3次。(2)并发数过高的服务器。并发连接数的上线,可以由客户端的..ActiveConnectionsLimit属性进行配置。
WeightedResponseTimeRule 为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。
ZoneAvoidanceRule 以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。
BestAvailableRule 忽略哪些短路的服务器,并选择并发数较低的服务器。
RandomRule 随机选择一个可用的服务器。
Retry 重试机制的选择逻辑

4.2.配置负载均衡算法

Ribbon可以进行全局负载均衡算法配置,也可以针对于具体的服务做不同的算法配置。同时可以使用注解方式和yml配置方式来实现上面两种情况。

1.注解全局配置

随机算法的效果最好演示,我们把负载均衡算法修改成随机算法,只需要RandomRule配置成Bean即可,修改主配置类如下:

/*** 订单的启动类*/@SpringBootApplication@EnableEurekaClientpublicclassOrderServerApplication1030{
//配置一个RestTemplate ,Spring封装的一个机遇Restful风格的http客户端 工具//@LoadBalanced :让RestTemplate有负载均衡的功能@Bean@LoadBalancedpublicRestTemplaterestTemplate(){
returnnewRestTemplate();
    }
//负载均衡算法@BeanpublicRandomRulerandomRule(){
returnnewRandomRule();
    }
//省略...

测试

重启订单服务,访问http://localhost:1030/order/1 ,发送多次请求应该可以看到结果中的端口随机变动。

2.配置具体服务的负载均衡

参照官方文档:https://cloud.spring.io/spring-cloud-static/Greenwich.SR5/multi/multi_spring-cloud-ribbon.html#_customizing_the_ribbon_client

如果要针对某一服务配置负载均衡算法可以通过@RibbonClient注解来实现。

先来定义一个注解,用来排除配置类不被扫描到(后面有解释):

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public@interfaceNoScan {
}

然后定义一个配置类,在配置类中定义随机算法策略:

@Configuration@NoScan//这是一个空标签,是用来防止@SpringBootApplication 扫描到该类publicclassRibbonConfig {
@BeanpublicIRulerandomRule(){
returnnewRandomRule();
    }
}

提示:需要注意的是这个类我们是要交给RibbonClient作为配置,而不应该被主配置类上的@SpringBootApplication(这个标签里面有个@ComponentScan)所扫描到,不然会不起作用(官方文档上有明确的解释),这里又两种方法可以不让@SpringBootApplication扫描到,1是调整 RibbonConfig 所在包的位置 (@MapperScan扫描当前包及其子包), 2是通过@ComponentScan排除注解的方式,所以我们在配置类上贴了一个注解@NoScan ,后面我们需要根据这个注解排除配置不被扫描。

主配置类通过@RibbonClient指定服务的负载均衡配置,同时排除@NoScan 注解不被扫描

/*** 订单的启动类*/@SpringBootApplication//排除 NoScan标签所在的类@ComponentScan(excludeFilters=@ComponentScan.Filter(type=FilterType.ANNOTATION,value=NoScan.class))
@EnableEurekaClient@RibbonClient(value="user-server",configuration=RibbonConfig.class)
publicclassOrderServerApplication1030{
//配置一个RestTemplate ,Spring封装的一个机遇Restful风格的http客户端 工具//@LoadBalanced :让RestTemplate有负载均衡的功能@Bean@LoadBalancedpublicRestTemplaterestTemplate(){
returnnewRestTemplate();
    }
//负载均衡算法//    @Bean//    public RandomRule randomRule(){//        return new RandomRule();//    }publicstaticvoidmain( String[] args )
    {
SpringApplication.run(OrderServerApplication1030.class);
    }
}

除了 @RibbonClient 注解以外还可以通过@RibbonClients来对多个服务进行策略配置

@RibbonClients({
@RibbonClient(value="服务名",configuration=RibbonConfig.class),
@RibbonClient(value="服务名",configuration=RibbonConfig.class)
})
3.yml方式配置负载均衡算法

配置全局Ribbon算法

ribbon:
   NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

配置某个服务的Ribbon算法

user-server:  ribbon:    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
4.做个总结

上面我们介绍了通过注解方式进行负载均衡策略全局配置和针对某个服务的负载均衡配置,也介绍了通过yml方式配置,我们可以根据项目情况选择其中一种配置方式即可。

5.Ribbon调优配置

5.1.超时配置

使用Ribbon进行服务通信时为了防止网络波动造成服务调用超时,我们可以针对Ribbon配置超时时间以及重试机制

ribbon:  ReadTimeout: 3000         #读取超时时间  ConnectTimeout: 3000        #链接超时时间  MaxAutoRetries: 1         #重试机制:同一台实例最大重试次数  MaxAutoRetriesNextServer: 1     #重试负载均衡其他的实例最大重试次数  OkToRetryOnAllOperations: false   #是否所有操作都重试,因为针对post请求如果没做幂等处理可能会造成数据多次添加/修改

当然也可以针对具体的服务进行超时配置:如"<服务名>.ribbon…"

5.2.饥饿加载

我们在启动服务使用Ribbon发起服务调用的时候往往会出现找不到目标服务的情况,这是因为Ribbon在进行客户端负载均衡的时候并不是启动时就创建好的,而是在实际请求的时候才会去创建,所以往往我们在发起第一次调用的时候会出现超时导致服务调用失败,我们可以通过设置Ribbon的饥饿加载来改善此情况,即在服务启动时就把Ribbon相关内容创建好。

ribbon:  eager-load:    enabled: true #开启饥饿加载    clients: user-server #针对于哪些服务需要饥饿加载

6.做个小结

Ribbon的使用相对比较简单,配合RestTemplate使用注解@LoadBalanced即可完成负载均衡配置,但是再我们的订单服务Controller中向用户服务发起请求的代码就显得不简单了。我们需要手动去拼接目标服务的URL,以及参数,可能参数比较简单的时候你没什么感觉,当地址比较复杂,参数比较多的时候,拼接URL就会得特别麻烦,而且显得好傻,在下一章节我们会学习另外一个客户端负载均衡Feign,它在Ribbon的基础上进行了封装,让服务的调用方式显得更简答和高级。

相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
目录
相关文章
|
3月前
|
负载均衡 算法 Java
Spring Cloud全解析:负载均衡算法
本文介绍了负载均衡的两种方式:集中式负载均衡和进程内负载均衡,以及常见的负载均衡算法,包括轮询、随机、源地址哈希、加权轮询、加权随机和最小连接数等方法,帮助读者更好地理解和应用负载均衡技术。
102 2
|
1月前
|
负载均衡 Java Nacos
Ribbon负载均衡
Ribbon负载均衡
33 1
Ribbon负载均衡
|
2天前
|
SpringCloudAlibaba Dubbo Java
【SpringCloud Alibaba系列】Dubbo基础入门篇
Dubbo是一款高性能、轻量级的开源Java RPC框架,提供面向接口代理的高性能RPC调用、智能负载均衡、服务自动注册和发现、运行期流量调度、可视化服务治理和运维等功能。
【SpringCloud Alibaba系列】Dubbo基础入门篇
|
4月前
|
负载均衡 算法 架构师
Ribbon负载均衡
上一节就已经实现的负载均衡笔者并未深入探讨,本节通过分析负载均衡算法、Ribbon实现负载均衡的底层原理和实现过程,让大家对负载均衡有了一个大体认识,同时针对Ribbon自定义负载均衡策略,饥饿加载让大家对于Ribbon的了解又多一些。Ribbon实现的负载均衡只是方案之一,我们可以尽量多了解但不要局限于此。
|
1月前
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
90 5
|
22天前
|
负载均衡 Java Nacos
常见的Ribbon/Spring LoadBalancer的负载均衡策略
自SpringCloud 2020版起,Ribbon被弃用,转而使用Spring Cloud LoadBalancer。Ribbon支持轮询、随机、加权响应时间和重试等负载均衡策略;而Spring Cloud LoadBalancer则提供轮询、随机及Nacos负载均衡策略,基于Reactor实现,更高效灵活。
54 0
|
2月前
|
Dubbo Java 应用服务中间件
Dubbo学习圣经:从入门到精通 Dubbo3.0 + SpringCloud Alibaba 微服务基础框架
尼恩团队的15大技术圣经,旨在帮助开发者系统化、体系化地掌握核心技术,提升技术实力,从而在面试和工作中脱颖而出。本文介绍了如何使用Dubbo3.0与Spring Cloud Gateway进行整合,解决传统Dubbo架构缺乏HTTP入口的问题,实现高性能的微服务网关。
|
3月前
|
负载均衡 Java Nacos
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
微服务介绍、SpringCloud、服务拆分和远程调用、Eureka注册中心、Ribbon负载均衡、Nacos注册中心
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
|
4月前
|
存储 设计模式 缓存
OpenFeign集成Ribbon负载均衡-过滤和选择服务核心实现
该文章主要介绍了如何在OpenFeign中集成Ribbon以实现负载均衡,并详细分析了Ribbon中服务选择和服务过滤的核心实现过程。文章还涉及了Ribbon中负载均衡器(ILoadBalancer)和负载均衡策略(IRule)的初始化方式。
OpenFeign集成Ribbon负载均衡-过滤和选择服务核心实现
|
4月前
|
缓存 负载均衡 Java
OpenFeign最核心组件LoadBalancerFeignClient详解(集成Ribbon负载均衡能力)
文章标题为“OpenFeign的Ribbon负载均衡详解”,是继OpenFeign十大可扩展组件讨论之后,深入探讨了Ribbon如何为OpenFeign提供负载均衡能力的详解。
OpenFeign最核心组件LoadBalancerFeignClient详解(集成Ribbon负载均衡能力)