背景

在feign中,一般是通过eureka、nacos等获取服务实例,但有时候调用一些服务时,人家给的是ip或域名,我们这时候还能用Feign这一套吗?

可以的。

有两种方式,一种是直接指定url:

这种是服务端自己会保证高可用、负载均衡那些。

但也可能对方给了多个url(一般不会这样,但是在app场景下,为了极致的高可用,可能会配置多个服务端地址),此时就需要咱们在客户端配置多个url,并且进行负载均衡。

此时应该怎么配置呢?前面的文章提到了,可以像下面这样配置:

spring:
application:
discovery:
client:
simple:
instances:
echo-service-provider:
- uri: http://1.1.1.1:8082
metadata:
my: instance1
- uri: http://2.2.2.2:8082
metadata:
my: instance2

但是,这第二种方式下,如果你同时使用了nacos,且打开了spring.cloud.loadbalancer.nacos.enabled=true这个选项,就会发现,调用报错了。

原因分析

从上面的错误堆栈可以看到,在执行Double.parseDouble的时候抛了空指针异常,为啥还涉及什么浮点数呢?

我们定位到报错的地方,原来是获取服务实例的权重值的时候,报错了:

很明显,是因为我们的服务实例里面的metadata字段,没有nacos.weight这个属性,所以是null,自然就空指针了。

这里的服务实例是ServiceInstance,这是个通用接口,定义在spring-cloud-commons中的,按理说,你作为一种实现,是需要考虑到传入的ServiceInstance不一定就有这个属性,比如可能是Eureka管理的。但是上面报错的地方又强制假设这个地方一定是metadata拥有nacos.weight。

这块就是个兼容性bug,看了下最新版本,也还是未修复:

https://github.com/alibaba/spring-cloud-alibaba/blob/2022.x/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/balancer/NacosBalancer.java#L58

接下来,我们看下,那如果是从nacos获取到的serviceInstance,是不是就没有这个问题?为啥配置静态ip地址的时候,就有这个问题。

nacos中获取到的serviceInstance

咱们先把前面的静态ip配置去掉,改为从nacos获取。

从上图看到,此时实例类型是com.alibaba.cloud.nacos.NacosServiceInstance:

此时自然就不会报错了。

静态ip时获取到的serviceInstance

在获取服务实例时,入口是org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClient#getInstances,它内部聚合了两个discoveryClient,第一个是simpleDiscoveryClient,这个就是从静态ip获取服务实例,可以看到其order是-1,所以它排在了第一位;第二个是nacosDiscoveryClient,由于它的order值是0,所以排序靠后。

从simpleDiscoveryClient中获取到的serviceInstance的类型就是org.springframework.cloud.client.DefaultServiceInstance,它内部自然是没有配置nacos相关的metadata的,所以在前面的场景中才会报错。

解决办法一

既然nacos这个loadbalancer不兼容静态ip这种org.springframework.cloud.client.DefaultServiceInstance,那我不使用nacos的loadbalancer不就可以了。

是的,只要你不打开spring.cloud.loadbalancer.nacos.enabled=true这个选项,就不会用到nacos的这个loadbalancer。

我们搜了下这个选项:

这被弄成了一个条件注解。这个条件用于以下的自动装配类:

在之前的文章里,我们提到了,每个feign服务只要url没指定,就默认是走负载均衡,就会有一个loadbalancerClient。

每个loadbalancerClient都是通过一个spring容器来的,每个服务都有一个自己的用于创建loadbalancer的spring容器(比如这里的echo-service,就有一个自己的用于创建loadbalancer的spring容器)。这个容器里面默认有啥内容呢?

@LoadBalancerClients(defaultConfiguration = NacosLoadBalancerClientConfiguration.class)

这里的NacosLoadBalancerClientConfiguration.class就会被作为各个spring容器的默认配置类。

这里就会自动配置一个NacosLoadBalancer,一旦有了这个bean,spring-cloud-loadbalancer里的默认配置,就不会生效了:

最终获取bean的时候,就拿到了nacos的这个NacosLoadBalancer类型的bean,进行负载均衡。

这个办法的缺点:

这个选项是全局的,不能针对某一个服务来单独开启,这个选项一旦关了,那么其他的走nacos的服务,也就没法用nacosLoadBalancer了。

所以,我们想到了如下的方法。

解决办法二

我们上面提到,这个nacosLoadBalancer被自动装配进去的,那么,破解自动装配的办法就是你自己定义一个这种类型的bean,它就不会再自动装配了。

这样的话,echo-service-provider的spring容器创建时,就会优先把这个配置class注册到容器里:

这种办法的优势是,可以在spring.cloud.loadbalancer.nacos.enabled=true开启的情况下,解决本文的问题。就是,nacos的依然可以用nacosLoadBalancer来负载均衡;静态ip的服务,就可以用轮询这种loadbalancer。

总结

这个feign写得差不多了,后面写点别的。如果后续需要补充这块,再说。

参考

官网有类似bug:

https://github.com/alibaba/spring-cloud-alibaba/issues/3346

