您的位置:首页 > 编程语言 > PHP开发

PHP使用数据库长连接

thinkjava 2020-06-29 17:58 162 查看 https://blog.51cto.com/php2012

PHP长连接的原由

数据库长连接对于PHP来说并不常用,实际上PHP是支持数据库长连接。PHP是单进程(或线程)工作并且大部分情况是由低层去协调,一般情况下只有保证当前进程(或线程)不结束长连接才会有效(即相同的连接地址与账号只会共用同一个连接,不会因为多次发起连接而创建多个连接),并且没有像JAVA常驻内存中可以自行开发连接池去管理这些长连接。

很多开发同学认为使用了长连接的代码就代表开启了长连接的功能,殊不知很多时候长连接等于短连接,即PHP执行完后进程(或线程)自动结束并关闭释放所有连接和资源。

长连接是为了减少业务代码连接数据所带来的性能开销,但会增加数据库连接数,一般数据库的连接数是有数量限制的,如果不能合理释放与创建将给数据库带来相反的效果。

PHP使用长连接

理想状态下一个长连接同一个时间只被一个进程(或线程)使用,当没有空闲长连接时需要重新创建一个长连接,当空闲长连接过盛时需要及时释放。在节省连接数据库开销的同时又不影响数据库对其它模块提供服务。

PHP使用长连接可直接通过官方提供的扩展库,比如:mysql、PostgreSQL 、PDO等。目前常用的还是PDO,它是一个通用的数据库操作扩展,只需要安装对应的数据库子扩展即可通过PDO进行操作。PDO开启长连接需要在new时增加长连接配置项(注意在new后再指定长连接配置项无效)。
例如:

$dsn = 'mysql:dbname=testdb;host=127.0.0.1';
$user = 'dbuser';
$password = 'dbpass';
try {
$dbh = new PDO($dsn, $user, $password, [PDO::ATTR_PERSISTENT => true]);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}

实际应用中如果需要PHP选用长连接需要了解利弊,否则出了问题再处理会非常棘手,同时也需要验证长连接是否有效,很多时候配置不当导致长连接以短连接的模式运行。
验证长连接是否有效只能通过查看数据库进程,比如:Mysql可以使用

SHOW FULL PROCESSLIST

当PHP运行后数据库连接进程并未释放说明已经成功了(连接进程可通过账号地址来区分),短连接在PHP结束后会立即释放连接进程。需要说明的是子进程(或线程)一般会强制生命周期,一段时间后线程会被销毁并重新创建新线程,目的为解决线程长期调用容易产生内部异常影响正常服务,所有长连接会在一定的时间内会被销毁。

PHP使用长连接的主要途径有:

  • php+apache(开mpm扩展)
  • php-fpm(官方推荐)
  • 中间件

php+apache(配置mpm扩展)
早期PHP都是与apache结合使用,通过apache的mpm进程池可以实现数据库长连接,这种方式是把长连接与PHP线程进行绑定,因此所有被调用过的线程会保留使用过的长连接数据,当下次线程被调用时会自动取出上次有效的长连接。

此种方式需要php以模块的形式加载到apache进程中(即PHP以CGI模式运行)。不同的系统安装与配置不一样,具体可以参考PHP文档:https://www.php.net/manual/zh/install.php

mpm说明文档:http://httpd.apache.org/docs/2.4/zh-cn/mpm.html

mpm在不同的系统中默认使用不同的mpm处理方式,尤其在编译安装时如果不指定mpm处理方式,则会使用默认对应系统的处理方式,每种处理方式有不尽相同的配置参数,最终的目的还是配置多个进程(或线程)。

默认的配置内容如下(apache 2.4)

AcceptFilter http none
AcceptFilter https none
<IfModule !mpm_netware_module>
<IfModule !mpm_winnt_module>
User daemon
Group daemon
</IfModule>
</IfModule>

<IfModule !mpm_netware_module>
PidFile "logs/httpd.pid"
</IfModule>
<IfModule !mpm_winnt_module>
<IfModule !mpm_netware_module>
LockFile "logs/accept.lock"
</IfModule>
</IfModule>

