![在 Apache2 上的 PHP 中对多个数据库使用 pconnect](https://linux22.com/image/624230/%E5%9C%A8%20Apache2%20%E4%B8%8A%E7%9A%84%20PHP%20%E4%B8%AD%E5%AF%B9%E5%A4%9A%E4%B8%AA%E6%95%B0%E6%8D%AE%E5%BA%93%E4%BD%BF%E7%94%A8%20pconnect.png)
我在 apache2 服务器上的 preforked(MOD_PHP) 中运行 PHP。设置是在 Linux Ubuntu 10.04 上。我使用的数据库是 firebird 数据库 2.5.2。apache2 服务器在由 8 个 Web 服务器组成的 Web 集群中运行。
有一次,我们遇到了严重的性能问题,因为应用程序的请求量激增(我们遇到高峰时段)。瓶颈在于需要大量数据库连接来处理短时间内收到的大量请求。Firebird 无法很好地应对这个问题,请求只是超时了。
这种类型的数据库没有连接池,这就是为什么我一直在 PHP 中使用 pconnect 来减轻数据库的压力。这会将数据库连接保留在 apache2 进程中。这大大提高了性能。缺点是,我们必须让 apache2 进程在轮换之前接收大量请求,并且即使没有负载,我们也会保持大量 apache2 进程运行。每个 Web 服务器都运行着 70 个 apache 进程。这是为了保持连接打开并准备就绪。基本上,我们试图将 apache2 作为我们的连接池。这很有效。当用户请求应用程序时,数据库句柄已准备就绪,Firebird 不必担心创建新数据库连接的成本。
现在我的问题来了。我们现在需要很多数据库 - 小型数据库。但它们都将在 apache2 服务器集群中运行。这意味着在 apache2 进程的生命周期中,它很可能与多个数据库(可能是 80-100 个)建立持久连接。
我担心 apache2 将如何处理这种情况。apache2 中可以处理的连接数是否有限制?它会变慢吗?它会在内存中增长并完美处理所有事情吗?
目前,数据库分片问题还没有解决。我们(作为开发团队)根本不喜欢拆分数据库的想法。但是,重写应用程序并创建新的数据库结构以提高代码性能的计划尚未获得批准。目前,硬件就是答案。还有一些法律问题迫使我们拆分成几个数据库来保存数据。但这让我有点担心 apache2 能够处理什么。
有人知道吗?
答案1
首先,你应该认真考虑一下这个设计。数据库设计的最佳实践是尽可能避免将数据拆分到多个数据库中。当然,也有例外(例如,如果你需要让客户/应用程序修改他们的架构),但一般来说,连接到多个数据库的可扩展性很差。此外,跨数据库查询很难编写,成本高,而且在许多(大多数?)数据库系统中支持不佳,迫使你做很多工作,而这些工作本来可以由应用程序中的数据库来完成。当数据库和应用程序之间存在 N..N 关系时,可维护性是一场噩梦。
其次,您的解释有点不清楚,但我想知道您如何使用您的池..?通常使用 prefork 时,您会保留一些服务器,以改善延迟。只要服务器存在,持久连接也应该存在。pconnect 并不是真正的池,听起来您也不像这样做。您能给出一个更清楚的例子吗?
第三,您可能会耗尽一些资源。文件描述符很可能会很早就造成问题,并且来自每个工作进程的大量连接将消耗 Apache 和数据库中的内存。此外,即使使用连接池,建立连接也会很昂贵。如果您无法减少正在使用的数据库数量,您很可能不得不承担使用 connect 而不是 pconnect 的成本,以减少陈旧的数据库连接所浪费的资源量。
如果有人向我提出一个需要从 Apache 工作器连接到数百个数据库的设计,我会让他们重新回到绘图板上。这种设计有太多可能出错的地方。合并数据库,如果不可能,就添加一个中间层。
编辑:好的,现在事情更清楚一点了。
这在一定程度上是一个容量规划问题,通常不可能提供好的答案。但是,需要澄清几点。
如前所述,在尝试与多个数据库建立连接时,您可能会遇到许多硬性限制。文件描述符和内存(尤其是共享内存)可能是您早期遇到的限制。
您所做的并不是真正的连接池,因为持久连接永远不会返回到池中。它只是持久连接,这为您节省了一些开销。
如果我真的必须以这种方式对数据库进行分片(我认为这是一个非常糟糕的设计选择),我的方法是将 Apache 进程专用于每个数据库。这样,我就可以降低在一个进程中积累过多持久连接的风险。据我所知,如果不安装多个 Apache2 并根据 FQDN 拆分请求,就无法做到这一点。我会考虑的替代解决方案是承担使用连接的成本并使用缓存来尽量减少数据库命中次数,并检查我是否无法将 Web 应用程序与数据库混乱分离开来。
答案2
apache2 处理的连接数有限制吗?
是的,它受到其配置参数(MaxClients、MaxServers、KeepAlive、MaxRequestsPerChild 等)和 CPU/内存(使用 KeepAlive 您可以用其中一个换取另一个)的限制。
它会在记忆中增长吗……?
是的,连接越多,线程越多,占用的内存也越多。查看每个 Apache 线程占用的内存量(通常为 20 - 30MB),这样您就可以了解在可用 RAM 的情况下可以占用的最大内存量。如果禁用未使用的模块,每个线程占用的内存就会更少。
或者,如果内存是一个问题,您可以考虑使用 Nginx 而不是 Apache,因为 nginx 消耗(少量)固定量的内存。
无论如何,瓶颈通常不会出现在 Web 服务器中,而是出现在数据库和磁盘 I/O 中,这些问题可以通过缓存和数据库设置/代码/模式优化来解决。
最终,这看起来像一个容量规划问题,最后,确定系统是否可以处理大量连接的唯一方法是尝试在测试环境中复制设置(或其中的代表部分)并对其进行基准测试。