文章
Oracle + PHP 简明手册 |
通过持久连接提高性能作者:John Coggeshall 持久数据连接的概念对许多 PHP 开发人员来说很陌生。那到底什么时候才应当使用它们呢?
2006 年 2 月发表 多年来我一直担任专门研究 PHP 的技术顾问,在此期间经常有人问我持久数据库连接的适当性,到底问过多少次我已经记不清了。总之,很多最流行的 PHP 数据库扩展都能够建立这样的连接。 要真正了解这个问题的答案,您需要了解 PHP 脚本执行的生命周期以及 Web 服务器对该生命周期的影响 - 而这正是本文的切入点。 Apache 和 PHP 服务器如何发出请求最常见的 PHP 设置是 PHP 以模块形式在 Apache Web 服务器(通常为 Apache 1.3.x,但 PHP 也可以在最新版本的 Apache 中运行,前提是您应在预分叉模式下运行更新的 Apache 2.0+ 版)中运行。PHP 必须在预分叉模式下运行这个表面上无关的事实却是了解持久数据库连接优缺点的框架。不明白我的意思?我们来看看 Apache 的工作方式吧。 当诸如 Web 浏览器这样的客户端连接到由 Apache 提供服务的网站时,将分派一个进程来处理该请求。在 Apache 1.3.x 中,这些进程(称作“子”进程)是相互独立的。也就是说,与基于线程的模型不同,每个进程在服务器中都有一个完全独立的内存和执行空间。由于该方法使整个服务器非常稳定(如果特殊请求导致 Apache 崩溃,那么将很有可能只导致处理该请求的特殊单个子进程崩溃),因此长期以来一直被视为有益于 Apache。 图 1 演示了该进程,图中的红色表示特殊 HTTP 请求导致的分段故障。
图 1 发生分段故障 尽管该体系结构显然有利于确保一个稳定的 Web 服务器环境,但每个独立 HTTP 请求的这个“沙箱”结构却具有负面影响,即与该请求有关的所有内容也必须与其他请求分隔开。由于大多数建议的 PHP 设置是将 PHP 作为模块 (mod_php) 在 Apache 中运行 实现的,因此在此预分叉模型中运行的 PHP 脚本本身也将受到相互孤立的请求的影响。因此,PHP 中的所有可用变量和资源将在单个 Apache 子进程的环境中分配和销毁 - 而这正是持久 Oracle 连接的用途所在。 由于所有 PHP 资源都在单个 Apache 子进程的环境中定义,因此当 PHP 与 Oracle 数据库建立数据库连接时,该连接将只位于该特定子进程中。因此,当执行为多个不同客户端同时建立数据库连接的同一 PHP 脚本时,每个子进程必须建立各自的连接。(参见图 2。)
图 2 跨多个客户端的并发数据库连接 如果每个子进程执行同一 PHP 脚本,那么您可以想象预分叉 Apache 模型将导致 PHP 以及 Oracle 效率很低,这是因为从理论上而言,所有四个子进程只需要一个数据库连接。此外,即使使用 Oracle API 为 PHP 提供的标准连接方法建立四个单独的数据库连接,将仍针对每个请求中断并重新建立此连接。即使每个子进程必须拥有自己的连接,在大多数情况下为每个请求重新建立连接也显得非常没有必要 - 因此,PHP 尝试通过持久数据库连接这个概念来解决此问题。遗憾的是,该方法只能解决部分问题 - 尽管持久连接会防止针对每个请求中断连接,但在请求之间持久保存的 PHP 资源仍然只存在于单个子进程中。 (提示:如果您很想知道可能建立的 Oracle 数据库连接总数,则查看 Apache Web 服务器中的 MaxClients 配置指令。假设 PHP 脚本针对每个请求创建 X 个数据库连接,那么 Oracle 将准备在高峰负载情况下接受 MaxClients * X 个数据库连接。) 阻止 Apache 中断数据库连接了解了 PHP、Apache 和 Oracle 如何交互后,您现在可以充分利用每个数据库连接了,在针对每个请求处理数据库时建立一个数据库连接通常是最昂贵的操作。 乍看来,除了在单个子进程中持久保存连接以外,提高性能的方法似乎并不多。但这样的假设是错误的 - 诀窍不在于优化 PHP,而是在于优化服务器体系结构本身。 除非您正在运行只处理 RPC 请求的某种远程过程调用 (RPC) 服务器,否则除了提供支持 PHP 的页面(利用数据库连接)以外,Apache 服务器还很可能在执行其他操作。实际上,几乎可以确定的是,对于每个“页面”的请求(从浏览器中加载 index.php 网页),浏览器可能向 Web 服务器发出 10、20 甚至 30 个针对图像、Flash 文件或框架中其他嵌入文档(等等)的请求。根据服务器的配置,该事实可以反映有效使用持久连接的任何好处。由于对运行 PHP 的 Web 服务器进行微调以充分利用每个数据库连接请求至关重要,因此下面我们将了解相关的 Apache 1.3.x 配置设置:KeepAlive、MaxRequestsPerChild 和 MaxSpareServers。 查明 Apache 在哪些情况下在哪里中断数据库连接现在,您已经了解了与 PHP 和持久连接相关的 Web 服务器中执行的操作,下面我们将了解如何提高性能。此处的基本目标是在 Apache 隐式关闭持久连接之前,最大限度地增加该连接的使用次数。 首先,了解一下 MaxRequestsPerChild 配置指令。这是一个处理持久连接时比较重要的指令,这是因为,顾名思义,它定义了在终止并重新启动进程之前单个 Apache 子进程可以服务的最大 HTTP 请求数。尽管理想情况下的设置为零(意味着每个子进程接受无限数量的连接),但如果 Web 服务器中运行的任何东西不稳定或发生内存泄露等情况,则必须使用该机制以使服务器保持最佳状态。因此,如果在 X 个请求之后中断子进程,则 X-1 是根据其利用持久性数据库连接的请求总数。这是您应找的第一个指令,因为它对于持久连接性能的影响最直接。 同样,MaxSpareServers 配置指令可通过终止实际上并未处理请求的非必要的 Apache 子进程“降低”在负载较低期间 Web 服务器上使用的资源数量。根据站点上遇到的负载模式类型,Apache(尽管它通常可以在一定程度上智能地管理该进程)也可能终止子进程,并进而过早地终止数据库连接。例如,对于经常遇到尖峰通信量的 Web 服务器而言,最好让更多的备用子进程运行,同时在高峰负载后长时间处于空闲状态的服务器可以终止它们来将资源释放给其他任务。 充分利用每个连接现在,我们制定了两个由 Apache 终止其子进程的主要方法以及任何您可能已经建立的持久连接,下面我们将了解优化此行为的方法。尽管并不能总是简单地中断子进程(尤其是当子进程有可能随时间泄露内存时),但正确地配置 Apache 却具有重要意义。以下是几个可提高性能的方法。
优化 OCI 扩展Zend Core for Oracle(其中包括对 PHP 的 OCI 扩展重新整理的功能)提供了一些充分利用持久连接的新管理工具。这些工具表现为一组 PHP 配置指令,可用于 php.ini 文件中。
结论您现在已经了解了充分利用每个 Oracle 数据库连接所需的所有内容以及何时使用(或不使用)持久连接。尽管本文提供的信息特定于数据库连接,但仍可以使用本文描述的技巧优化任何遵循同一模式的持久资源。 John Coggeshall [ http://www.coggeshall.org/)] 是 Zend Technologies 的高级技术顾问,他为全球范围的客户提供专业服务。他从 1997 年开始接触 PHP,并在一些业界知名的出版社(如 Sams Publishing、Apress 和 O'Reilly)出版了三部有关 PHP 的书籍以及 100 多篇文章。John 还是 PHP 内核的积极贡献者(tidy 扩展的作者)、Zend 教育顾问委员会的成员,并经常在世界范围内的与 PHP 相关的会议上发表演讲。 |