avatar

Nacos-服务启动无法获取配置问题排查与解决

一、问题背景

在微服务架构中,Nacos 作为配置中心和服务注册中心被广泛使用。但在生产环境中,我们遇到了应用启动时无法从 Nacos 获取配置的问题,导致应用启动失败。本文将详细分析该问题的排查过程、根本原因及解决方案。

二、问题描述

1、问题现象

Java 应用在启动时连接 Nacos 超时,导致配置读取失败、应用启动异常。具体表现为:

  • 应用启动过程卡顿约 15 秒
  • 随后报错读取配置失败,提示”【XXX】配置文件is empty”
  • 日志中显示连接 Nacos 超时

2、环境信息

  • JDK 版本:JDK 8
  • Spring Cloud Alibaba 版本:2.2.0.RELEASE
  • Nacos 版本:2.4.1
  • 操作系统:CentOS 7

三、问题排查过程

1、初步排查

首先,我们检查了 Nacos 服务端的运行状态和网络连通性:

1
2
3
4
5
6
7
8
# 检查 Nacos 服务是否正常运行
ps -ef | grep nacos

# 检查 Nacos 服务端口是否正常监听
netstat -anp | grep 8848

# 检查应用服务器到 Nacos 服务器的网络连通性
telnet <nacos-server-ip> 8848

检查结果显示 Nacos 服务正常运行,网络连通性也没有问题。

2、日志分析

通过分析应用启动日志,我们发现以下关键信息:

  • 应用在启动过程中卡顿约 15 秒
  • 卡顿发生在 Spring 容器初始化的早期阶段
  • 卡顿结束后立即报错无法从 Nacos 获取配置

3、深入分析

为了定位卡顿的具体原因,我们在应用中添加了详细的日志,并使用 JVM 分析工具进行分析。最终发现,卡顿发生在 java.net.InetAddress.getLocalHost() 方法调用上。

四、根本原因分析

1、Java 网络栈的初始化机制

Java 虚拟机(JVM)在获取本地主机地址时,遵循一套严格的查找逻辑。当应用代码(或其依赖的中间件 SDK)调用 java.net.InetAddress.getLocalHost() 时,JVM 会执行以下步骤:

  • 获取主机名:首先通过系统调用获取操作系统的主机名(Hostname,例如 server-01
  • 解析主机名:JVM 必须将这个主机名解析为一个 IP 地址
  • 查找顺序
    • 第一步(最快):检查本地安全策略文件(/etc/hosts)。如果找到 IP 主机名 的映射,立即返回
    • 第二步(最慢):如果未找到,JVM 会向配置的 DNS 服务器发起查询请求
  • DNS 查询陷阱
    • 对于内网环境的服务器,其主机名(如 server-01)通常是私有的,公网 DNS 服务器根本无法解析
    • JVM 会一直等待 DNS 服务器返回”不存在”或超时
    • 默认的 DNS 超时时间通常较长(受 JVM 参数 networkaddress.cache.ttlsun.net.inetaddr.ttl 影响,部分环境可能长达 15 秒甚至更久)

2、Spring 容器与 Nacos 客户端的启动时序

Nacos 客户端通常作为 Spring Boot 的 Starter 依赖被引入。其启动流程具有严格的时序依赖:

  • Spring Boot 启动:开始创建 ApplicationContext
  • Environment 后处理:在刷新上下文的早期阶段,Spring 需要处理配置源。如果配置了 Nacos Config,此时会初始化 Nacos Config Client
  • Nacos 客户端初始化
    • 为了生成唯一的 Client ID 或进行网络通信准备,Nacos Client SDK 可能会触发 InetAddress.getLocalHost()
    • 阻塞点:如果此时触发 DNS 查询,主线程被阻塞 15 秒
  • 服务端超时判定
    • Nacos 服务端对于客户端的连接请求或注册请求都有默认的超时时间(通常远小于 15 秒,例如几秒)
    • 由于客户端在本地解析阶段就消耗了所有时间,导致真正发出的网络请求远远滞后于服务端的预期窗口
    • 结果:服务端判定客户端无响应或连接超时,关闭连接或拒绝请求

3、根因总结

服务器 /etc/hosts 未配置本机主机名映射,导致 Java 应用启动时,InetAddress.getLocalHost() 被迫等待 DNS 解析超时。这 15 秒的延迟发生在 Spring 容器初始化的最早期阶段,导致 Nacos 客户端无法在服务端期望的时间窗口内完成服务注册和配置拉取。

五、解决方案

1、解决方案一:配置 /etc/hosts(优)

在服务器的 /etc/hosts 文件中添加本机主机名映射:

1
2
3
4
5
6
7
8
9
10
# 查看当前主机名
hostname

# 编辑 /etc/hosts 文件
vi /etc/hosts

# 添加以下内容(将 <当前主机名> 替换为实际的主机名)
127.0.0.1 localhost localhost.localdomain <当前主机名>
# 或者使用实际 IP
192.168.x.x <当前主机名>

2、解决方案二:指定 Nacos 客户端 IP(不建议)

在应用配置中指定 Nacos 客户端的 IP 地址:

1
2
3
4
5
6
spring:
cloud:
nacos:
config:
#直接指定为127.0.0.1,只适合nacos和服务在同一台主机
server-addr: 127.0.0.1

六、总结

本文详细分析了应用启动时无法从 Nacos 获取配置的问题。问题的根本原因是服务器 /etc/hosts 未配置本机主机名映射,导致 Java 应用启动时,InetAddress.getLocalHost() 被迫等待 DNS 解析超时,从而影响了 Nacos 客户端的初始化和配置拉取。

通过在 /etc/hosts 文件中添加本机主机名映射,可以有效解决这个问题。

在生产环境中,建议在服务器初始化时就配置好 /etc/hosts 文件,避免因 DNS 解析问题导致应用启动失败。

另外,这其实是个偶现问题,我在其他服务器上并没有复现这个问题。

文章作者: Frosro
文章链接: https://frosro.github.io/2026/04/17/Nacos-%E6%9C%8D%E5%8A%A1%E5%90%AF%E5%8A%A8%E6%97%A0%E6%B3%95%E8%8E%B7%E5%8F%96%E9%85%8D%E7%BD%AE%E9%97%AE%E9%A2%98/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 BETTER LATE THAN NEVER
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论