Feign远程调用失败问题

今天在调试代码的时候遇到了一个远程调用失败的问题,用Feign调用服务名时,无法从服务名解析成对应的URL。FeignClient接口如下:

@FeignClient("blogservice")
public interface BlogClient {

    @RequestMapping("/category/getCategoryListTest")
    List<CategoryVo> getCategoryList();

    @RequestMapping("/category/getNacosConfig")
    NacosConfigEntity getNacosConfig();

}

按理来说,FeignClient应该将"/blogservice/category/getNacosConfig"解析为Nacos中的blogservice服务,即“http://localhost:8888/category/getNacosConfig”,而我在调用时报错“nested exception is java.net.UnknownHostException”,且调用的URL显示的是服务名称,而不是真正的URL;在我显式指定了FeignClient对应的URL地址后,又能够成功访问了,说明确实出现了服务名解析问题。

//显式指定的方法,相当于写死URL,无法依靠负载均衡策略做分布式,没什么意义
@FeignClient(value = "blogservice", url = "http://localhost:8888/")

没道理啊,我另一个工程代码基本一模一样,调用没一点问题,于是我开始了对这个问题漫长的分析。

首先怀疑是负载均衡失效,Ribbon无法根据服务名寻找到正确的服务,以及它对应的URL。为了印证是负载均衡的问题,我用RestTemplate代替Feign来进行远程调用,同样用服务名来调用服务。这时报出了这样的错误“java.lang.IllegalStateException: No instances available for localhost”,意为没有找到对应的服务实例,而Nacos控制台的服务全部注册成功且健康无比,说明问题确实出现在负载均衡上。

接下来我继续使用RestTemplate,看看调整负载均衡策略是否能解决这个问题。于是我在RestTemplate上加入了@LoadBalanced开启负载均衡,并注入IRule中的随机策略。加入@LoadBalanced的RestTemplate会被加上一个loadBalancerInterceptor拦截器,在这个RestTemplate发起请求时,会将其拦住并寻找对应的实例地址,再根据负载均衡策略进行挑选。

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    @Bean
    public IRule randomRule() {
        return new RandomRule();
    }

但是代码中IRule一直爆红,怎么都无法引入。IRule来自于“com.netflix.loadbalancer”中,虽然资料显示SpringCloudAlibaba是整合了Netflix相关组件的,但是SpringCloud新版本对于Netflix支持不是很友好,所以我自己引入了一个netflix-ribbon

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

这个时候IRule确实是不爆红了,再次调用接口还是显示没有服务实例。按理来说负载均衡策略应该已经生效了,数个服务实例也都正常运行,但还是没法正常调用,只能把思路转向另一个方向。

项目一开始的版本管理是SpringBoot 2.5.0 + SpringCloud 2020.0.3 + SpringCloud Alibaba 2.2.5.RELEASE,之前因为SpringBoot与SpringCloud版本有强对应关系,导致Nacos的无法正常启动,因此我调整过对应的版本很多次。但我在让SpringBoot和SpringCloud版本对应的时候,并没有管SpringCloud Alibaba的版本。于是我去搜索了一下他们三者的版本对应关系,果然一查发现SpringCloud Hoxton.SR8才能与SpringCloud Alibaba 2.2.5.RELEASE兼容,说明他们三者存在版本冲突问题。

发现这个问题后,我开始了漫长的排列组合,最后将所有版本回退,使用如下版本才正常了。

        <spring.cloud-version>Hoxton.SR8</spring.cloud-version>
        <spring.cloud.alibaba-version>2.2.3.RELEASE</spring.cloud.alibaba-version>
        <spring.boot-version>2.3.2.RELEASE</spring.boot-version>

RestTemplate调用正常后,我又用Feign进行远端调用也成功了,且负载均衡策略也正常运行。泪目,这问题是真坑啊。

### 解决Feign远程调用超时问题 #### 配置超时时间 对于Feign客户端,默认情况下其连接和读取操作都有一个较短的超时设定,通常为1秒。当遇到较为耗时的服务请求时,这可能导致调用失败的情况发生[^1]。 为了应对这种情况,在Spring Boot应用中可以通过自定义`feign.Client`来调整这些参数。一种方法是在项目的配置文件(application.properties 或 application.yml)里指定全局性的超时设置: ```properties # application.properties 文件中的配置方式 feign.client.config.default.connectTimeout=5000 feign.client.config.default.readTimeout=5000 ``` 或者采用YAML格式: ```yaml # application.yml 文件中的配置方式 feign: client: config: default: connectTimeout: 5000 readTimeout: 5000 ``` 上述配置适用于所有通过Feign发起的HTTP请求;如果希望针对特定服务单独定制,则可以替换掉`default`关键字并使用目标服务名称作为键名[^2]。 另外需要注意的是,虽然简单地增加超时期限能够解决问题,但这可能会带来其他风险,比如占用更多网络资源或影响整体性能表现[^3]。 #### 处理超时异常的最佳实践 除了合理地设置超时时长外,还需要考虑如何优雅地处理可能出现的超时错误。建议采取如下措施: - **重试机制**:利用Hystrix或其他熔断器库实现自动化的重试逻辑,以便在网络波动的情况下提高成功率。 - **降级策略**:预先准备好备用方案,一旦检测到上游依赖不可达或是响应过慢时立即切换至替代数据源或返回默认值。 - **监控报警**:集成Prometheus、Grafana等工具持续跟踪API的表现状况,并及时发出警告通知运维团队介入调查根本原因。 综上所述,解决Feign远程调用超时的关键在于找到合适的平衡点——既不过度放宽时限以免造成不必要的延迟累积,也不过分严苛以至于频繁触发故障转移流程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值