前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Feign源码解析7:nacos loadbalancer不支持静态ip的负载均衡

Feign源码解析7:nacos loadbalancer不支持静态ip的负载均衡

作者头像
低级知识传播者
发布2024-01-23 16:47:03
7490
发布2024-01-23 16:47:03
举报
文章被收录于专栏:低级Java知识传播者

背景

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

可以的。

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

image-20240121151018163

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

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

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

代码语言:javascript
复制
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这个选项,就会发现,调用报错了。

image-20240121151628850

原因分析

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

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

image-20240121151853048

很明显,是因为我们的服务实例里面的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

image-20240121152632222

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

nacos中获取到的serviceInstance

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

image-20240121153456819

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

image-20240121153542584

此时自然就不会报错了。

静态ip时获取到的serviceInstance

image-20240121153910030

在获取服务实例时,入口是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的,所以在前面的场景中才会报错。

image-20240121153833435

解决办法一

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

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

我们搜了下这个选项:

image-20240121154722753

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

image-20240121154806179

image-20240121154854657

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

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

代码语言:javascript
复制
@LoadBalancerClients(defaultConfiguration = NacosLoadBalancerClientConfiguration.class)

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

image-20240121155450960

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

image-20240121155754346

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

image-20240121160127329

这个办法的缺点:

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

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

解决办法二

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

image-20240121162841370

image-20240121162914911

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

image-20240121163142851

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

总结

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-01-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 低级知识传播者 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 原因分析
    • nacos中获取到的serviceInstance
      • 静态ip时获取到的serviceInstance
        • 解决办法一
          • 解决办法二
          • 总结
          相关产品与服务
          负载均衡
          负载均衡(Cloud Load Balancer,CLB)提供安全快捷的四七层流量分发服务,访问流量经由 CLB 可以自动分配到多台后端服务器上,扩展系统的服务能力并消除单点故障。轻松应对大流量访问场景。 网关负载均衡(Gateway Load Balancer,GWLB)是运行在网络层的负载均衡。通过 GWLB 可以帮助客户部署、扩展和管理第三方虚拟设备,操作简单,安全性强。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档