📣 极限科技诚招搜索运维工程师(Elasticsearch/Easysearch)- 全职/北京 👉 : 立即申请加入

适用版本: 7.13-8.x

1. 错误异常的基本描述 #

failed to start watching service_tokens file [path] 表示 Elasticsearch 安全模块在尝试为 service_tokens 文件注册文件变更监控时失败。该文件用于存放服务账户(Service Account)对应的令牌信息,Elasticsearch 通过文件监控机制实现令牌的热加载,无需重启节点即可感知令牌变更。

当监控注册失败时,节点无法自动感知 service_tokens 文件的内容变化,这意味着新增、修改或删除的服务令牌不会被实时生效,可能影响依赖服务账户令牌的客户端请求、API 调用或跨集群访问场景。

常见现象 #

  • 节点启动日志或运行日志中出现 failed to start watching service_tokens file 异常信息,伴随 IOExceptionElasticsearchException
  • 修改 service_tokens 文件后,新的服务令牌无法被节点识别,相关请求返回 401 Unauthorized403 Forbidden
  • 在容器化部署或 Kubernetes 环境中,该错误出现频率较高,尤其是在使用 ConfigMap、Secret 或网络文件系统挂载令牌文件时。
  • 部分节点正常而部分节点报错,通常指向特定节点的文件系统或挂载配置差异。

典型报错与异常栈 #

日志中常见的异常形态如下:

ElasticsearchException: failed to start watching service_tokens file [/path/to/service_tokens]
Caused by: java.io.IOException: Unable to register watch for file
	at org.elasticsearch.watcher.FileWatcher...
Caused by: java.nio.file.WatchException: Too many open files

2. 为什么会发生这个错误 #

service_tokens 文件的监控依赖底层操作系统的文件通知机制(Linux 下为 inotify,macOS 下为 FSEvents,Windows 下为 ReadDirectoryChangesW)。当 Elasticsearch 调用 resourceWatcherService.add() 为文件父目录注册监控时,若底层机制不可用或资源不足,就会抛出此异常。

常见原因通常包括:

  • 目录不存在或路径错误service_tokens 文件所在的父目录尚未创建,或 xpack.security.authc.service.token_hashes_file.path 配置指向了不存在的路径。
  • 文件权限不足:Elasticsearch 运行用户(如 elasticsearch)对 service_tokens 文件或其父目录缺少读取、执行(遍历目录)权限,导致无法在该目录上注册监控。
  • 容器/网络文件系统限制:Docker、Kubernetes 的某些卷类型(如 emptyDirhostPath 的某些挂载方式)、NFS、CIFS 等网络文件系统不支持 inotify 文件监控,或监控行为存在延迟和异常。
  • 系统 inotify 资源耗尽:Linux 系统下 fs.inotify.max_user_watchesfs.inotify.max_user_instances 达到上限,无法为新目录注册监控。
  • 文件句柄耗尽:节点打开的文件句柄数达到 ulimit -n 限制,间接导致文件监控注册失败。
  • 只读文件系统:令牌文件被放置在只读挂载点(如某些容器镜像的只读层),文件监控机制无法正常工作。
  • 安全配置错误service_tokens 文件路径配置错误,指向了非常规位置,而该位置的文件系统类型不支持监控。

3. 如何排查和解决这个异常 #

建议按以下顺序逐步排查:

  1. 确认文件路径与存在性:检查 service_tokens 文件的绝对路径,确认文件及其父目录真实存在。可通过 ls -la 查看文件状态。
  2. 检查目录权限:确认 Elasticsearch 运行用户对文件父目录拥有 rx 权限(读取和遍历),对文件本身拥有 r 权限。
  3. 检查系统 inotify 配置(Linux):执行 cat /proc/sys/fs/inotify/max_user_watchescat /proc/sys/fs/inotify/max_user_instances,确认未达上限。
  4. 检查文件句柄限制:执行 ulimit -n 查看当前限制,结合 lsof -p <es_pid> | wc -l 确认是否接近上限。
  5. 确认文件系统类型:在容器或特殊挂载场景下,使用 df -Tmount | grep <path> 确认文件所在文件系统类型是否支持 inotify
  6. 区分异常类型:注意区分 failed to start watching service_tokens file(监控注册失败)和 Failed to load service_tokens file(文件内容加载失败),两者根因不同。

