SpringCloud Netflix复习之Ribbon

写作背景

本文是接上一篇《SpringCloud Netflix复习之Eureka》来写的,有了Eureka之后,微服务之间调用可以通过Eureka Server拉取到服务注册表,就知道了要调用的下游服务的访问IP加端口等信息。但是呢,现在一般微服务都是多实例部署,一来防止单点问题,二来可以水平扩展提高并发能力。那么问题来了,服务A调用服务B,服务B是多实例部署的,我服务A怎么知道要调用服务B哪个实例呢?是随机还是轮询,还是有更智能一些的根据负载和机器配置来选择,Ribbon就是来干这件事的。
本文来复习SpringCloud Ribbon的相关知识,书写思路是以下几个方面

  1. SpringCloud Ribbon是什么,干了什么事情
  2. Ribbon组件的核心功能
  3. 上手实战
  4. 从源码角度来看下Ribbon的实现原理

SpringCloud Ribbon是什么,干了什么事情

Ribbon本身是Netflix公司(类似国内爱奇艺)研发的一个用于客户端负载均衡的组件,SpringCloud官方拿来封装了一下,成为SpringCloud Netflix生态的一员。刚刚说到了客户端的负载均衡,对应的还有个服务端负载均衡,常见的比如Nginx就是服务端负载均衡,相信你已经懂了一个是从客户端自己发起并执行的,一个是请求到达服务器之后再根据负载算法选择目标服务器。

Ribbon组件的核心功能

Ribbon提供了一系列完善的配置,比如超时配置,重试配置。通过ILoadBalancer获取所有服务实例列表ServerList,然后基于IRule实现的某种负载均衡算法,比如随机、轮询等选出一个服务实例,然后通过RestTemplate发起一个Rest请求。
可以说Ribbon这个中间件最核心的组件就是ILoadBalancer,然后服务实例列表的ServerList,以及用于负载算法IRule从ServerList中选出一个服务实例,还有一个用于ping每个服务实例判断其是否存活的IPing组件。

Ribbon内置了哪些负载均衡算法

Ribbon内置了许多负载均衡算法规则,这些规则的顶级接口是com.netflix.loadbalancer.IRule,可以通过实现IRule接口自定义负载均衡算法,但是一般用内置的负载均衡算法就够了。
在这里插入图片描述

RandomRule:随机找一个服务实例,这种基本不会用。

RoundRobinRule:轮询,从一堆server list中轮询选择出来一个server,每个server平摊到的这个请求,基本上是平均的,比如你100个请求,然后5个实例,基本每个实例会打到20个请求。有个限制默认超过10次获取的server都不可用,会返回空

AvailabilityFilteringRule:顾名思义,这个规则会考察服务器的可用性。如果3次连接失败,就会等待30秒后再次访问;如果某个服务器的连接数超限也就是并发请求太高了,那么会绕过去,不再访问

WeightedResponseTimeRule:带着权重的,每个服务器可以有权重,权重越高优先访问,如果某个服务器响应时间比较长,那么权重就会降低,减少访问

ZoneAvoidanceRule:根据区域来进行负载均衡,说白了就是优先在同一个机房内的节点轮询选取

BestAvailableRule:最小链接数策略,遍历ServerList从中选出一个可用且连接数最小的Server。

RetryRule:重试,默认继承RoundRobinRule就是通过轮询找到的服务器不可用或者请求失败,可以重新找一个服务器,而且没有RoundRoinRule超过10的限制,只要serverList不挂会不停选取判断。

其中ZoneAvoiddanceRule是默认策略,这个在后面源码中也有体现

上手实战

在SpringCloud里Ribbon实战

Springcloud项目中使用Ribbon只需要注入RestTemplate,然后加一个@LoadBalanced注解就可以了

/**
     * Ribbon负载均衡
     *
     * @return RestTemplate
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
   
        RestTemplate restTemplate = new RestTemplate();
        return restTemplate;
    }

连依赖都不用加,因为Eureka客户端里已经有Ribbon的依赖,所以只要你项目里已经有了eureka客户端的依赖
在这里插入图片描述
RestTemplate本身只是一个Http组件,指定一个url发起一个Http请求,它是不具备负载均衡的功能的,但是这里加了@LoadBalanced注解之后,底层就会用Ribbon实现负载均衡。

我这边演示fc-service-portal(端口是8002)调用fc-service-screen服务,其中fc-service-screen启动两个实例,一个端口是8003,一个端口是8004。
下面是fc-service-portal服务里的Controller代码,通过RestTemplate调用fc-service-screen的/getPort接口,主要是查端口,根据端口号来区分调用的是哪个实例

@RestController
public class HelloWorldController {
   

    @Resource
    RestTemplate restTemplate;

    @GetMapping("/getPort")
    public int getPort() {
   
        return restTemplate.getForObject("http://fc-service-screen/getPort", Integer.class);
    }
}

fc-service-sceen8003和8004里Controller里的代码都是下面这样的

@RestController
public class HelloWordController {
   

    @Value("${server.port}")
    int port;

    @GetMapping("/getPort")
    public int getPort() {
   
        return port;
    }

}

启动所有服务后,看下Eureka的注册情况
在这里插入图片描述
可以看到fc-service-screen已经有两个实例了
我们请求http://localhost:8002/getPort 看返回结果情况
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看的出来是轮询的访问方式

从源码角度看下Ribbon实现原理

SpringCloud与Ribbon整合的原理

从@LoadBalanced注解入手


/**
 * Annotation to mark a RestTemplate bean to be configured to use a LoadBalancerClient.
 * @author Spencer Gibb
 */
@Target({
    ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
   

}

看注释的意思是@LoadBalanced注解的意思是将一个RestTemplate标记为底层采用LoadBalancerClient来执行实际的Http的请求,支持负载均衡。还是老套路找下XXAutoConfiguration类,找到了LoadBalancerAutoConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
   
@LoadBalanced
	@Autowired(required = false)
	private List<RestTemplate> restTemplates = Collections.emptyList();

	@Autowired(required = false)
	private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();

	@Bean
	public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
			final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
   
		return () -> restTemplateCustomizers.ifAvailable(customizers -> {
   
			for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
   
			//定制restTemplate
				for (RestTemplateCustomizer customizer : customizers) {
   
					customizer.customize(restTemplate);
				}
			}
		});
	}

可以看到有个restTemplate的列表然后每个restTemplate都被定制了,我们找下RestTemplateCustomizer

@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
		final LoadBalancerInterceptor loadBalancerInterceptor) {
   
		return restTemplate -> {
   
				List<ClientHttpRequestInterceptor> list = new ArrayList<>(
						restTemplate.getInterceptors());
				list.add(loadBalancerInterceptor);
				//往restTemplate里设置了拦截器LoadBalancerInterceptor
				restTemplate.setInterceptors(list);
		};
}
@Bean
public LoadBalancerInterceptor ribbonInterceptor(
      LoadBalancerClient loadBalancerClient,
      LoadBalancerRequestFactory requestFactory) {
   
   return new 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值