mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2025-12-16 20:33:03 +00:00
4.4 KiB
4.4 KiB
⚠️ Nashorn引擎限制说明
问题描述
Nashorn JavaScript引擎(Java 8-14自带)无法中断正在执行的JavaScript代码。
这是Nashorn引擎的一个已知限制,无法通过编程方式解决。
具体表现
症状
当JavaScript代码包含无限循环时:
while(true) {
var x = 1 + 1;
}
会出现以下情况:
- ✅ 30秒后客户端收到超时错误
- ❌ Worker线程继续执行无限循环
- ❌ 线程被永久阻塞,无法释放
- ❌ 日志持续输出线程阻塞警告
日志示例
WARN -> [-thread-checker] i.vertx.core.impl.BlockedThreadChecker:
Thread Thread[playground-executor-1,5,main] has been blocked for 60249 ms, time limit is 60000 ms
为什么无法中断?
尝试过的方案
- ❌
Thread.interrupt()- Nashorn不响应中断信号 - ❌
Future.cancel(true)- 无法强制停止Nashorn - ❌
ExecutorService.shutdownNow()- 只能停止整个线程池 - ❌
ScriptContext.setErrorWriter()- 无法注入中断逻辑 - ❌ 自定义ClassFilter - 无法过滤语言关键字
根本原因
- Nashorn使用JVM字节码执行JavaScript
- 无限循环被编译成JVM字节码级别的跳转
- 没有安全点(Safepoint)可以插入中断检查
while(true)不会调用任何Java方法,完全在JVM栈内执行
现有防护措施
1. ✅ 客户端超时(已实现)
executionFuture.toCompletionStage()
.toCompletableFuture()
.orTimeout(30, TimeUnit.SECONDS)
- 30秒后返回错误给用户
- 用户知道脚本超时
- 但线程仍被阻塞
2. ✅ 前端危险代码检测(已实现)
// 检测无限循环模式
/while\s*\(\s*true\s*\)/gi
/for\s*\(\s*;\s*;\s*\)/gi
- 执行前警告用户
- 需要用户确认
- 依赖用户自觉
3. ✅ Worker线程池隔离
- 使用独立的
playground-executor线程池 - 最多16个线程
- 不影响主服务的事件循环
4. ✅ 代码长度限制
- 最大128KB代码
- 减少内存消耗
- 但无法防止无限循环
影响范围
最坏情况
- 16个恶意请求可以耗尽所有Worker线程
- 后续所有Playground请求会等待
- 主服务不受影响(独立线程池)
- 需要重启服务才能恢复
实际影响
- 取决于使用场景
- 如果是公开服务,有被滥用风险
- 如果是内部工具,风险较低
解决方案
短期方案(已实施)
- ✅ 前端检测和警告
- ✅ 超时返回错误
- ✅ 文档说明限制
- ⚠️ 监控线程阻塞告警
- ⚠️ 限流(已有RateLimiter)
中期方案(建议)
- 添加IP黑名单机制
- 添加滥用检测(同一IP多次触发超时)
- 考虑添加验证码
- 定期重启被阻塞的线程池
长期方案(需大量工作)
-
迁移到GraalVM JavaScript引擎
- 支持CPU时间限制
- 可以强制中断
- 更好的性能
- 但需要额外依赖
-
使用独立进程执行
- 完全隔离
- 可以强制杀死进程
- 但复杂度高
-
代码静态分析
- 分析AST检测循环
- 注入超时检查代码
- 但可能被绕过
运维建议
监控指标
# 监控线程阻塞告警
tail -f logs/*/run.log | grep "Thread blocked"
# 监控超时频率
tail -f logs/*/run.log | grep "JavaScript执行超时"
告警阈值
- 单个IP 1小时内超时 >3次 → 警告
- Worker线程阻塞 >80% → 严重
- 持续阻塞 >5分钟 → 考虑重启
应急方案
# 重启服务释放被阻塞的线程
./bin/stop.sh
./bin/run.sh
用户建议
✅ 建议的代码模式
// 使用有限循环
for(var i = 0; i < 1000; i++) {
// 处理逻辑
}
// 使用超时保护
var maxIterations = 10000;
var count = 0;
while(condition && count++ < maxIterations) {
// 处理逻辑
}
❌ 禁止的代码模式
// 无限循环
while(true) { }
for(;;) { }
// 无退出条件的循环
while(someCondition) {
// someCondition永远为true
}
// 递归炸弹
function boom() { return boom(); }
相关链接
最后更新: 2025-11-29
状态: ⚠️ 已知限制,已采取缓解措施
建议: 如需更严格的控制,考虑迁移到GraalVM JavaScript引擎