排查时需要注意的问题 #

  • 不要将监控失败直接等同于令牌内容错误,前者是文件系统/权限问题,后者是文件格式问题。
  • 在 Kubernetes 环境中,若使用 ConfigMap 或 Secret 挂载 service_tokens 文件,需注意某些版本中 ConfigMap 的更新不会触发 inotify 事件,或存在显著延迟。
  • 若仅部分节点报错,优先对比各节点的配置文件、挂载方式和系统参数,而非直接怀疑 Elasticsearch 版本问题。

4. 如何解决这个错误 #

常用修复思路 #

  • 修正文件路径与权限:确保 service_tokens 文件放置在 Elasticsearch 可访问的本地目录,并赋予正确的权限。推荐将文件放在 $ES_PATH_CONF 目录下(如 config/service_tokens),由 Elasticsearch 自动管理。

    # 确认文件与目录权限
    ls -la $ES_PATH_CONF/service_tokens
    chown elasticsearch:elasticsearch $ES_PATH_CONF/service_tokens
    chmod 600 $ES_PATH_CONF/service_tokens
    
  • 调整系统 inotify 限制(Linux):若 inotify 资源不足,可适当调大内核参数。

    # 临时调整
    sysctl -w fs.inotify.max_user_watches=524288
    sysctl -w fs.inotify.max_user_instances=1024
    
    # 持久化配置
    echo "fs.inotify.max_user_watches=524288" >> /etc/sysctl.conf
    echo "fs.inotify.max_user_instances=1024" >> /etc/sysctl.conf
    sysctl -p
    
  • 调整文件句柄限制:修改系统 ulimit 配置,确保 Elasticsearch 进程有足够的文件句柄。

    # 在 systemd service 文件中添加
    LimitNOFILE=65536
    
  • 避免不支持监控的挂载方式:将 service_tokens 文件放在节点本地文件系统(如 ext4xfs)上,而非 NFS、CIFS 或某些容器特殊卷上。若必须在容器中管理令牌文件,考虑使用 hostPath 挂载本地目录。

  • 重启节点:在修复上述配置后,重启 Elasticsearch 节点使文件监控重新注册。

后续注意事项与推荐建议 #

  • service_tokens 文件纳入配置管理,避免手动修改后忘记同步到所有节点。
  • 建立对节点日志中 failed to start watching 关键字的告警规则,尽早发现监控异常。
  • 在 Kubernetes 环境中,若使用 Secret 管理令牌文件,建议结合 reloader 等工具主动触发令牌重载,而非依赖 inotify。
  • 定期审查服务账户令牌的使用情况,清理不再使用的令牌,减少令牌文件大小和监控压力。

借助 INFINI 产品提升排障效率 #

  • INFINI Console 适合查看集群健康度、节点日志、安全配置状态和错误趋势,帮助快速判断异常是局部节点问题还是全局配置问题。
  • INFINI Gateway 可部署在 Elasticsearch 前面做请求观测和流量治理,当服务令牌失效导致 401/403 错误时,可通过 Gateway 的日志和指标快速定位是令牌问题还是其他权限问题。

5. 小结 #

failed to start watching service_tokens file 指向的是文件监控注册失败,而非令牌内容本身的问题。排查时应优先关注目录存在性、文件权限、文件系统类型以及系统 inotify/文件句柄资源,而非直接修改令牌文件内容。在容器化和云原生部署场景下,尤其需要注意挂载方式和文件系统对 inotify 的支持情况。

只要把文件路径、权限、系统参数和部署方式四个维度检查到位,大多数此类异常都可以快速定位并修复。

相关错误 #

附:日志上下文 #

下面保留当前页面中的源码片段,便于结合异常调用栈定位问题:

FileWatcher watcher = new FileWatcher(file.getParent());
watcher.addListener(new FileReloadListener(file, this::tryReload));
try {
    resourceWatcherService.add(watcher, ResourceWatcherService.Frequency.HIGH);
} catch (IOException e) {
    throw new ElasticsearchException("failed to start watching service_tokens file [{}]", e, file.toAbsolutePath());
}
try {
    tokenHashes = parseFile(file, logger);
} catch (IOException e) {
    throw new IllegalStateException("Failed to load service_tokens file [" + file + "]", e);
}