Scala Play+Akka服务报Too many open files崩溃求排查方案
排查与解决思路
一、先确认文件句柄限制是否真的生效
调了ulimit但容器进程未必能拿到,得实打实验证:
- 进入运行中的容器,执行
ulimit -n查看当前API进程的文件句柄上限,别只盯着宿主机的配置 - 检查容器启动参数,比如Docker要加
--ulimit nofile=1000000:1000000,K8s得在Pod的securityContext里配置对应文件句柄限制 - 查看JVM启动参数,有没有设置
-XX:MaxFileDescriptorCount,这个参数会直接覆盖系统ulimit值,得确保和你设置的上限匹配
二、定位到底是啥占了文件句柄
光知道句柄不够用没用,得找出元凶:
- 拿到API进程ID,执行
lsof -p <进程ID>列出所有打开的句柄,再分类统计:- 统计TCP连接数:
lsof -p <PID> | grep TCP | wc -l - 统计普通文件数:
lsof -p <PID> | grep REG | wc -l
- 统计TCP连接数:
- 重点查TIME_WAIT状态的连接,执行
ss -s或netstat -tan | grep TIME_WAIT | wc -l,这类连接大量堆积会吃掉大量句柄
三、检查Akka/Play的连接配置
Play基于Akka HTTP,默认配置可能扛不住生产流量:
- 打开
application.conf,核对这些参数:akka.http.server.idle-timeout:建议设为30-60秒,过长会堆积闲置连接,过短会频繁断开重建akka.http.server.max-connections:设置合理的最大连接数,避免无限制接收新连接导致句柄耗尽akka.http.host-connection-pool.max-open-requests:如果API有对外调用,这个参数控制客户端连接池的最大请求数,防止溢出
- 检查Akka IO的TCP配置:
akka.io.tcp.maximum-open-files,确保和ulimit值一致 - 排查资源泄漏:比如数据库连接池是否配置超时回收、文件流有没有手动关闭、WebSocket连接是否在客户端离线后正常释放句柄
四、模拟生产流量复现问题
本地复现不了就造流量:
- 用Gatling或JMeter压测,模拟高并发短连接、长连接混合的场景,尽量贴近生产流量模式
- 模拟异常场景:比如客户端突然断连、请求超时,看服务端会不会泄漏句柄
- 压测时实时监控句柄数:
watch -n 1 lsof -p <PID> | wc -l,观察句柄数是否持续上涨不回落
五、系统层面的TCP参数优化
就算ulimit够,TCP本身的参数也可能导致连接堆积:
- 调整TIME_WAIT回收参数:
net.ipv4.tcp_tw_reuse = 1:允许重用处于TIME_WAIT状态的连接net.ipv4.tcp_tw_recycle = 1:快速回收TIME_WAIT连接(注意NAT环境下慎用,可能导致连接异常)net.ipv4.tcp_fin_timeout = 30:缩短FIN_WAIT2的超时时间,加快连接释放
- 调大监听队列:
net.core.somaxconn = 65535,避免连接队列溢出导致无法接收新连接
内容的提问来源于stack exchange,提问作者Igor Molchanov
相关产品推荐
相关产品推荐

