SpringCloud 整合 Ribbon 实现服务负载均衡请求,实战讲解!
一、背景介绍
在上一篇文章中,我们介绍了 Spring Cloud 技术体系中最核心的组件之一 Eureka,它主要用于服务的注册和发现管理。
今天通过这篇文章,结合之前的知识,我们一起来了解一下 Spring Cloud 技术体系中另一个最核心的组件之一 Ribbon。
二、Ribbon 简介
Spring Cloud Ribbon 是一个基于 Netflix Ribbon 实现的客户端负载均衡工具,主要作用就是提供客户端的负载均衡算法,帮助服务消费方以某种规则(如简单轮询、随机连接等)从多个服务提供方中选择一个进行通信。
我们知道在生产环境,一个服务通常不是单独部署,而是以集群的方式进行部署,比如扣减产品库存服务,通常会在至少两台服务器上部署相同的服务,以防止某个服务突然宕机了,另一台服务器依然能正常提供访问。
在传统的集群架构中,客户端向服务端发起调用,通常会先请求服务端的负载均衡服务(例如 nginx),然后由负载均衡服务负责将请求转发到具体的服务提供者,已完成整个服务的请求。大致流程,可以用如下图来简易描述。

与服务端的负载均衡不同,Ribbon 的负载均衡主要作用在客户端。
在微服务架构中,Ribbon 通常它会每隔一段时间主动从服务注册中心 Eureka 上拉取相关的服务实例列表,然后缓存到本地客户端。当客户端向服务端发起远程调用的时候,会从服务实例列表中选择一个有效的服务提供者地址,最后发起远程调用。当有多个地址时,默认以轮流选择服务器方式以达到均衡负载的效果。大致流程,可以用如下图来简易描述。

