Hacktoberfest 2026: as issues que os mantenedores marcaram para outubro, abertas e boas para iniciantes. Ver issues do Hacktoberfest

[BUG] - Java-Chassis 新版本无法自动清理临时上传文件的句柄

Aberta
#4,835 4 comentários 0 reações 0 responsáveis Ver no GitHub

Ninguém assumiu esta issue ainda.

Avaliação

Dificuldade
5/5
Tempo estimado
Mais de uma semana
Facilidade para iniciantes
35/100
Tipo de issue
Bug
Clareza
Razoavelmente clara
Status de atividade
Estagnada
Stack de tecnologia
java
Domínio
api, backend

Direção de pesquisa

Comece por foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/FileUploadPart.java e revise a alteração associada à issue #4476. Reproduza o comportamento de retenção de handles no Linux com Java-Chassis 2.8.24 e, em seguida, determine e valide um design de limpeza que permaneça compatível com Java 8 e Java 21 sem interromper o processamento assíncrono de uploads.

Escrita pelo modelo de indexação a partir do texto da issue.

Descrição

bug
Steps to Reproduce
  1. 编写一个处理文件上传请求的controller.
  2. 接收到上传文件参数后, 打开文件流, 不关闭, 直接返回.
  3. 在Java-Chassis 1.x分支上可以观察到一段时间后文件句柄会被清理, 而在 Java-Chassis 2.8.24 版本, 文件句柄会一直存在, 直到进程重启才会消失.

注意:

  1. 实际测试发现此问题在Windows上不会出现(Java8), 我们是在Linux上复现的问题.
  2. 打开文件流不关闭只是为了让问题必现. 实际上即使业务代码有正常的close调用也可能遇到类似的问题, 因为业务处理文件流的逻辑可能超时, 导致 Vert.x 执行临时文件清理回调时文件流仍然处于打开的状态.
Expected Behavior

预期 Java-Chassis 2.8.24 能像 Java-Chassis 1.x 分支一样, 能够自动兜底清理文件句柄.

Servicecomb Version

2.8.24

Additional Context

根因分析

导致 Java-Chassis 1.x 和 2.8.x 差异的代码在于:

https://github.com/apache/servicecomb-java-chassis/blob/6873ee5992ff2211a1e0efa33dd30377a914ecbf/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/FileUploadPart.java#L37-L40

在更早的版本中, 它返回的是一个 FileInputStream:

https://github.com/apache/servicecomb-java-chassis/blob/f3dc998d78394fec8d6755192a57ab7ea889b859/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/FileUploadPart.java#L37-L40

而 2.8.20 版本对此做了上述修改, 实测返回的是 sun.nio.ch.ChannelInputStream 类型的流.

在 Java8 中, FileInputStream 的 finalize 方法会执行 close 方法, 而 sun.nio.ch.ChannelInputStream 的 finalize 方法是空的. 这就导致 Java-Chassis 2.8.19 及之前的版本, 即使业务代码由于各种各样的原因没有执行 close 方法, FileInputStream 也能在被GC回收时兜底关闭文件句柄, 而在升级到 Java-Chassis 2.8.20 之后就只能泄漏句柄了.

回溯 Java-Chassis 的代码修改记录可知, 这个变化是为了修复另外一个问题而引入的:
https://github.com/apache/servicecomb-java-chassis/issues/4476

解决思路

Java-Chassis 已经不适合将文件输入流的类型改回 FileInputStream 了.

除了上面说的 issue #4476 的原因, 高版本的 Java 还废弃了 finalize 方法, 即使用回 FileInputStream 也不能兜底关闭文件句柄.
为了能够同时兼容 Java8 和 Java21, 也不适合选用 Cleaner 机制(Java9才具备此特性).

目前能想到的解决办法:

  1. 基于 Java-Chassis 自身的 Invocation 生命周期管理机制来做自动清理动作.

    此方案的风险在于, 考虑到业务可能在 controller 层获取上传文件参数后, 异步调度到其他任务线程池处理, 因此在 Invocation 的结束事件发生时就直接关闭流的话可能会导致业务视角看到的Java-Chassis框架行为发生了影响业务功能的不兼容变化.

  2. 记录已打开的 InputStream, 在后台定时任务中监控其关闭状态.

    此方案可以一定程度规避方案1的风险, 但存在内存用量上升甚至泄漏的风险, 若选择这个思路, 也需要小心进行可靠性设计.

此外, 建议Java-Chassis增加对 FileUploadPart 的打开流的调用记录的监控, 便于辅助业务分析此类文件句柄泄漏问题的触发代码位置.

Linguagem predominante
Java
Estrelas
1.9k
Forks
813
Métricas de merge de PRs
Nenhum PR com merge em 30d

Preparar o ambiente

  • Sem Dockerfile nem arquivo Docker Compose
  • Tem um modelo de pull request
  • Sem guia de contribuição

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Mais de apache/servicecomb-java-chassis

Todas as issues de apache/servicecomb-java-chassis

Issues semelhantes

Mais issues de Java

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.