php-fpm与mysql长连接

总结:php-fpm在整个进程的生命周期中会把所有长连接的链接句柄缓存到进程中,在每个请求进来时都会复用

转载自:http://blog.csdn.net/twg17865933200/article/details/52672826


之前在写博文关于学习PHPde 几点思考遗留了一个数据库连接的疑问,疑问解决了,新oJ也上线运行一个多月了,今天整理出来记录一下。

其实是利用PHP-fpm的工作方式配合MySQL配置一下实现了一个伪连接池。

首先明白一下php语言的架构和php生命周期。

SAPI接口

SAPI: Server abstraction API,它提供了一个接口,使得PHP可以和其他应用进行交互数据。 

看图很清楚就可以理解,sapi以上是使用php的各种方式mod_php,fastcgi,cli等等,sapi以下是php语言,我们使用php一切的开始就从sapi开始。

php开始阶段 (分两个阶段)

第一阶段:是在我们启动php-fpm,或者apache的时候是在所有请求到达之前进行的,且只进行一次。启动Apache或者php-fpm后,PHP解释程序也随之启动; PHP调用各个扩展(模块)的MINIT方法,从而使这些扩展切换到可用状态。看看php.ini文件里打开了哪些扩展吧; MINIT的意思是“模块初始化”。各个模块都定义了一组函数、类库等用以处理其他请求。 模块在这个阶段可以进行一些初始化工作,例如注册常量, 定义模块使用的类等等.

第二阶段:是在请求发生阶段,当一个页面请求发生时.则在每次请求之前都会进行初始化过程(RINIT请求开始).请求到达之后,SAPI层将控制权交给PHP层,PHP初始化本次请求执行脚本所需的环境变量,例如创建一个执行环境,包括保存php运行过程中变量名称和变量值内容的符号表. 以及当前所有的函数以及类等信息的符号表.例如是Session模块的RINIT,如果在php.ini中启用了Session 模块,那在调用该模块的RINIT时就会初始化$_SESSION变量,并将相关内容读入; 然后PHP会调用所有模块RINIT函数,即“请求初始化”。 在这个阶段各个模块也可以执行一些相关的操作, 模块的RINIT函数和MINIT函数类似 ,RINIT方法可以看作是一个准备过程,在程序执行之前就会自动执行。

php结束阶段(分两个阶段)

第一阶段:请求结束,请求处理完后就进入了结束阶段,PHP就会启动清理程序。它会按顺序调用各个模块的RSHUTDOWN方法。 RSHUTDOWN用以清除程序运行时产生的符号表,也就是对每个变量调用unset函数。

第二阶段:SAPI关闭,比如php-fpm销毁一个子进程。php调用每个扩展的MSHUTDOWN方法,这是各个模块最后一次释放内存的机会。

单进程SAPI生命周期


多进程SAPI生命周期


单进程图可以对映我们在命令行执行php脚本,MINT,RINT执行后执行我们的脚本代码,然后执行RSHUTDOWN,MSHUTDOWN就结束了。 
多进程图可以对映php-fpm的方式,一个进程MINT后,循环执行RINT,RSHUTDOWN,循环处理很多请求直到该进程要销毁执行MINT,然后结束。

数据库长连接(伪连接池)

在上面讲php结束阶段的时候我们知道php在执行RSHUTDOWN的时候会释放所有处理本次请求的资源,如申请的变量。那么理所当然的是我们打开的数据库连接句柄也会被释放,但是这只限于我们打开连接的时候使用的是短链接,看官方文档我们可知道如果你打开的是长连接,在请求处理完后php会收留在本次打开的连接(即使你主动关闭也不会关闭而被收留),在下次有打开相同连接的请求时php会把收留的句柄直接给出去,就免去了建立连接的过程效率更高。这个收留的域是MINT,MSHUTDOWN之间也就对应我们php-fpm的一个子进程存活期。好了,现在我们想,php-fpm子进程数固定,一个子进程收留一个连接(假设打开的都是同一个数据库)给这个进程处理的所有页面用,那么我数据库连接的数量就应该和我php-fpm子进程的数量一样无论我们处理多少个页面,这样效果就和一个连接池差不多了。 
这样配置php-fpm子进程数实现的伪连接池也要配合数据库的一些配置才好使,比如数据库允许连接数要大于php-fpm子进程数,如mysq再配置一下wait_timeout 和interactive_timeout控制连接时长当一个连接很长时间没活动的时候mysql就关闭它,php活动时这边会重新建立新连接。这样避免时间长了mysql有一大堆不活动的连接。

另外有人会有这样的疑问,我们知道一个php-fpm子进程处理请求是阻塞的,一个进程瞬间也就处理一个请求,那么同时我处理的请求数就应该是我php-fpm子进程数,那这样我用短链接打开用完后关闭,那同时我活动的连接数也应该是和我php-fpm子进程的数量相同啊,那为什么在很多人访问的时候我mysql会报too many connection?这个应该真的是应该和项目代码有关了,短连接,长链接主要省的是建立链接关闭链接过程的消耗。

参考连接: 
深入理解Zend SAPIs(Zend SAPI Internals) 
http://www.laruence.com/2008/08/12/180.html 
深入理解php底层:php生命周期 
http://blog.csdn.net/hguisu/article/details/7377520#comments 
数据库持久链接 
http://php.net/manual/zh/features.persistent-connections.php

 

转载自:http://www.liuxos.com/post/56/php-fpm%E4%B8%8Emysql%E9%95%BF%E8%BF%9E%E6%8E%A5.html

posted on 2017-07-02 21:22  wpjamer  阅读(4676)  评论(0编辑  收藏  举报

导航