PHP MYSQL 连接池解决方案 - umyproxy
目录
传统的 PHP 项目在高并发场景下有一个痛点:没有 mysql 连接池。
为什么连接池这么重要
我们看看在没有连接池的情况下会发生什么事情:
- 大量的短连接会占用端口,而计算机只有256*256(65536)个端口, 实际更少,高并发情况下会导致无端口可用。
- 当服务器处理完请求后主动关闭连接, 这个场景下会出现大量 socket 处于 TIME_WAIT 状态, 这个状态是 TCP 协议规定的,主要是为了保证连接的可靠性。
PHP 为什么没有连接池
这是由于 PHP-FPM 的运行机制,导致了 PHP 没办法使用连接池,因为每次请求结束,PHP 脚本都会被释放, 无法保持一个连接池。
PHP 使用连接池的方案
- 基于 workman 或者 swoole 这样的常驻内存的框架是可以实现连接池的, 但是这种运行模式与 php-fpm 完全不一样了,需要对原来的项目进行大量的改造,传统项目实现成本较高,新项目可以考虑使用。
- 对于传统的 php-fpm 项目可以使用本地代理的方式来实现,每个项目本地建立一个代理服务, 代理服务与 mysql 建立长连接和连接池,项目访问代理服务来与 mysql 通信。
我用 go 语言写了一个 mysql 代理服务umyproxy,代理服务支持连接池,不需要对项目进行大量的改动,仅仅修改配置即可。
umyproxy 实现原理
- 代理服务通过
unix domain socket
与 php 脚本进行通信,这样不占用端口,也不需要真正的经过网络协议栈,有更高的通信效率。 - 代理服务与 mysql 建立连接实现连接池。
- 代理服务可以识别 php 和 mysql 的握手,认证,发送命令等协议。
- 当 php 程序使用完成发送 close 指令时,代理服务把 mysql 连接放入连接池,等待下次请求使用。
- PHP 程序只需要把连接 mysql 的方式改成 unix socket 的方式即可。