前提

在阅读这篇博客之前,希望你对SpringCloud套件熟悉和理解,更希望关注下微服务开发平台

概述

在使用springcloud ribbon客户端负载均衡的时候,可以给RestTemplate bean 加一个@LoadBalanced注解,就能让这个RestTemplate在请求时拥有客户端负载均衡的能力,先前有细嚼过但是没有做过笔记,刚好处理此类问题记录下

@LoadBalanced

/**
* 注释将RestTemplate bean标记为配置为使用LoadBalancerClient。
*/
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}

通过源码可以发现这是一个LoadBalanced标记注解并且标记了@Qualifier(基于Spring Boot的自动配置机制),我们可以溯源到LoadBalancerAutoConfiguration

LoadBalancerAutoConfiguration

/**
* 功能区的自动配置(客户端负载平衡)
*/
@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration { @LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList(); //这里持有@LoadBalanced标记的RestTemplate实例 @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) {
for (RestTemplateCustomizer customizer : customizers) {
//为restTemplate添加定制
customizer.customize(restTemplate);
}
}
});
} // ... /**
* 以下针对classpath存在RetryTemplate.class的情况配置,先忽略
*/
@Configuration
@ConditionalOnClass(RetryTemplate.class)
public static class RetryAutoConfiguration { @Bean
@ConditionalOnMissingBean
public LoadBalancedRetryFactory loadBalancedRetryFactory() {
return new LoadBalancedRetryFactory() {
};
}
} // ...
}

@LoadBalanced@Autowried结合使用,意思就是这里注入的RestTempate Bean是所有加有@LoadBalanced注解标记的(持有@LoadBalanced标记的RestTemplate实例)

这段自动装配的代码的含义不难理解,就是利用了RestTempllate的拦截器,使用RestTemplateCustomizer对所有标注了@LoadBalanced的RestTemplate Bean添加了一个LoadBalancerInterceptor拦截器,而这个拦截器的作用就是对请求的URI进行转换获取到具体应该请求哪个服务实例ServiceInstance。

关键问下自己:为什么?

  • RestTemplate实例是怎么被收集的?
  • 怎样通过负载均衡规则获取具体的具体的server?

继续扒看源码>

上面可以看出,会LoadBalancerAutoConfiguration类对我们加上@LoadBalanced注解的bean 添加loadBalancerInterceptor拦截器

LoadBalancerInterceptor

/**
* 功能区的自动配置(客户端负载平衡)。
*/
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor { private LoadBalancerClient loadBalancer; private LoadBalancerRequestFactory requestFactory; public LoadBalancerInterceptor(LoadBalancerClient loadBalancer,
LoadBalancerRequestFactory requestFactory) {
this.loadBalancer = loadBalancer;
this.requestFactory = requestFactory;
} public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
// for backwards compatibility
this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
} @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,
this.requestFactory.createRequest(request, body, execution));
} }

重点看intercept方法 当我们restTemplate执行请求操作时,就会被拦截器拦截进入intercept方法,而loadBalancer是LoadBalancerClient的具体实现

RibbonLoadBalancerClient

	public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
throws IOException {
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
Server server = getServer(loadBalancer, hint);
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);
}

看到这里相信都遇到过类似的错误,恍然大悟

No instances available for  xxxxx

总结

  • 1.根据serviceId 获取对应的loadBalancer
  • 2.根据loadBalancer获取具体的server(这里根据负载均衡规则,获取到具体的服务实例)
  • 3.创建RibbonServer
  • 4.执行具体请求

这里

注意: @LoadBalanced 标记注解获取到最后通过负载均衡规则获取具体的具体的server来发起请求

案例