Feign源码解析7:nacos loadbalancer不支持静态ip的负载均衡的更多相关文章

  1. Feign源码解析

    1. Feign源码解析 1.1. 启动过程 1.1.1. 流程图 1.1.2. 解释说明 Feign解析过程依赖Spring的初始化,它通过实现ImportBeanDefinitionRegistr ...

  2. 从源码解析Nginx对 Native aio支持_运维_youbingchen的博客-CSDN博客 https://blog.csdn.net/youbingchen/article/details/51767587

    从源码解析Nginx对 Native aio支持_运维_youbingchen的博客-CSDN博客 https://blog.csdn.net/youbingchen/article/details/ ...

  3. [源码解析] TensorFlow 分布式环境(2)---Master 静态逻辑

    [源码解析] TensorFlow 分布式环境(2)---Master 静态逻辑 目录 [源码解析] TensorFlow 分布式环境(2)---Master 静态逻辑 1. 总述 2. 接口 2.1 ...

  4. [源码解析] TensorFlow 分布式环境(3)--- Worker 静态逻辑

    [源码解析] TensorFlow 分布式环境(3)--- Worker 静态逻辑 目录 [源码解析] TensorFlow 分布式环境(3)--- Worker 静态逻辑 1. 继承关系 1.1 角 ...

  5. Eureka源码探索(一)-客户端服务端的启动和负载均衡

    1. Eureka源码探索(一)-客户端服务端的启动和负载均衡 1.1. 服务端 1.1.1. 找起始点 目前唯一知道的,就是启动Eureka服务需要添加注解@EnableEurekaServer,但 ...

  6. Feign源码解析系列-注册套路

    感谢不知名朋友的打赏,感谢你的支持! 开始 在追寻Feign源码的过程中发现了一些套路,既然是套路,就可以举一反三,所以值得关注. 这篇会详细解析Feign Client配置和初始化的方式,这些方式大 ...

  7. Feign源码解析系列-那些注解们

    开始 Feign在Spring Cloud体系中被整合进来作为web service客户端,使用HTTP请求远程服务时能就像调用本地方法,可见在未来一段时间内,大多数Spring Cloud架构的微服 ...

  8. Feign源码解析系列-最佳实践

    前几篇准备写完feign的源码,这篇直接给出Feign的最佳实践,考虑到目前网上还没有一个比较好的实践解释,对于新使用spring cloud的同学会对微服务之间的依赖产生一些迷惑,也会走一些弯路.这 ...

  9. Feign源码解析系列-核心初始化

    开始 初始化Feign客户端当然是整个过程中的核心部分,毕竟初始化完毕就等着调用了,初始化时候准备的什么,流程就走什么. 内容 从上一篇中,我们已经知道,对于扫描到的每一个有@FeignClient, ...

  10. Android 开源项目源码解析(第二期)

    Android 开源项目源码解析(第二期) 阅读目录 android-Ultra-Pull-To-Refresh 源码解析 DynamicLoadApk 源码解析 NineOldAnimations ...

随机推荐

  1. 【C#】【WinForm】MDI窗体

    MDI窗体的相关学习使用 1.设置MDI父窗体 在属性中找到IsMdiContainer选项,设置为True 2.添加MDI子窗体,在项目中依次选择添加->窗体,然后一直默认即可 添加后的项目目 ...

  2. 5s!用浏览器打造一个开箱即用的Linux系统

    做为Linux系统管理员.或者是系统运维工程师,肯定会在工作遇到这样的需求:需要开发环境.测试环境.准生产环境等等环境,有时候建一个环境费时间不说,还容易出各种错误,好不容易建好了,可能还用不了几天. ...

  3. Spring系列:基于Spring-Jdbc实现事务

    目录 一.事务基本概念 二.编程式事务 三.声明式事务 前期准备 四.基于注解的声明式事务 @Transactional注解标识的位置 事务属性:只读 事务属性:超时 事务属性:回滚策略 事务属性:隔 ...

  4. C# 创建Excel气泡图

    气泡图(Bubble Chart)是可用于展示三个变量之间的关系.通过绘制x 值, y 值和大小值即可确定图表中气泡的坐标及大小.下面通过后端C#代码及VB.NET代码展示如何来实现在Excel中创建 ...

  5. 华为云GaussDB打造最可信的数据库,给世界一个更优选择

    近日,第14届中国数据库技术大会(DTCC2023)在北京国际会议中心顺利举行.大会以"数智赋能 共筑未来"为主题,邀请了上百位行业专家,一起探讨新时代下各类型数据库的最新动态和应 ...

  6. Serverless: AI everywhere的下一块拼图

    摘要:本文介绍华为云函数工作流(FunctionGraph)的灵活.速度,如何让开发人员提升工程效率,缩短TTM等 本文分享自华为云社区<华为云FunctionGraph函数工作流-- Serv ...

  7. DTT第7期直播回顾 | 低代码应用构建流程和适用场景,与你想的一样吗?

    摘要:本期直播主题是<揭秘华为云低代码技术微认证>,向开发者们讲述低代码的发展历程,介绍华为低代码平台应用魔方AppCube的开发能力,解读华为低代码的认证和学习体系 本期直播详解 本期直 ...

  8. 教你VUE中的filters过滤器2种用法

    摘要:Vue.js 允许我们自定义过滤器,可被用于一些常见的文本格式化. 本文分享自华为云社区<VUE中的filters过滤器用法>,作者:小小张自由--张有博. 前言 Vue.js 允许 ...

  9. 带你掌握不同平台下,探索JDK源码所需的native方法

    摘要:要探索JDK的核心底层源码,那必须掌握native用法.文章中会以"获取系统的默认时区"为例,介绍说明如何查看native对应方法的源码. 本文分享自华为云社区<要探索 ...

  10. Windows系统快速安装Superset 0.37

    Windows系统安装Superset 0.37 Superset 是一款由 Airbnb 开源的"现代化的企业级 BI(商业智能) Web 应用程序",其通过创建和分享 dash ...