ORA-00020 根本原因是 Oracle 实例 process 限额被耗尽,需联合 v$process 与 v$session 按 machine 和 program 分组统计,结合服务注册中心定位异常节点;HikariCP 的 maximumPoolSize 仅控制单节点池大小,实际占用取决于节点数×单节点连接数,且须检查 JDBC 隐式缓存、连接泄漏及 OS 层 ulimit 限制,调大 processes 后需同步调整 sessions 并重启数据库。
Oracle报 ORA-00020: maximum number of processes exceeded 怎么快速定位是哪个应用节点撑爆的
直接查 v$process 和 v$session 联合过滤,别只盯着 v$resource_limit 看上限——它只反映历史峰值,不反映当前谁在占坑。
重点看 program 和 machine 字段,微服务里通常 program 是统一的 jdbc 驱动名(如 jdbc thin client),但 machine 会暴露真实宿主机或 pod ip。配合你自己的服务注册中心(比如 nacos/eureka)反查 ip 对应的服务名和实例 id。
- 执行
SELECT machine, program, COUNT(*) FROM v$process p JOIN v$session s ON p.addr = s.paddr GROUP BY machine, program ORDER BY COUNT(*) DESC; - 如果用的是 Kubernetes,
machine常是容器内 hostname,需提前在启动脚本里把hostname设为$(POD_NAME).$(NAMESPACE)或写入client_info(用DBMS_APPLICATION_INFO.SET_CLIENT_INFO) - 注意:连接未正确 close 的“幽灵连接”可能显示
STATUS = INACTIVE但LOGON_TIME很老,这类要结合LAST_CALL_ET判断是否真空闲
Spring Boot + HikariCP 下改 maximumPoolSize 为什么没让 Oracle 连接数降下来
HikariCP 的 maximumPoolSize 控制的是本地连接池大小,但 Oracle 的 processes 是实例级硬限,每个 TCP 连接进来都会消耗一个 process slot——哪怕连接池里只开 5 个连接,如果 10 个微服务节点各连一次,就占掉 10 个 process。
- 真正起作用的是每个节点的连接池配置 × 节点数量,不是单个节点的池大小
- 确认是否启用了连接复用:检查 Oracle JDBC URL 是否带
oracle.jdbc.useImplicitCaching=true,否则即使 HikariCP 回收了连接,底层 socket 仍可能被驱动缓存并维持 process 占用 - 检查
spring.datasource.hikari.leak-detection-threshold是否开启,避免连接泄露长期霸占 process - Oracle 12c+ 可启用
SHARED_SERVER模式(即 MTS),但微服务场景下一般不推荐——共享服务器对短连接友好,但会增加调度开销,且部分 JDBC 功能受限
调整 Oracle processes 参数后重启库,应用侧还要做什么
光调大 processes 是治标。Oracle 实际能创建的进程还受操作系统限制:kernel.sem(信号量)、ulimit -u(用户最大进程数)、/proc/sys/kernel/pid_max。尤其在容器中,这些值常被默认压得很低。
- 检查宿主机
ulimit -u,确保大于 Oracle 的processes值;K8s 中需在securityContext里显式设置runAsUser和ulimits - Docker 启动时加
--ulimit nofile=65536:65536 --ulimit nproc=65536:65536,否则 Oracle 启动可能失败或静默降级 - 改完
processes后,记得同步调大sessions(建议sessions = 1.1 * processes),否则登录时可能报ORA-00018: maximum number of sessions exceeded - 不要只改
spfile就完事,用ALTER SYSTEM SET processes=500 SCOPE=SPFILE;后必须重启 DB,SCOPE=BOTH不生效
怎么用连接数画像替代“拍脑袋设 MaxActive”
靠经验设 maximumPoolSize 容易要么浪费资源,要么突发流量直接打穿。应该基于真实负载建模:统计单位时间、单位接口的平均连接持有时长 × QPS,再叠加缓冲系数。
- 用 Prometheus + Micrometer 抓取 HikariCP 的
hikaricp_connections_active和hikaricp_connections_idle指标,按服务维度聚合 - 观察高峰期 95 分位连接活跃时长(比如
SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY last_call_et) FROM v$session WHERE status = 'ACTIVE';) - 公式:目标池大小 ≈ (QPS × 平均持有毫秒数 / 1000)× 1.5;例如 200 QPS × 300ms = 60,再 ×1.5 → 设 90 比较稳妥
- 上线后持续监控
v$resource_limit中processes的CURRENT_UTILIZATION,超过 70% 就该触发告警,而不是等报错
实际最难的不是算数字,是说服团队接受“连接池不是越大越好”——高并发下过大的池会加剧 Oracle latch 竞争,反而降低吞吐。这点在 OLTP 类微服务里特别明显。

