这样做的好处就是,通过客户端可以直接调用具体的服务提供者,近一步降低了服务的请求耗时。
下面我们通过具体实例,看看如何使用 Ribbon 来调用服务,并实现客户端的均衡负载效果。
三、方案实践
3.1、创建多个服务提供方
与之前介绍的服务提供方案例类似,首先创建一个 Spring Boot 工程,命名为eureka-provider-1
,并在pom.xml
中引入相关的依赖内容,示例如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Edgware.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
接着,创建一个服务启动类并添加@EnableDiscoveryClient
注解,表示当前是一个 Eureka 客户端服务。
@EnableEurekaServer
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
然后,创建一个 web 接口,以便等会发起 RPC 调用测试。
@RestController
public class HelloController {
@GetMapping("/hello")
public String index() {
System.out.println("收到客户端发起的rpc请求!");
return "hello,我是服务提供方 provider 1";
}
}
最后,在application.properties
配置文件中添加服务注册中心地址,示例如下:
spring.application.name=eureka-provider
server.port=9011
# 设置与Eureka Server交互的地址,多个地址可使用【,】分隔
eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/
同样的操作,创建一个eureka-provider-2
工程,将接口返回结果修改成hello,我是服务提供方 provider 2
,以便等会测试客户端的负载均衡效果。
3.2、创建服务消费方并集成 Ribbon
与服务提供方类似,创建一个 Spring Boot 工程,命名为eureka-consumer-ribbon
,并在pom.xml
中引入 Ribbon 依赖内容,示例如下:
<dependencies>
...
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
</dependencies>
然后,创建应用主类并注入RestTemplate
网络请求工具类,同时增加@LoadBalanced
注解以开启客户端均衡负载的能力。
@EnableDiscoveryClient
@SpringBootApplication
public class Application {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
接着,创建一个发起远程调用的controller
服务,通过RestTemplate
实现网络请求,此处的url
中使用的是服务名称,而不是服务所在的具体 IP 地址和端口。
@RestController
public class HelloController {
@Autowired
private RestTemplate restTemplate;
/**
* 发起远程调用测试
* @return
*/
@GetMapping("/rpc")
public String rpc() {
// 当请求真正发起的时候,url 中的服务名会根据负载均衡策略从服务清单中挑选出一个实例来进行替换,最后发起请求
String url = "http://eureka-provider/hello";
String result = restTemplate.getForObject(url, String.class);
return "发起远程调用,收到返回的信息:" + result;
}
}
最后,在application.properties
配置文件中添加相关的配置信息。
spring.application.name=eureka-consumer
server.port=9002
eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/
完成以上工程之后,依次将eureka-server
、eureka-provider-1
、eureka-provider-2
、eureka-consumer-ribbon
服务启动起来。
然后在浏览器上多次访问http://localhost:9002/rpc
,可以得到类似于如下内容。

可以清晰的看到,客户端以轮训的方式调用目标接口,已实现服务均衡负载的效果。
四、Ribbon 高级特性
多数情况下,Ribbon 的默认配置足够使用,如果想要对其进行
4.1、配置负载均衡算法
Ribbon 支持多种负载均衡算法,默认采用轮询算法,也就是上文介绍的轮流选择服务器。
具体可支持的其它参数有以下几个:
- RoundRobinRule:轮流选择服务器(默认算法)
- RandomRule:随机选择一个服务器
- BestAvailableRule:选择一个最小的并发请求的服务器
- WeightedResponseTimeRule:根据响应时间分配权重,响应时间短的服务器分配权重大,被选择的概率高
- AvailabilityFilteringRule:过滤掉故障服务器后,然后再以线性轮询的方式从过滤后的实例清单中选择一个服务器
- RetryRule:在指定时间内若请求失败,则一直尝试该服务器,超过指定时间才尝试其他服务器
- ZoneAvoidanceRule:从最佳区域实例集合中选择一个最优性能的服务实例
开发者如果想要更换负载均衡算法,可以在application.properties
文件中进行配置。
以eureka-consumer-ribbon
服务为例,配置ribbon
客户端的负载均衡采用随机算法,示例如下。
# 设置ribbon客户端的负载均衡采用随机算法
eureka-consumer-ribbon.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
如果以上的负载均衡算法不满足实际业务需求,开发者也可以自定义的负载均衡算法,通过实现IRule
接口自定义负载均衡规则,具体实现可以参考官网文档。
4.2、配置请求重试机制
当请求某个接口因为服务故障失败了,Ribbon 支持自动发起重试请求。
以eureka-consumer-ribbon
服务的请求调用为例,可以在配置文件中增加如下内容。
# 开启失败重试
spring.cloud.loadbalancer.retry.enabled=true
# 设置请求连接的超时时间(ms)
eureka-consumer-ribbon.ribbon.ConnectTimeout=250
# 设置请求读取的超时时间(ms)
eureka-consumer-ribbon.ribbon.ReadTimeout=1000
# 设置最大自动重试次数
eureka-consumer-ribbon.ribbon.MaxAutoRetries=1
# 设置切换服务器最大重试次数
eureka-consumer-ribbon.ribbon.MaxAutoRetriesNextServer=2
# 设置是否所有操作都重试
eureka-consumer-ribbon.ribbon.OkToRetryOnAllOperations=true
当请求失败时,Ribbon 可以自动重试。
重试次数由MaxAutoRetries
和MaxAutoRetriesNextServer
控制,这两个属性默认都是 1 次;当MaxAutoRetries
重试次数用完,Ribbon 会切换到另一个服务实例发起MaxAutoRetriesNextServer
重试次数的请求;如果都失败,返回失败信息。
五、小结
最后总结一下,Ribbon 是 Spring Cloud 体系中最重要的组件之一,主要用于客户端的负载均衡管理。
尽管 Netflix 也对其停止维护了,但是作为快速掌握 Spring Cloud 技术体系,依然是一个很好的学习案例。
六、参考
1.https://blog.didispace.com/springcloud2/
2.https://cloud.tencent.com/developer/article/2344762
作者:潘志的技术笔记
出处:https://pzblog.cn/
版权归作者所有,转载请注明出处
