DISPATCHERS需显式配置,推荐'DISPATCHERS=(PROTOCOL=TCP)(DISPATCHERS=4)(CONNECTIONS=500)(SESSIONS=1000)',避免盲目增加数量,注意内存开销与协议隔离,并结合V$视图验证实际负载。
Shared Server模式下 DISPATCHERS 参数怎么设才不踩坑
oracle shared server 连接池是否稳定,dispatchers 是第一道关。它不是“开个数就行”,而是要和实际并发连接类型、网络延迟、客户端行为强绑定。
常见错误现象:ORA-12520: TNS:listener could not find available handler for requested type of server,或大量会话卡在 WAITING ON DISPATCHER 状态——本质是 dispatcher 实例没撑住请求洪峰,或配置了却没真正启用。
-
DISPATCHERS必须在init.ora或 SPFILE 中显式配置,仅靠SHARED_SERVERS不会自动拉起 dispatcher - 推荐写法:
DISPATCHERS='(PROTOCOL=TCP)(DISPATCHERS=4)(CONNECTIONS=500)(SESSIONS=1000)',其中CONNECTIONS指单个 dispatcher 最大 TCP 连接数(非会话数),SESSIONS是该 dispatcher 能服务的总会话上限 - 不要盲目堆数量:每个 dispatcher 进程吃约 2–4MB 内存;超过 8 个 dispatcher 在多数 OLTP 场景反而因上下文切换增加延迟
- 若使用 SSL,必须单独配
(PROTOCOL=TCPS)的 dispatcher,TCP 和 TCPS 不共用同一组进程
SHARED_SERVERS 和 MAX_SHARED_SERVERS 到底谁管扩容
SHARED_SERVERS 是启动时创建的共享服务器进程数,MAX_SHARED_SERVERS 是它能动态增长的天花板——但这个“动态”是有条件的。
典型误判:把 MAX_SHARED_SERVERS 设得极高(比如 200),以为就能扛住突发流量。结果发现新进程根本没起来,V$SHARED_SERVER 里长期只有初始那几个。
- 触发扩容的前提是:当前所有 shared server 都处于
WAIT或BUSY状态,且等待队列长度持续超过SHARED_SERVER_IDLE_TIME(默认 60 秒) -
SHARED_SERVER_IDLE_TIME太小(如设成 10)会导致进程频繁启停,加大 latch 争用;太大(如 300)则突发流量来临时响应滞后 - 生产环境建议:初始
SHARED_SERVERS设为峰值并发会话数的 15%~25%,MAX_SHARED_SERVERS设为 1.5 倍初始值,留出弹性但不过度预留
如何验证 dispatcher 和 shared server 真正在干活
光看参数没用,得进数据库查实时状态。很多问题不是配错了,而是没确认它是否按预期运行。
错误验证方式:只查 V$DISPATCHER 看 STATUS = 'READY' 就认为 OK——其实可能所有 dispatcher 都在空转,而请求全压在少数几个 shared server 上。
Content at Scale
SEO长内容自动化创作平台
下载
- 关键视图组合:
V$DISPATCHER(看当前 dispatcher 数量和状态)、V$SHARED_SERVER(看每个 shared server 的BUSY/IDLE时间比)、V$QUEUE(看 dispatcher 请求队列长度,重点关注WAIT列) - 如果
V$QUEUE中某 dispatcher 的WAIT值持续 > 5,说明它已成瓶颈,需增加该 protocol 的 dispatcher 数量 - 用
SELECT NAME, BUSY/(BUSY+IDLE) AS BUSY_RATE FROM V$SHARED_SERVER;查忙闲比,长期 > 0.8 表示 shared server 不够,但也要排除是不是 SQL 执行太久拖慢了轮转
Shared Server 下 CLIENT_IDENTIFIER 为什么总为空
这是 Shared Server 最隐蔽的坑之一:应用层设置的 CLIENT_IDENTIFIER 在连接池复用后经常丢失,导致审计、监控、绑定变量跟踪全部失效。
根本原因:shared server 进程被多个会话复用,而 CLIENT_IDENTIFIER 是 session 级属性,不是 process 级。如果应用没在每次请求开始时重设,后续请求就沿用上一个会话的值,甚至为空。
- Java 应用必须在获取连接后立即执行
conn.prepareStatement("DBMS_SESSION.SET_IDENTIFIER(?)").execute(),不能只在连接初始化时设一次 - OCI 程序需调用
OCISessionBegin后立刻用OCIAttrSet设置OCI_ATTR_CLIENT_IDENTIFIER - Oracle Wallet 或连接字符串里加
CLIENT_IDENTIFIER=xxx无效——这个参数只对 dedicated connection 生效,shared server 下会被忽略
复杂点在于:这个问题不会报错,也不会影响功能,但会让基于 client identifier 的所有治理能力形同虚设。排查时容易绕远路去查监听器或网络,其实根源就在应用每次请求的初始化逻辑里漏了一行 set。