springcloud openfeign 偶现 Caused by: java.net.UnknownHostException

背景

最近查看日志发现某服务偶现Caused by: java.net.UnknownHostException 同时查看eureka的access.log 出现如下异常

10.xxx.xxx.xxx - - [27/May/2025:23:57:29 +0800] "PUT /eureka/apps/{appName}/{host}:xxx-job:8082?status=UP&lastDirtyTimestamp=1748351637173 HTTP/1.1" 404 -

问题关联分析

1. 问题链条

scss 复制代码
Eureka心跳续约失败(404) → 服务从注册中心下线 → 服务发现失败 → DNS解析失败 → UnknownHostException

2. 具体流程

  1. xxx-job 服务向Eureka发送心跳续约请求
  2. Eureka Server返回404,表示该服务实例不存在
  3. 经过几次失败后,Eureka Server将该服务实例从注册表中移除
  4. 其他服务调用 xxx-job 时,从Eureka获取不到该服务的实例信息
  5. Spring Cloud LoadBalancer无法解析 xxx-job 服务名
  6. 最终抛出 UnknownHostException: xxx-job

为什么会出现404错误

1. 服务注册不完整

yaml 复制代码
# 可能的配置问题
eureka:
  client:
    initial-instance-info-replication-interval-seconds: 40  # 初始注册延迟太长
    instance-info-replication-interval-seconds: 30

2. Eureka Server清理策略

yaml 复制代码
# Eureka Server可能过于激进地清理实例
eureka:
  server:
    eviction-interval-timer-in-ms: 60000  # 清理间隔
    enable-self-preservation: false       # 自我保护模式关闭

3. 网络问题导致注册失败

实例ID中的 host 可能存在DNS解析问题。

解决方案

1. 修复服务注册配置

yaml 复制代码
eureka:
  client:
    service-url:
      defaultZone: http://eureka-server:8761/eureka/
    register-with-eureka: true
    fetch-registry: true
    initial-instance-info-replication-interval-seconds: 5
    instance-info-replication-interval-seconds: 10
  instance:
    prefer-ip-address: true
    ip-address: xxx.xxx.xxx.xxx
    instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}
    lease-renewal-interval-in-seconds: 10
    lease-expiration-duration-in-seconds: 30

2. 启用Eureka Server自我保护模式

yaml 复制代码
eureka:
  server:
    enable-self-preservation: true
    renewal-percent-threshold: 0.85
    eviction-interval-timer-in-ms: 120000

3. 添加重试机制

yaml 复制代码
# 为Feign客户端添加重试
feign:
  client:
    config:
      default:
        retryer: feign.Retryer.Default

4. 监控和诊断

java 复制代码
@Component
public class ServiceHealthMonitor {
    
    @Autowired
    private EurekaClient eurekaClient;
    
    @Scheduled(fixedRate = 30000)
    public void checkServiceHealth() {
        Application app = eurekaClient.getApplication("xxx-job");
        if (app == null || app.getInstances().isEmpty()) {
            logger.warn("xxx-job服务不可用");
        }
    }
}

5. 应急预案

java 复制代码
@Component
public class ServiceFallback {
    
    @Retryable(value = UnknownHostException.class, maxAttempts = 3)
    public String callXxxjob() {
        // 服务调用逻辑
    }
    
    @Recover
    public String recover(UnknownHostException ex) {
        logger.error("服务调用失败,启用降级策略", ex);
        return "服务暂时不可用";
    }
}

验证步骤

  1. 检查Eureka Dashboard :确认xxx-job服务是否持续在线
  2. 监控日志:观察404错误的频率和时间模式
  3. 测试网络ping host
  4. 检查服务启动顺序:确保Eureka Server先启动

这个问题的核心是服务注册中心的状态不一致,建议重点解决服务注册稳定性问题。

相关推荐
Mr Aokey39 分钟前
Spring MVC参数绑定终极手册:单&多参/对象/集合/JSON/文件上传精讲
java·后端·spring
地藏Kelvin1 小时前
Spring Ai 从Demo到搭建套壳项目(二)实现deepseek+MCP client让高德生成昆明游玩4天攻略
人工智能·spring boot·后端
菠萝012 小时前
共识算法Raft系列(1)——什么是Raft?
c++·后端·算法·区块链·共识算法
长勺2 小时前
Spring中@Primary注解的作用与使用
java·后端·spring
小奏技术3 小时前
基于 Spring AI 和 MCP:用自然语言查询 RocketMQ 消息
后端·aigc·mcp
编程轨迹3 小时前
面试官:如何在 Java 中读取和解析 JSON 文件
后端
lanfufu3 小时前
记一次诡异的线上异常赋值排查:代码没错,结果不对
java·jvm·后端
编程轨迹3 小时前
如何在 Java 中实现 PDF 与 TIFF 格式互转
后端
编程轨迹3 小时前
面试官:你知道如何在 Java 中创建对话框吗
后端
编程轨迹3 小时前
深入理解 Java 中的信号机制
后端