You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

K8s容器内Java程序偶发无法向/tmp写入Snappy库文件报错排查

问题根因

这个偶发FileNotFoundException是两个问题叠加触发的:

  • 你的K8s配置把容器内/tmp、/var/tmp都挂载到了宿主机/opt/tmp的hostPath路径。绝大多数服务器都会配置定时清理规则(systemd-tmpfiles、tmpwatch或自定义运维脚本),定期删除临时目录下长期未访问的文件,部分激进的清理规则甚至会直接删除空的临时目录。hostPath的DirectoryOrCreate规则仅在Pod启动挂载阶段检查并创建目录,运行过程中如果宿主机侧删掉了/opt/tmp目录,容器内的/tmp挂载点会直接失效,此时创建文件就会抛出No such file or directory错误。
    而Snappy的so库解压是懒触发的:不是JVM启动时就加载,是第一次调用Snappy压缩逻辑(也就是堆栈里第一次new SnappyOutputStream写Kafka消息)时才会执行静态块,把so文件从jar包里拷到临时目录。如果首次触发Snappy加载的时间点刚好撞上宿主机清理任务的执行窗口,就会触发异常。
  • 你依赖的snappy-java 1.1.7版本存在已知并发加载缺陷:如果多线程同时首次触发Snappy类初始化,会出现临时文件操作竞争,小概率出现一个线程删掉另一个线程正在操作的临时文件的情况,也会抛出同类异常。
  • 额外配置隐患:start.sh里的JVM参数有笔误,-XX:HeapDumpPath=${LOG_DIR}/ \= 末尾多了冗余的\=,可能引发JVM参数解析异常,虽然不是本次问题的直接诱因,但建议一并修复。
修复方案

按优先级从高到低操作即可彻底解决:

  • 优先替换临时目录的卷类型,不要用hostPath挂载容器/tmp目录,改用K8s原生的emptyDir卷,生命周期和Pod完全绑定,不会被宿主机侧的清理任务影响,配置片段如下:
volumes:
  - hostPath:
      path: /opt/log/stash
      type: DirectoryOrCreate
    name: log-volume
  - emptyDir: {}
    name: tmp-volume
  • 如果因为特殊原因必须用hostPath挂载临时目录,做两个调整:
    1. 协调集群运维调整宿主机清理规则,不要自动删除/清空/opt/tmp目录
    2. 修改start.sh,在启动Java进程前强制创建临时目录、设置正确权限,同时修复参数笔误,显式指定JVM临时目录路径:
#!/bin/bash
# 提前创建临时目录并设置粘滞位,避免目录不存在
mkdir -p /tmp /var/tmp
chmod 1777 /tmp /var/tmp

exec java ${JAVA_OPTS} \
   ${JVM_OPTS} \
   -XX:+ExitOnOutOfMemoryError \
   -XX:+HeapDumpOnOutOfMemoryError \
   -XX:HeapDumpPath=${LOG_DIR}/ \
   -XX:ErrorFile=log.err \
   -Djava.io.tmpdir=/tmp \
   -jar ${WAR} 1>/dev/null 2>>log.err
  • 升级snappy-java版本到1.1.8.4及以上,新版本修复了并发加载时的临时文件竞争bug,还支持通过JVM参数-Dorg.xerial.snappy.tempdir=/opt/snappy-lib自定义so文件的释放目录,你可以指定一个不会被清理的专用路径存放so文件,彻底避开/tmp目录的干扰。
  • 可选优化:在启动脚本中增加一段简单的Java逻辑,在服务启动前主动触发一次Snappy类加载,让so文件解压动作在Pod启动阶段完成,不要等业务流量进来才懒加载,进一步降低异常触发概率。

内容的提问来源于stack exchange,提问作者pain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 03:03:22