浅谈 PHP

        这篇博客分三个部分陈述,分别是PHP进程管理器、PHP启动流程和PHP优化。

 

        谈到PHP进程管理器,不得不讲下它的进化过程,CGI--->FastCGI--->PHP-FPM。

 

        CGI全称是“公共网关接口”(Common Gateway Interface),是外部应用程序(CGI程序)与Web服务器之间的接口标准。

 

        以APP调用CRM服务接口为例,当web服务器收到此请求后,根据配置文件知道这不是一个静态文件,需要去找PHP解释器来处理。于是,web服务器会把这个请求经过相关处理后交给PHP解释器。接下来PHP解释器会解析php.ini文件,初始化执行环境,然后处理请求,再以CGI规定的格式返回处理后的结果,退出进程。web服务器再把结果返回给客户端。

 

        CGI方式在遇到连接请求先要创建CGI的子进程,激活一个CGI进程,然后处理请求,处理完后结束这个子进程。这就是fork-and-execute模式。所以用CGI方式的服务器有多少连接请求就会有多少CGI子进程,子进程反复加载是CGI性能低下的主要原因。当用户请求数量非常多时,会大量挤占系统的资源如内存,CPU时间等,造成效能低下。

 

        FastCGI是一个可伸缩地、高速地在HTTP server和动态脚本语言间通信的接口, 是CGI的一种改进方案。与传统的CGI不用的是,FastCGI像是一个常驻(long-live)型的CGI,它可以一直执行着,只要激活后,不会每次都要花费时间去fork一次。具体表现为:FastCGI会先启一个master,解析配置文件,初始化执行环境,然后再启动多个worker。当请求过来时,master会传递给一个worker,然后立即可以接受下一个请求。这样就避免了重复的劳动,效率自然是高。

 

        PHP-FPM是一个实现了FastCGI的程序,PHP5.3.3已经集成php-fpm了,不再是第三方的包了,在./configure的时候带 –enable-fpm参数即可开启PHP-FPM。PHP-FPM提供了更好的PHP进程管理方式,可以有效控制内存和进程、可以平滑重载PHP配置。

 

       PHP-FPM进程管理器自身初始化,启动多个CGI解释器进程等待来自Nginx的请求。当客户端请求达到PHP-FPM,管理器选择到一个CGI进程进行处理,Nginx将CGI环境变量和标准输入发送到一个PHP-CGI子进程。PHP-CGI子进程处理完成后,将标准输出返回给Nginx,当PHP-CGI子进程关闭连接时,请求处理完成。PHP-CGI子进程等待着下一个连接。

 

        下面可以看看PHP-FPM的常用配置。

        

;listen = 127.0.0.1:9000 nignx与php-fpm通讯地址
;修改之后会有502错误,fastcgi错误
listen = /dev/shm/php-cgi.sock

location ~ .*\.(php|php5)?$  {
    #fastcgi_pass  127.0.0.1:9000;
    #/dev/shm/是linux下一个非常有用的目录,因为这个目录不在硬盘上,而是在内存里。
    fastcgi_pass   unix:/dev/shm/php-cgi.sock;
    fastcgi_index index.php;
    include fastcgi.conf;
}

;动静子进程
pm = dynamic/static:进程管理
pm.max_children:static模式下创建的子进程数或dynamic模式下同一时刻允许最大的php-fpm子进程数量
pm.start_servers:动态方式下的起始php-fpm进程数量
pm.min_spare_servers:动态方式下服务器空闲时最小php-fpm进程数量
pm.max_spare_servers:动态方式下服务器空闲时最大php-fpm进程数量
pm.max_requests:php-fpm子进程能处理的最大请求数
;指定了一个php-fpm子进程执行多少次之后重启该进程,nginx会报502

 

 

 

        PHP启动过程分两部分讲,SAPI和PHP生命周期。

 

        SAPI是Server Application Programming Interface(服务器应用编程接口)的缩写。PHP通过SAPI提供了一组接口,供应用和PHP内核之间进行数据交互。PHP提供了一个函数查看当前SAPI接口类型:php_sapi_name(cli/cli-server 命令行模式/apache2handler Apache加载PHP以模块模式/fastcgi Nignx+FastCGI 模式)。

 

        

 

        生命周期:无论使用哪种SAPI,在PHP执行脚本前后,都包含一系列事件:Module的Init(MINT)和Shutdown(MSHUTDOWN),Request 的Init(RINT)和Shutdown(RSHUTDOWN)。

 

 

        第一阶段是PHP模块初始化阶段(MINT),可以初始化扩展内部变量、分配资源和注册资源处理器,在整个PHP实例生命周期内,该过程只执行一次。使用get_loaded_extensions 函数来查看所有编译并加载的模块/扩展,相当于CLI模式下的php -m。

 

        第二阶段是请求初始化阶段(RINT),在模块初始化并激活后,会创建PHP运行环境,同时调用所有模块注册的RINT函数,调用每个扩展的请求初始化函数 ,设定特定的环境变量、分配资源或执行其他任务,如审核。

 

        第三阶段,请求处理完成后,会调用PHP_RSHUTDOWN_FUNCTION进行回收,这是每个扩展的请求关闭函数,执行最后的清理工作。Zend引擎执行清理过程、垃圾收集、对之前的请求期间用到的每个变量执行unset。请求完成可能是执行到脚本完成,也可能是调用die()或exit()函数完成。
 

        第四阶段,当PHP生命周期结束时候,PHP_MSHUTDOWN_FUNCTION对模块进行回收处理,这是每个扩展的模块关闭函数,用于关闭自己的内核子系统。
 

        

