3Ribbon客户端 · SpringCloud微服务实战 · 看云
导航
本节代码地址
下面我们开始创建Ribbon客户端的项目,本节我们会讲到Ribbon调用的原理和自定义规则。
1.新建客户端
新建模块fw-cloud-ribbon,注意是New Module ,我们创建的是一个聚合工程
1.1 maven 配置
这里我们使用Spring Cloud 官方提供的spring-cloud-starter-netflix-ribbon
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
</dependencies>
1.2 新建启动类
@EnableDiscoveryClient
@SpringBootApplication
public class FwRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(FwRibbonApplication.class, args);
}
}
1.3 项目配置
server:
port: 8772
spring:
application:
name: fw-feign
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
因为服务端是接口返回的User 类,所以接收端也需要同样的User 类
1.4 新建User 类
注意
@NoArgsConstructor如果不添加反序列化的时候回报错
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private long id;
private String username;
private String realname;
private String email;
private String remark;
}
1.5 添加 Ribbon 的配置
@Configuration
public class EurekaRibbonConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
1.5.1 @LoadBalanced 原理
在 RestTemplate 上加了一个 @LoadBalanced 注解就可以负载均衡。这是因为 Spring Cloud 做了大量的底层封装,做了很多简化。
内部的主要逻辑就是给 RestTemplate 增加拦截器,在请求之前对请求的地址进行了替换,或者根据具体的负载策略选择服务地址,然后去调用,这就是 @LoadBalanced 的原理。
Spring Web 为 HttpClient 提供了 Request 拦载器 ClientHttpRequestInterceptor,位于 spring-web jar 包下。
在 spring-cloud-commons 包中提供了负载均衡自动配置类 LoadBalancerAutoConfiguration ,里面维护了一个 @LoadBalanced 注解的 RestTemplate 列表,里面的静态类 LoadBalancerInterceptorConfig 注册了 负载均衡拦截器 LoadBalancerInterceptor,RestTemplateCustomizer 来添加拦截器列表。
负载均衡拦截器 LoadBalancerInterceptor 实现了 ClientHttpRequestInterceptor,主要逻辑在 intercept() 方法中,执行交给了 LoadBalancerClient,通过 LoadBalancerRequestFactory 来构建一个 LoadBalancerRequest 对象,createRequest 方法中通过 ServiceRequestWrapper 来执行替换 URI 的逻辑,核心是通过 reconstructURI() 方法实现,该方法的业务实现是在 RibbonLoadBalancerClient 类中 。
1.6 创建Ribbon Service
@Service
@Slf4j
public class EurekaRibbonService {
@Autowired
RestTemplate restTemplate;
public User findUserById(Long id) {
return restTemplate.getForObject("http://fw-cloud-ribbon-server/user/" + id, User.class);
}
}
restTemplate.getForObject("http://fw-cloud-feign-server/user/" + id, User.class)这里需要添加正确的服务名称,RestTemplate 这样请求的好处就是不需要关心应用的IP,通过Eureka 注册中心发现是此服务名的服务提供者就会去请求。非常方便应用的水平拓展。
1.7 Ribbon RESTFUL 请求层
@RestController
public class EurekaRibbonController {
@Resource
private EurekaRibbonService eurekaRibbonService;
@GetMapping("/user/{id:\\d+}")
public User findUserById(@PathVariable long id){
return eurekaRibbonService.findUserById(id);
}
}
\\d+是一个正则表达式,这个正则表达式的含义就是请求的id只能是正整数
1.8 启动应用
通过postman 验证发现,分别输入localhost:8771/user/1
结果如下
通过返回结果可以看到8773和8774一直在变化,轮询着变化,原因是什么呢?下面我们说一下负载均衡的策略。
1.9 负载均衡策略
Ribbon 默认的负载策略是轮询,同时也提供了很多其他的策略能够让用户根据业务需求来选择。负载均衡策略的根接口是 com.netflix.loadbalancer.IRule
- BestAvailableRule
选择最小并发请求的服务器,每个客户端都会获得一个随机的服务器列表,如果服务器被标记为错误,则跳过。 - AvailabilityFilteringRule
用于过滤连接一直失败或读取失败而被标记为 circuit breaker tripped 状态的服务;或持有超过可配置限制的活动连接(默认值为 Integer.MAX_VALUE),即过滤掉高并发的后端服务。实际就是检查获取到的服务列表里,各个 Server 的 Status 。 - ZoneAvoidanceRule
根据区域和可用性来过滤服务器。使用 ZoneAvoidancePredicate 来判断 Zone 的使用是否达到阀值,过滤出最差 Zone 中的所有服务器; AvailabilityPredicate 用于过滤出并发连接过多的服务。 - RandomRule
随机分配流量,即随机选择一个 Server。 - RetryRule
向现有负载均衡策略添加重试机制。 - ResponseTimeWeightedRule
该策略已过期,同见 WeightedResponseTimeRule。 - WeightedResponseTimeRule
根据响应时间为每个服务器动态分配权重(Weight)分,然后台加权循环的方式使用该策略。响应时间越长,权重越低,被选中可能性越低。
以上是Ribbon 自带的负载策略,如果我们想改变策略怎么改?我们可以自定义策略吗? 请见下一节 Ribbon 自定义负载规则
2. 总结
本节主要讲解了Ribbon 如何负载的请求服务端的接口,并且讲解了LoadBalanced 原理和负载均衡策略,学习完本节,相信对Ribbon的操作已经了然于心了。