/**
* 服务注册中心配置
*
* @author <a href="mailto:shangzhi.ibyte@gmail.com">iByte</a>
* @since 1.0.1
*/
@Configuration
@EnableConfigurationProperties(ModuleMappingHelper.class)
public class DiscoveryConfig {
@Autowired
Environment environment; /**
* DiscoveryHeaderHelper默认bean
* @return
*/
@Bean
public DiscoveryHeaderHelper discoveryHeaderHelper() {
DiscoveryHeaderHelper discoveryHeaderHelper = new DiscoveryHeaderHelper(environment);
DiscoveryHeaderHelper.INSTANCE = discoveryHeaderHelper;
return discoveryHeaderHelper;
} /**
* resttemplate构建
*/
@Resource
private RestTemplateBuilder restTemplateBuilder; /**
* resttemplate请求bean,更改系统本身的builder
* @return
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
RestTemplate restTemplate = restTemplateBuilder.configure(new RestTemplate());
//RestTemplate interceptors 远程调用请求增加头部信息处理
restTemplate.getInterceptors().add(new RestApiHeaderInterceptor());
//RestTemplate Set the error handler 错误处理
restTemplate.setErrorHandler(new RestResponseErrorHandler());
return restTemplate;
} @Bean
public DiscoveryClient.DiscoveryClientOptionalArgs discoveryClientOptionalArgs() {
DiscoveryClient.DiscoveryClientOptionalArgs discoveryClientOptionalArgs = new DiscoveryClient.DiscoveryClientOptionalArgs();
discoveryClientOptionalArgs.setAdditionalFilters(Collections.singletonList(new DiscoveryHeaderClientFilter()));
discoveryClientOptionalArgs.setEventListeners(Collections.singleton(new EurekaClientEventListener()));
return discoveryClientOptionalArgs;
}
}

源码地址 > DiscoveryConfig

深入理解@LoadBalanced注解的实现原理与客户端负载均衡的更多相关文章

  1. 为何一个@LoadBalanced注解就能让RestTemplate拥有负载均衡的能力?【享学Spring Cloud】

    每篇一句 你应该思考:为什么往往完成比完美更重要? 前言 在Spring Cloud微服务应用体系中,远程调用都应负载均衡.我们在使用RestTemplate作为远程调用客户端的时候,开启负载均衡极其 ...

  2. Spring Cloud(十四):Ribbon实现客户端负载均衡及其实现原理介绍

    年后到现在一直很忙,都没什么时间记录东西了,其实之前工作中积累了很多知识点,一直都堆在备忘录里,只是因为近几个月经历了一些事情,没有太多的经历来写了,但是一些重要的东西,我还是希望能坚持记录下来.正好 ...

  3. Ribbon使用及其客户端负载均衡实现原理分析

    1.ribbon负载均衡测试 (1)consumer工程添加依赖 <dependency> <groupId>org.springframework.cloud</gro ...

  4. Nginx 负载均衡原理简介与负载均衡配置详解

    Nginx负载均衡原理简介与负载均衡配置详解   by:授客  QQ:1033553122   测试环境 nginx-1.10.0 负载均衡原理 客户端向反向代理发送请求,接着反向代理根据某种负载机制 ...

  5. HA主备路由模式的原理 + HA和负载均衡的区别

       HA主备路由模式的原理 HA是High Availability缩写,即高可用性 ,可防止网络中由于单个防火墙的设备故障或网络故障导致网络中断,保证网络服务的连续性和安全强度.目前,ha功能已经 ...

  6. springcloud ribbon的 @LoadBalanced注解

    在使用springcloud ribbon客户端负载均衡的时候,可以给RestTemplate bean 加一个@LoadBalanced注解,就能让这个RestTemplate在请求时拥有客户端负载 ...

  7. Spring cloud 之Ribbon(二)负载均衡原理

    ribbon实现负载均衡的原理 我们从Ribbon实现负载均衡的代码可以看到,Ribbon是通过RestTemPlate实现客户端负载均衡的,准确的说是RestTemPlate上的@LoadBalan ...

  8. SpringCloud学习笔记(7)----Spring Cloud Netflix之负载均衡-Ribbon的深入理解

    1. 注解@LoadBalanced 作用:识别应用名称,并进行负载均衡. 2. 入口类:LoadBalancerAutoConfiguration 说明:类头上的注解可以知道Ribbon 实现的负载 ...

  9. F5负载均衡原理

    一. 负载均衡技术 负载均衡技术在现有网络结构之上提供了一种廉价.有效.透明的方法,来扩展网络设备和服务器的带宽.增加吞吐量.加强网络数据处理能力.提高网络的灵活性和可用性. 1.负载均衡发生的流程图 ...

随机推荐

  1. 从零开始入门 K8s | Kubernetes 网络概念及策略控制

    作者 | 阿里巴巴高级技术专家  叶磊 一.Kubernetes 基本网络模型 本文来介绍一下 Kubernetes 对网络模型的一些想法.大家知道 Kubernetes 对于网络具体实现方案,没有什 ...

  2. Travis CI持续集成使用

    用好这个工具不仅可以提高效率,还能使开发流程更可靠和专业化,从而提高软件的价值.而且,它对于开源项目是免费的,不花一分钱,就能帮你做掉很多事情. 一.什么是持续集成? Travis CI 提供的是持续 ...

  3. PHP弱性处理0e开头md5哈希字符串缺陷/bug

    PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会认为他 ...

  4. 爬虫1:html页面+beautifulsoap模块+get方式+demo

    前言:最近公司要求编写一个爬虫,需要完善后续金融项目的数据,由于工作隐私,就不付被爬的网址url了,下面总结下spider的工作原理. 语言:python:工具:jupyter:    概要:说到爬虫 ...

  5. KMP算法复习笔记

    KMP 算法 KMP 算法是一种改进的字符串匹配算法,KMP 算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的.具体实现就是实现一个next()函数,函数本身包含了 ...

  6. ‎Cocos2d-x 学习笔记(14.2) EventListener _paused _isEnabled _isRegistered

    监听器3个bool类型成员变量. 监听器能设置是否能够接收事件. 能随时接收事件进行处理,此时把它看做工作状态,需要满足条件:     _paused = false;     _isEnabled ...

  7. 约瑟夫环问题详解(java版)

    1 什么是约瑟夫环问题? 约瑟夫,是一个古犹太人,曾经在一次罗马叛乱中担任将军,后来战败,他和朋友及另外39个人躲在一口井里,但还是被发现了.罗马人表示只要投降就不死,约瑟夫想投降,可是其他人坚决不同 ...

  8. opencv::模板匹配(Template Match)

    模板匹配介绍 模板匹配就是在整个图像区域发现与给定子图像匹配的小块区域. 所以模板匹配首先需要一个模板图像T(给定的子图像) 另外需要一个待检测的图像-源图像S 工作方法,在带检测图像上,从左到右,从 ...

  9. 简单理解TCP通信的三次握手

    TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接. 位码(可以理解为请求状态): 有6种标示:SYN(synchronous建立联机) ACK(acknowledg ...

  10. 15.Nginx动静分离Rewrite

    1.什么是动静分离? 将动态请求和静态请求区分访问, 2.为什么要做动静分离? 静态由Nginx处理, 动态由PHP处理或Tomcat处理.... 因为Tomcat程序本身是用来处理jsp代码的,但t ...