<IfModule mpm_prefork_module>
StartServers          5
MinSpareServers       5
MaxSpareServers      10
MaxClients          150
MaxRequestsPerChild   0
</IfModule>
<IfModule mpm_worker_module>
StartServers          2
MaxClients          150
MinSpareThreads      25
MaxSpareThreads      75
ThreadsPerChild      25
MaxRequestsPerChild   0
</IfModule>
<IfModule mpm_beos_module>
StartThreads            10
MaxClients              50
MaxRequestsPerThread 10000
</IfModule>
<IfModule mpm_netware_module>
ThreadStackSize      65536
StartThreads           250
MinSpareThreads         25
MaxSpareThreads        250
MaxThreads            1000
MaxRequestsPerChild      0
MaxMemFree             100
</IfModule>
<IfModule mpm_mpmt_os2_module>
StartServers           2
MinSpareThreads        5
MaxSpareThreads       10
MaxRequestsPerChild    0
</IfModule>
<IfModule mpm_winnt_module>
ThreadsPerChild      150
MaxRequestsPerChild    3000
</IfModule>

注意:php不建议运行在apache的mpm线程化模式下(windows系统除外),具体的原因:https://www.php.net/manual/zh/faq.installation.php#faq.installation.apache2

php-fpm
php-fpm是PHP官方的进程管理器,它如同一个独立的服务模块,并且提供了很多优化措施与配置。这种方式与apache的mpm扩展类似,只是PHP内部自行处理,不需要借助其它模块,可以方便与nginx、apache等配合对外提供服务。
只要以php-fpm形式使用长连接,都会保存在内存中,但php-fpm的子进程受配置影响,不同的配置会影响子进程的生命周期,子进程被销毁长连接也一样。

php-fpm文档:https://www.php.net/manual/zh/install.fpm.php

中间件
使用中间件就省掉了PHP特意处理,但会中间件会额外增加系统开销,这种方式是把数据库的连接压力转移到中间件。使用中间件会有很多选择,你可以使用PHP开发(比如使用swoole),也可以使用其它语言开发,或者使用已经开源的中间件(比如:atlas)。中间可以提供更多定制化的功能,比较事务自动回滚,锁自动释放等。

长连接与短连接的优劣

长连接对节省数据库开销是有一定的帮助,但需要合理的管理,目前PHP没有像JAVA那样有很多成熟的连接池管理模块,主要也是因为PHP没有多少超大型系统及相关需求。长连接节省的性能开销需要有足够的数据量才能放大到很直观,对于PHP开发人员来说能体现到的机会并不多,一来PHP在短连接上性能表现已经很不错,二来PHP目前还没有成熟的连接池模块来管理长连接冒然去实现有一定的风险。
其实数据库的压力在数据增、删、改、查上,很少听说因为使用短连接把数据库搞挂了,如果数据量上来了都需要改为多节点来分压。同时数据库的压力都会留有余地,理想状态需要数据库压力最大化(提高应用率),但很少会把数据库平均压力放到80%以上,不然来个活动很有可能把数据库给搞挂。因此数据库留有了一定的余地那短连接所带来的开销基本上可以接受。

短连接
优点

  • 业务逻辑简单,不需要考虑连接池
  • 连接可以及时释放方便其它模块使用
  • 事务处理会及时回滚或提交
    缺点
  • 频繁连接会增加数据库压力
  • 会增加很多网络连接待释放(主要是TCP/IP协议关闭连接时会进入等待造成的,不过会自动释放)
  • 占用资源较多,性能较差

长连接
优点

  • 减少连接次数缓解连接数据库压力
  • 不会增加很多网络连接待释放
  • 占用资源较少,性能较好
    缺点
  • 复杂的连接池管理逻辑
  • 事务需要及时回滚与提交(如果不及时回滚或提交会进入到下一次请求中,造成数据混乱)
  • 连接释放不合理会影响其它模块使用
  • 不会自动释放锁没,影响其它进程处理
标签: