
第一部分:官方严谨的详细阐述
一、 核心概念与设计目标
-
专用服务器(Dedicated Server):
- 模式: 一个客户端连接对应一个专用的服务器进程(Server Process)。连接的生命周期等于会话的生命周期。
- 痛点: 对于成千上万的轻量级、短生命周期的连接(典型Web应用),创建和销毁进程的开销巨大,大量空闲进程也消耗大量内存(PGA),导致系统可扩展性差。这就是著名的“连接风暴(Connection Storm)”问题。
-
共享服务器(Shared Server - MTS):
- 设计目标: 减少操作系统进程数量,从而节省内存(主要是PGA)和进程创建开销。
- 模式: 客户端连接并不直接与服务器进程绑定。它们连接到调度进程(Dispatcher),将请求放入一个公共的请求队列。池中空闲的共享服务器进程(Shared Server Process) 从队列中取出请求并进行处理,然后将结果通过调度程序返回给客户端。
- 本质: 是连接(Network Connection) 与服务器进程(Server Process) 的解耦。一个共享服务器进程可以为多个客户端连接服务。
-
数据库驻留连接池(DRCP - Database Resident Connection Pooling):
- 设计目标: 减少数据库会话(Session)和服务器进程(Server Process)的数量,应对海量(数万级)的、短暂的、空闲的连接。
- 模式: DRCP维护一个池,里面是已经建立了的“服务器进程+数据库会话”的组合,称为池化服务器(Pooled Server)。客户端应用可以从池中“借用(Borrow)”一个池化服务器,执行操作,然后“归还(Return)”回池中供其他客户端使用。
- 本质: 是连接(Network Connection)、服务器进程(Server Process) 和数据库会话(Database Session) 三者的完全解耦和池化。
二、 DRCP的深入内部原理与工作流程
DRCP由三个核心组件构成,由一个后台进程CPnn(Connection Pool Process)管理:
-
连接代理(Connection Broker):
- 负责管理整个连接池,是客户端连接请求的入口和协调者。
- 维护着池中池化服务器的状态(空闲或忙碌)。
-
池化服务器(Pooled Server):
- 池中的“货物”。每个池化服务器都是一个 “服务器进程 + 已初始化的数据库会话” 的活跃组合。它已经完成了登录认证,初始化了会话上下文,处于“就绪”状态。
-
连接池(Pool):
- 存放空闲池化服务器的场所。
详细使用过程(Borrow-Return生命周期):
-
客户端连接(Connect):
- 客户端使用特殊的连接字符串(包含
POOLED关键字,如jdbc:oracle:thin:@host:port/service_name:POOLED)发起连接。 - 连接请求首先到达连接代理(Broker)。
- 客户端使用特殊的连接字符串(包含
-
借用(Borrow):
- 代理检查池中是否有空闲的池化服务器。
- 如果有: 代理将这个空闲的池化服务器分配给客户端。此时,客户端连接与这个池化服务器(会话)绑定。这是一个极快的操作,因为无需创建进程和登录。
- 如果没有: 代理可以启动一个新的服务器进程来创建一个新的池化服务器(受限于
MAXSIZE),或者让客户端请求等待(受限于INACTIVITY_TIMEOUT和MAX_Think_TIME)。
-
执行SQL(Execute):
- 客户端在这个“借来的”会话上执行SQL操作,就像使用专用服务器一样。
-
归还(Return):
- 客户端事务结束后(通常是断开物理连接,或在支持显式归还的驱动中调用
close()方法),池化服务器与客户端的绑定被解除。 - 关键步骤: DRCP会执行一个会话清理(Session Cleanup) 操作,包括:
- 回滚任何未提交的事务。
- 关闭当前打开的游标。
- 重置会话的某些状态(如
ALTER SESSION的修改)。
- 注意: 不会完全销毁会话。会话的大部分上下文(如包变量的状态)会被保留,但Oracle不保证这一点,因此应用不应依赖跨“借还”周期的状态。清理后,池化服务器被标记为空闲,返回连接池,等待下一个客户端。
- 客户端事务结束后(通常是断开物理连接,或在支持显式归还的驱动中调用
三、 DRCP 与 共享服务器(MTS)的根本区别
| 特性 | 数据库驻留连接池 (DRCP) | 共享服务器 (MTS) | 根本区别 |
| :— | :— | :— | :— |
| 解耦级别 | 连接、进程、会话 三者解耦 | 连接 与 进程 解耦 | DRCP的解耦更彻底,池化的是现成的会话。 |
| 内存结构 | 每个池化服务器拥有独立的PGA和UGA | 共享服务器进程使用SGA中的UGA | MTS更节省UGA内存(在SGA中),DRCP的每个会话仍有独立的PGA。 |
| 适用场景 | 海量、短命、空闲的连接
(e.g., Web PHP/Python App) | 中量、长生命期、活跃的连接
(e.g., 传统的客户端工具) | DRCP为“突发性”连接设计;MTS为“持续性”连接设计。 |
| 会话状态 | 借还周期后,会话状态被清理重置 | 会话状态在连接生命周期内持续保持 | DRCP会话是“无状态”的;MTS会话是“有状态”的。 |
| 性能特点 | 消除登录/注销和进程创建开销 | 消除进程创建开销,但仍有登录开销 | DRCP的“借用”比MTS的“连接”更快。 |
四、 争用、等待事件、排查与解决
场景: DRCP池配置不当,无法应对连接请求峰值。
1. 池化服务器不足争用
- 争用原因: 瞬时并发请求数超过池中
MINSIZE且达到MAXSIZE,新的请求必须等待有池化服务器被归还。 - 等待事件:
“wait for connection pool broker”或相关的等待。 - 具体影响: 应用程序获取数据库连接的调用(如
getConnection())延迟或超时,用户体验到延迟。 - 排查:
- 查询
V$CPOOL_STATS视图,这是诊断DRCP健康状态的核心视图。
-- 查看DRCP池的整体统计信息 SELECT pool_name, num_requests, num_hits, num_misses, num_waits, wait_time FROM v$cpool_stats;NUM_MISSES: 表示多少次请求未能在池中找到空闲服务器(需要创建或等待)。NUM_WAITS: 表示多少次请求不得不等待。WAIT_TIME: 累计等待时间。
- 查询
- 解决:
- 调整池大小: 增加
MAXSIZE(DBMS_CONNECTION_POOL.CONFIGURE_POOL)。但需权衡内存消耗。 - 调整超时: 减少
INACTIVITY_TIMEOUT(让空闲服务器更快被释放)或增加MAX_Think_TIME(减少客户端占用服务器不干活的时间)。 - 应用优化: 确保应用在使用后及时关闭连接(归还服务器)。
- 调整池大小: 增加
2. 连接代理(Broker)争用
- 争用原因: 单个连接代理可能成为数万连接请求的单一瓶颈。
- 解决: 可以配置多个连接代理。
-- 查询当前代理数量 SELECT component, status FROM dba_cpool_info; -- (通常通过参数调整,需要重启) -- 设置多个代理进程 -- ALTER SYSTEM SET max_connection_brokers = 2;
五、 常用管理SQL语句
-- 1. 启用和配置DRCP(通常需要DBA权限)
EXEC DBMS_CONNECTION_POOL.START_POOL(); -- 启动默认池
EXEC DBMS_CONNECTION_POOL.STOP_POOL();
-- 2. 配置池参数
BEGIN
DBMS_CONNECTION_POOL.CONFIGURE_POOL(
pool_name => 'SYS_DEFAULT_CONNECTION_POOL',
minsize => 10, -- 池中始终保持的最小服务器数
maxsize => 100, -- 池允许的最大服务器数
inactivity_timeout => 300, -- 空闲服务器被清理前的秒数
max_think_time => 120 -- 客户端借用后不执行操作的超时时间
);
END;
/
-- 3. 查看池的状态和统计信息(核心监控视图)
SELECT * FROM V$CPOOL_STATS; -- 池整体统计
SELECT * FROM V$CPOOL_CC_STATS; -- 连接类级别统计(11g+)
SELECT * FROM V$CPOOL_CONN_INFO; -- 当前活动连接信息
-- 4. 查看当前活跃的池化服务器会话
SELECT s.sid, s.serial#, s.username, s.program, s.server
FROM v$session s
WHERE s.server = 'POOLED'; -- 关键:SERVER列为'POOLED'
-- 5. 监控共享服务器(以作对比)
SELECT name, value FROM V$SHARED_SERVER_MONITOR;
SELECT * FROM V$DISPATCHER;
SELECT * FROM V$SHARED_SERVER;
SELECT sid, program, server FROM v$session WHERE server = 'SHARED';
第二部分:通俗易懂的解释
让我们用两个比喻来彻底理解它们的区别。
比喻一:打电话给客服中心
-
专用服务器(Dedicated): 你打电话,公司就专门为你招聘并训练一个新客服(创建服务器进程)。你挂断电话,公司就解雇他(销毁进程)。如果你和一万个人同时打电话,公司瞬间要招聘一万人,经理忙疯,办公室也挤炸了。
-
共享服务器(MTS): 你打电话,总机(调度进程)接听,把你的需求记下来(放入请求队列)。然后总机让一个现成的、多技能的客服(共享服务器进程)来处理你的需求。这个客服处理完你的需求后,马上就去处理总机分配的下一个需求。客服是共享的,但你的“通话状态”(会话)一直被保持着,直到你主动挂断。
-
数据库驻留连接池(DRCP): 公司有一批正在待命的客服,他们都已上班打卡、登录了系统、准备好了纸笔(这就是池化服务器:进程+会话)。你打电话过来,接线员(连接代理) 直接找一个空闲的待命客服接你的电话。你问完问题,立刻挂断电话。客服不会下班,他只需把你刚才的通话记录清理一下(回滚事务、重置状态),然后就回到待命区,等待接听下一个电话。客服和会话都是共享的,而且一次只服务一个人,但通话是极其短暂的。
比喻二:交通工具
- 专用服务器: 专车接送。从你家到公司,一辆车只接你一个人。舒服,但成本极高。
- 共享服务器: 公交车。有固定的路线(调度程序),你上车(连接),告诉司机去哪(请求),车把你送到。你在车上的整个旅程是一个“会话”。虽然车是共享的,但你一直占着一个座位(UGA在SGA中)。
- DRCP: 共享单车/共享汽车。你到街上(连接池)扫一辆已经停在路边、没上锁的车(借用池化服务器)。你骑到目的地(执行SQL),然后立刻锁车走人(归还)。下一个人可以接着扫这辆车。车的状态(轮胎气足不足)可能略有不同,但你每次用的都是不同的车,而且用完即还。
总结:
- 用MTS还是DRCP? 看你的应用“通话”时间长不长。
- 如果你的应用连接后,会保持连接并频繁交互一段时间(如传统客户端),MTS更合适。
- 如果你的应用是“问一句就跑”(Web请求:连接->执行一个查询->断开),DRCP是无可争议的最佳选择,它能轻松应对万级并发。
- DRCP的精髓: 它通过池化并复用“已初始化的会话”,将昂贵的、频繁的登录/注销(Logon/Logoff) 操作,几乎完全消除了。这对于PHP、Python、Ruby等无状态Web应用的扩展性来说是革命性的。
欢迎关注我的公众号《IT小Chen》
1574

被折叠的 条评论
为什么被折叠?