单进程下PHP生命周期

 

多进程下PHP生命周期

 

多线程下PHP生命周期

 

        最后,谈谈PHP优化,分为zval结构、opcache和代码优化三部分。

 

        先介绍下PHP中变量及其内存对象的内部表示。PHP变量划分为两类:标量类型和复杂类型。标量类型包括布尔型、整型、浮点型和字符串;复杂类型包括数组、对象和资源;还有一个NULL比较特殊,它不划分为任何类型,而是单独成为一类。所有这些类型,在PHP内部统一用一个叫做zval的结构表示,在PHP源代码中这个结构名称为“_zval_struct”。zval的具体定义在PHP源代码的“Zend/zend.h”文件中。

 

 

        其中联合体“_zvalue_value”用于表示PHP中所有变量的值,这里之所以使用union,是因为一个zval在一个时刻只能表示一种类型的变量。可以看到_zvalue_value中只有5个字段,但是PHP中算上NULL有8种数据类型,那么PHP内部是如何用5个字段表示8种类型呢?这算是PHP设计比较巧妙的一个地方,它通过复用字段达到了减少字段的目的。例如,在PHP内部布尔型、整型及资源(只要存储资源的标识符即可)都是通过lval字段存储的;dval用于存储浮点型;str存储字符串;ht存储数组(注意PHP中的数组其实是哈希表);而obj存储对象类型;如果所有字段全部置为0或NULL则表示PHP中的NULL,这样就达到了用5个字段存储8种类型的值。

        需要指出的是是联合体中当前存储的数据类型会记录到type字段,用一个整型来标记:

 

        值得一提的是,PHP5中zval占24个字节,而PHP7中只占16个字节,PHP RC7已于本月12号放出,本来是放正式版本的,此版本性能比PHP5提升一倍,值得期待。

 

PHP7的zval结构

 

PHP7的性能测试结果,性能压测结果,耗时从2.991下降到1.186,大幅度下降60%。

 

        PHP代码经过编译后,会生成opcache码,由Zend引擎执行。由于PHP是解释型语言,每次执行PHP都会重新编译,这会造成一定得性能损耗。那么,把opcache存储起来,岂不是更快了。Alternative PHP Cache (APC) 是一个开放自由的PHP opcode 缓存。它的目标是提供一个自由、 开放,和健全的框架用于缓存和优化PHP的中间代码。

 

 

 

        说起PHP优化来,有两大法宝,基本上不用改什么代码,性能就蹭蹭提升了很多,法宝为PHP版本升级和opcache,示例可以见上面两幅图。

 

        目前主流的框架大多是php代码写的,这里推荐个C扩展的框架,Yaf(Yet another framework),PHP启动的时候便加载到内存,速度性能远比PHP写的框架强很多。此框架由目前国内最权威的PHP专家鸟哥开发维护,性能没的说,在微博工作时就用的是此框架,也可以见鸟哥关于此框架的Yaf的性能对比测试博客

 

        善用xhprofxdebug查看PHP代码中的性能瓶颈。

 

        下面就罗列了下,PHP的主要优化写法

 

1、尽可能的使用PHP内部函数

2、能用PHP内部字符串操作函数的情况下,尽量用他们,不要用正则表达式; 因为其效率高于正则

3、在循环之前设置循环的最大次数,而非在在循环中

4、尽量使用单引号

5、在组织大字符串时多试试heredoc、nowdoc写法

6、最好不用@,用@掩盖错误会降低脚本运行速度

7、用单引号代替双引号来包含字符串,这样做会更快一些

8、使用++$i递增

9、不要随便就复制变量,会增加内存消耗

10、循环里不要套SQL查询,SQL查询时不要用MySQL自带的函数,交给PHP来处理

11、使用xhprof或xdebug查看性能

12、缓存,Memcached MongoDB Redis

13、……

 

 

 

 

 

        【ps】此博客由PPT整理而成,插图均由网上搜集,文章内容部分也参照网上优秀文章而来。

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值