遇到Oracle共享服务器连接失败,别急着重启数据库,先按顺序检查监听器状态、dispatchers进程和会话占用,多数情况下几分钟就能定位问题。
共享服务器模式(Shared Server)和老式的专用服务器(Dedicated Server)不一样,它靠的是调度进程(Dispatcher)来分发负载,连接一旦失败,往往不是数据库本身宕了,而是某个环节堵住了,下面按排查顺序,从现象到根因,一步步拆解。
oracle共享服务器连接失败的症状与初步判断
先看报错,不同错误码对应的处理方向完全不同。
ORA-12520:TNS监听器无法为请求的服务器类型找到可用的处理程序,这是共享服务器最典型的故障,意思是监听器活着,但所有dispatcher都忙不过来,或者压根没配dispatcher。
ORA-12535:TNS连接超时,客户端连上了监听器,但等不到dispatcher响应,基本可以锁定是dispatcher进程异常或共享服务器配额耗尽。
ORA-00020:超出进程数限制,这是数据库层面的进程上限被顶穿了,不只是共享服务器的问题,但共享服务器模式下更容易触发。
ORA-12560:TNS协议适配器错误,在Windows下很常见,往往是Oracle服务没起来,或者客户端位数与服务端不一致。
行业共识认为,超过七成的共享服务器连接失败都指向同一个根源:dispatchers初始化参数设置不合理,不是配少了就是配多了,配少了扛不住并发,配多了白占内存。
第一步动作很简单,查监听状态:
lsnrctl status
重点看输出里的“Handler”部分,如果显示DISPATCHER行数少于预期的并发连接数,或者压根没有DISPATCHER条目,问题就找到了,正常情况下列表里应该同时有DEDICATED和DISPATCHER两种条目。
检查dispatchers是否在运行
登录数据库执行:
show parameter dispatchers;
show parameter shared_servers;
show parameter max_dispatchers;
如果dispatchers返回空值,说明实例压根没启用共享服务器,应用却用共享服务器方式去连,必然报ORA-12520。
如果shared_servers返回0,即使有dispatcher也没用,共享服务器进程池是空的,请求进来没人接单。
确认会话是否被阻塞
执行以下SQL,看有没有大量会话卡在WAITING状态:
SELECT program, status, wait_class, seconds_in_wait
FROM v$session
WHERE username IS NOT NULL
ORDER BY seconds_in_wait DESC;
如果发现大量SNAPPED或INACTIVE会话堆积,且等待事件集中在dispatcher timer或virtual circuit,基本可以判定是共享服务器连接数打满,新连接进不来。
oracle共享服务器连接数满怎么解决
这属于高频事故场景,连接数满不一定是真的并发高,很多时候是慢SQL把共享服务器进程拖死了,共享服务器进程复用代价极高,一条烂查询能让几十个会话排队等同一个进程。
先看当前共享服务器使用率:
SELECT name, value
FROM v$sysstat
WHERE name IN ('workarea executions - optimal', 'workarea executions - onepass');
加上:
SELECT COUNT() FROM v$shared_server WHERE status = 'BUSY';
BUSY数量接近shared_servers上限,说明确实满了。
扩容共享服务器进程池
动态调整,不需要重启数据库:
ALTER SYSTEM SET shared_servers = 50 SCOPE=BOTH;
ALTER SYSTEM SET max_shared_servers = 100 SCOPE=BOTH;
ALTER SYSTEM SET dispatchers = '(PROTOCOL=TCP)(DISPATCHERS=4)(SERVICE=ORCLPDB1)' SCOPE=BOTH;
注意SERVICE名一定要和你连接的库服务名一致,否则dispatcher注册不到监听器上,等于白配。
调整完成后立刻验证:
lsnrctl services
这一步会列出每个服务的所有handler,看新增的DISPATCHER行数是否叠加上了。
杀掉僵尸会话释放进程
有些会话挂死但没断开,占用着共享服务器进程不释放,查出来一秒处理:
SELECT 'ALTER SYSTEM KILL SESSION ''' || sid || ',' || serial# || ''' IMMEDIATE;'
FROM v$session
WHERE status = 'INACTIVE'
AND last_call_et > 3600
AND type = 'USER';
这条SQL会生成一批KILL命令,复制出来执行即可,批量清理时用IMMEDIATE关键字,强制回滚并释放,别用默认的延迟方式,否则会话不一定真断。
调整processes参数上限
如果发现v$process里进程数接近processes参数值,需要扩容:
SHOW parameter processes;
ALTER SYSTEM SET processes = 500 SCOPE=SPFILE;
这个参数必须重启数据库才生效,属于静态参数,改之前先确认服务器内存够用,一个Oracle后台进程平均占用10-20MB内存,500个进程就是5-10GB内存开销,心里得有数。
检查listener.ora配置是否指向正确的服务名
常见的配置错误是监听器配置文件里没有把共享服务器专用的SERVICE_NAME写进去,打开$ORACLE_HOME/network/admin/listener.ora,确认以下内容:
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(GLOBAL_DBNAME = ORCLPDB1)
(ORACLE_HOME = /u01/app/oracle/product/19c/dbhome_1)
(SID_NAME = ORCL)
)
)
GLOBAL_DBNAME要和数据库服务名精确匹配,大小写敏感,改完配置文件后重载监听器:
lsnrctl reload
用lsnrctl services再验证一次,看到DISPATCHER行就说明注册成功了。
windows下oracle共享服务器配置与验证
Windows环境下的坑比Linux多,主要出在服务权限和防火墙两层。
Windows下的Oracle服务默认以LOCAL SYSTEM账户运行,如果监听器端口1521被防火墙拦截,或者Oracle服务没启动,客户端连的时候表现就是时通时断。
配置步骤回顾
打开SQLPlus:
sqlplus / as sysdba
ALTER SYSTEM SET dispatchers='(PROTOCOL=TCP)(DISPATCHERS=3)(SERVICE=ORCL)' SCOPE=BOTH;
ALTER SYSTEM SET shared_servers=20 SCOPE=BOTH;
ALTER SYSTEM SET max_shared_servers=40 SCOPE=BOTH;
然后重启监听器:
lsnrctl stop
lsnrctl start
不要只reload,Windows下监听器有时hold住旧配置,必须彻底重启。
确认共享连接生效
lsnrctl services
lsnrctl status
执行完这两个命令后,看输出是否符合预期,再用客户端从另一台机器测试:
sqlplus user/password@host:1521/ORCL
连接成功后,用绿灯场景确认走的是共享服务器路径:
SELECT server FROM v$session WHERE sid = (SELECT sid FROM v$mystat WHERE rownum = 1);
返回SHARED表示成功,返回DEDICATED说明又绕回专用服务器了。
Windows防火墙排查
Windows Server默认防火墙规律性拦截入站连接,共享服务器模式下dispatcher的端口范围不固定,很难精确放行,最省事的方法:
- 控制面板 → Windows防火墙 → 高级设置 → 入站规则
- 新建规则 → 端口 → TCP → 特定本地端口:1521
- 选择允许连接 → 应用到所有配置文件
- 名称填Oracle Listener
如果用了多listener或多dispatcher端口范围,直接放行Oracle安装目录的所有exe更省心,包括tnslsnr.exe和oracle.exe。
oracle共享服务器和专用服务器的选型建议
不是所有场景都适合共享服务器,搞错架构选型,后面的问题层出不穷。
| 维度 | 共享服务器 | 专用服务器 |
|---|---|---|
| 适用并发量 | 高并发、低活跃度 | 低并发、高活跃度 |
| 内存占用 | 低,进程复用 | 高,每连接一个进程 |
| 适用场景 | OLTP、Web应用 | 数据仓库、批处理 |
| 调优难度 | 高 | 低 |
| 故障影响面 | 单点故障影响所有会话 | 单点故障只影响单个会话 |
共享服务器适合大量短连接、空闲时间长的场景,比如Web应用连接池,每个连接大部分时间在等用户操作,共享几个进程足够。
专用服务器适合跑重SQL、长事务的场景,比如报表生成、大数据量批量处理,这类操作CPU密集,共享进程一旦被占住,其他会话就得排队,性能反而更差。
现实环境里多数情况是两种模式混用默认走共享服务器,某些特定应用通过SERVICE_NAME指定专用连接,Oracle在Service层面就能区分,不用改代码。
配置方式是在tnsnames.ora里给专用连接单独配一段:
ORCL_DEDICATED =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = yourhost)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = ORCL)
)
)
共享连接的tnsnames.ora则不带SERVER = DEDICATED,或者写SERVER = SHARED。
客户端通过环境变量或连接串来控制走共享还是专用,这给了DBA很大的调优空间,不至于非黑即白。
不同场景下的配置建议
小型Web应用(并发50以内)
- shared_servers:5-10
- dispatchers:2-3
- 可以不需要max_shared_servers,默认自动扩展
中型OLTP系统(并发200-500)
- shared_servers:50-100
- dispatchers:5-10
- max_dispatchers:20
- 同时监控
v$dispatcher里的busy比例,超过60%就加数
高并发接入(并发1000以上)
- 这个量级建议上连接池中间件,比如Proxysql或Oracle官方连接池
- 数据库层面shared_servers设定值反而不要太高,避免进程切换开销大于收益
- 业内专家指出,3000以上并发时,共享服务器的性能优势会逐渐消退,物理进程切换的代价开始大于复用收益
Oracle共享服务器故障排查常用SQL速查表
这部分是实操集锦,把前面说的命令汇总成一张速查表,遇到问题直接复制执行。
| 故障类型 | 排查SQL或命令 | 预期结果 |
|---|---|---|
| 监听无响应 | lsnrctl status | 显示READY状态 |
| dispatcher未注册 | lsnrctl services | 输出包含DISPATCHER行 |
| 连接数打满 | SELECT COUNT() FROM v$shared_server WHERE status=’BUSY’ | 数值远小于shared_servers |
| 会话堆积 | SELECT FROM v$session WHERE wait_class=’Idle’ | 无大量异常等待 |
| 进程数超限 | SHOW parameter processes | 当前进程数留有20%余量 |
| 共享连接未生效 | SELECT server FROM v$session WHERE sid=SYS_CONTEXT(‘USERENV’,’SID’) | 返回SHARED |
最后一条SQL里的SYS_CONTEXT('USERENV','SID')替代了传统的查sid方式,在Oracle 12c及以上版本更直观。
常见坑点补充
坑一:连接池配置里的最小连接数大于共享服务器上限。 很多Java应用配置了连接池min=10,而共享服务器shares才5,等于连接池初始化时就预留了一半失败概率。
坑二:服务名不匹配。 应用连接串里的SERVICE_NAME没写对,Oracle把请求路由到了DEDICATED模式而不是共享模式,监听器忙了半天白忙活。
坑三:并发测试工具和实际负载差距大。 压测出来的“性能不行”未必是共享服务器的锅,很多压测工具直接绕过连接池,瞬间建几百条物理连接,再好的配置也扛不住。
坑四:调大dispatchers参数后忘了重启监听器。 ALTER SYSTEM改完参数只是改了内存和spfile,监听器还是旧配置,必须lsnrctl reload或者lsnrctl stop/start才能把新dispatcher信息注册上去。
坑五:共享服务器模式下跑了批处理大事务。 批处理占住共享进程不放,其他OLTP会话全部排队,表现为系统瞬间卡死,这种情况要把批处理账号通过服务名强制走DEDICATED连接,和OLTP流量彻底隔离。
Oracle共享服务器连接失败常见问题和解答
修改dispatchers参数后连接立刻恢复吗?
不一定,修改参数本身是动态生效的,但监听器需要重新加载配置才能注册新的dispatcher进程,执行完ALTER SYSTEM后,务必跟随执行lsnrctl reload或lsnrctl stop/start,然后确认lsnrctl services里出现了对应数量的DISPATCHER条目,连接才能恢复。
为什么共享服务器模式下执行复杂查询特别慢?
共享服务器的进程调度有额外开销,CPU密集型查询会让单个共享进程长时间保持忙碌状态,其他会话只能等待,这类查询适合改走专用连接,或者把共享服务器参数值适量调小,减少进程间切换的额外成本,多数情况下,共享服务器模式更适合短平快的OLTP操作而不是重型查询。
如何确认客户端的连接确实走了共享服务器而不是专用服务器?
执行以下SQL,查看返回结果:
SELECT server, status FROM v$session WHERE sid = SYS_CONTEXT('USERENV', 'SID');
返回SHARED表示连接走的是共享服务器模式,返回DEDICATED表示走的是专用模式,同时可以用lsnrctl services查看服务端注册了多少个DISPATCHER和DEDICATED处理程序,对比客户端实际建立的会话类型,就能定位连接是否走错了通道。
连接失败的根源往往不在数据库本身,而在于配置与业务模型不匹配。先把连接模式搞清楚,再判断是容量问题还是配置偏差问题,调整方向对了,问题自然就解决了。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/797616.html


