springcloud — 微服务负载均衡组件之Ribbon解析(一)

Ribbon 负载均衡

Ribbon是一个内置软件负载平衡器的进程间通信(远程过程调用)库。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,Ribbon是一个客户端负载均衡器,我们可以在配置文件中Load Balancer后面的所有机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器,我们也很容易使用Ribbon实现自定义的负载均衡算法。

Ribbon是一个经过云测试的客户端库。它提供了以下特性

  • Load balancing 负载均衡
  • Fault tolerance 故障容错
  • 异步和响应模型中支持多个协议(HTTP、TCP、UDP)
  • 缓存和批处理

Ribbon 核心组件

在这里插入图片描述
ServerList:可以响应客户端的特定服务的服务器列表
ServerListFilter:可以动态获得的具有所需特征的候选服务器列表的过滤器
ServerListUpdater:用于执行动态服务器列表更新
IRule:负载均衡策略,用于确定从服务器列表返回哪个服务器
IPing:客户端用于快速检查服务器当时是否处于活动状态(心跳检测)
ILoadBalancer:负载均衡器,负责负载均衡调度的管理
IClientConfig:定义 Ribbon 中管理配置的接口

Ribbon 核心解析

引用依赖:

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

注解LoadBalancerClient使用:

@Service
public class SpringDemoRibbonService {

    @Autowired
    RestTemplate restTemplate;

    @Autowired
    LoadBalancerClient loadBalancerClient;

    @HystrixCommand(fallbackMethod = "portFallback")
    public String port() {
        this.loadBalancerClient.choose("spring-demo-service");  //随机访问策略
        return restTemplate.getForObject("http://SPRING-DEMO-SERVICE/port", String.class);
    }

    public String portFallback() {
        return "sorry ribbon, it's error!";
    }
}
1、源码解析:

ServiceInstanceChooser 为指定服务选择一个ServiceInstance

public interface ServiceInstanceChooser {
    /**从LoadBalancer中为指定服务选择一个ServiceInstance
     * Choose a ServiceInstance from the LoadBalancer for the specified service
     */
    ServiceInstance choose(String serviceId);
}

LoadBalancerClient通过继承 ServiceInstanceChooser 实现负载请求

public interface LoadBalancerClient extends ServiceInstanceChooser {
	// 使用来自LoadBalancer的ServiceInstance对指定对象执行请求
    <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;
    <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException;
	// 使用真实的主机和端口创建适当的URI
    URI reconstructURI(ServiceInstance instance, URI original);
}

LoadBalancerAutoConfiguration-负载均衡配置的自动装配

@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
    /***
    * 从类的注解就可以看出,它配置加载的时机
    * 一是当前工程环境必须有 RestTemplate 的实 例,
    * 二是在工程环境中必须初始化了 LoadBalancerClient 的实现类
    **/
	@LoadBalanced
	@Autowired(required = false)
	private List<RestTemplate> restTemplates = Collections.emptyList();

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

	@Autowired(required = false)
	private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
	/**
	* LoadBalancerRequestFactory 用于创建 LoadBalancerRequest和LoadBalancerlnterceptor 使用,它在低版本中是没有的.LoadBalancerInterceptorConfig 中 则 维 护 了 Load- Balancerinterceptor 与RestTemplateCustomizer 的实例 , 它们的作用如下:
	  LoadBalancerlnterceptor : 拦截每一次 HTTP 请求,将请求绑定进 Ribbon 负载均衡的 生命周期。
	  RestTemplateCustomizer: 为每个 RestTemplate 绑定 LoadBalancerlnterceptor 拦截器。
	**/
	@Bean
	@ConditionalOnMissingBean
	public LoadBalancerRequestFactory loadBalancerRequestFactory(
			LoadBalancerClient loadBalancerClient) {
		return new LoadBalancerRequestFactory(loadBalancerClient, transformers);
	}

	@Configuration
	@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
	static class LoadBalancerInterceptorConfig {
		@Bean
		public LoadBalancerInterceptor ribbonInterceptor(
				LoadBalancerClient loadBalancerClient,
				LoadBalancerRequestFactory requestFactory) {
			return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
		}

		@Bean
		@ConditionalOnMissingBean
		public RestTemplateCustomizer restTemplateCustomizer(
				final LoadBalancerInterceptor loadBalancerInterceptor) {
			return restTemplate -> {
                List<ClientHttpRequestInterceptor> list = new ArrayList<>(
                        restTemplate.getInterceptors());
                list.add(loadBalancerInterceptor);
                restTemplate.setInterceptors(list);
            };
		}
	}
}

LoadBalancerInterceptor-负载均衡拦截器

public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {

	private LoadBalancerClient loadBalancer;
	private LoadBalancerRequestFactory requestFactory;

    /**
	* 利用 ClientHttpRequestlnterceptor 来对每次 HTTP 请求进行拦截的,此类是 Spring 中维护的请求拦截器,
	* 实现它的 intercept 方法就可以使请求进入方法体,从而做一些处理。
	* 可以看出这里把请求拦截下来之后使用了 LoadBalancerClient 的 execute 方法来处理请求 
	**/
	@Override
	public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
			final ClientHttpRequestExecution execution) throws IOException {
		final URI originalUri = request.getURI();
		String serviceName = originalUri.getHost();
		Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
		return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
	}
}

LoadBalancerClient实现类RibbonLoadBalancerClient负载均衡

public class RibbonLoadBalancerClient implements LoadBalancerClient {
    @Override
	public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
    	// 获取具体的服务实例 就是根基服务的实例名字获取服务的相关元数据信息
		ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
    	// Server 就是具体服务实例的封装,就是发生负载均衡过程的地方
		Server server = getServer(loadBalancer);
		if (server == null) {
			throw new IllegalStateException("No instances available for " + serviceId);
		}
		RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,serviceId), serverIntrospector(serviceId).getMetadata(server));
		// 执行请求
		return execute(serviceId, ribbonServer, request);
	}
    
    protected Server getServer(ILoadBalancer loadBalancer) {
		if (loadBalancer == null) {
			return null;
		}
		return loadBalancer.chooseServer("default"); // default 就是默认的负载均衡算法的key
	}

     public Server chooseServer(Object key) {
        if (counter == null) {
            counter = createCounter();
        }
        counter.increment();
        if (rule == null) {
            return null;
        } else {
            try { 
                // rule.choose(key) 中的 rule 其实就是 IRule, 至此,拦截的HTTP 请求与负载均衡策略得以关联起来
                return rule.choose(key);
            } catch (Exception e) {
                logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", name, key, e);
                return null;
            }
        }
    }
}

引用:https://github.com/Netflix/ribbon
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RachelHwang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值