标签归档:php

PHP7开启Opcode性能对比

Opcache 的前生是 Optimizer+ ,它是PHP的官方公司 Zend 开发的一款闭源但可以免费使用的 PHP 优化加速组件。 Optimizer+ 将PHP代码预编译生成的脚本文件 Opcode 缓存在共享内存中供以后反复使用,从而避免了从磁盘读取代码再次编译的时间消耗。同时,它还应用了一些代码优化模式,使得代码执行更快。从而加速PHP的执行。

 PHP的正常执行流程如下

 

request请求(nginx,apache,cli等)–>Zend引擎读取.php文件–>扫描其词典和表达式 –>解析文件–>创建要执行的计算机代码(称为Opcode)–>最后执行Opcode–> response 返回

每一次请求PHP脚本都会执行一遍以上步骤,如果PHP源代码没有变化,那么Opcode也不会变化,显然没有必要每次都重新生成Opcode,结合在Web中无所不在的缓存机制,我们可以把Opcode缓存下来,以后直接访问缓存的Opcode岂不是更快,启用Opcode缓存之后的流程图如下所示:

 

 Opcode cache 的目地是避免重复编译,减少 CPU 和内存开销。

下面介绍Opcache的安装

安装:

1、找到opcache的扩展,我的是php7.1
yum list php71*
2、安装扩展
yum install php71w-opcache.x86_64

配置:

zend_extension=opcache.so
[opcache]
;开启opcache
opcache.enable=1  

;CLI环境下,PHP启用OPcache
opcache.enable_cli=1

;OPcache共享内存存储大小,单位MB
opcache.memory_consumption=128  

;PHP使用了一种叫做字符串驻留(string interning)的技术来改善性能。例如,如果你在代码中使用了1000次字符串“foobar”,在PHP内部只会在第一使用这个字符串的时候分配一个不可变的内存区域来存储这个字符串,其他的999次使用都会直接指向这个内存区域。这个选项则会把这个特性提升一个层次——默认情况下这个不可变的内存区域只会存在于单个php-fpm的进程中,如果设置了这个选项,那么它将会在所有的php-fpm进程中共享。在比较大的应用中,这可以非常有效地节约内存,提高应用的性能。
这个选项的值是以兆字节(megabytes)作为单位,如果把它设置为16,则表示16MB,默认是4MB
opcache.interned_strings_buffer=8

;这个选项用于控制内存中最多可以缓存多少个PHP文件。这个选项必须得设置得足够大,大于你的项目中的所有PHP文件的总和。
设置值取值范围最小值是 200,最大值在 PHP 5.5.6 之前是 100000,PHP 5.5.6 及之后是 1000000。也就是说在200到1000000之间。
opcache.max_accelerated_files=4000

;设置缓存的过期时间(单位是秒),为0的话每次都要检查
opcache.revalidate_freq=60

;从字面上理解就是“允许更快速关闭”。它的作用是在单个请求结束时提供一种更快速的机制来调用代码中的析构器,从而加快PHP的响应速度和PHP进程资源的回收速度,这样应用程序可以更快速地响应下一个请求。把它设置为1就可以使用这个机制了。
opcache.fast_shutdown=1

;如果启用(设置为1),OPcache会在opcache.revalidate_freq设置的秒数去检测文件的时间戳(timestamp)检查脚本是否更新。
如果这个选项被禁用(设置为0),opcache.revalidate_freq会被忽略,PHP文件永远不会被检查。这意味着如果你修改了你的代码,然后你把它更新到服务器上,再在浏览器上请求更新的代码对应的功能,你会看不到更新的效果
强烈建议你在生产环境中设置为0,更新代码后,再平滑重启PHP和web服务器。
opcache.validate_timestamps=0 

;开启Opcache File Cache(实验性), 通过开启这个, 我们可以让Opcache把opcode缓存缓存到外部文件中, 对于一些脚本, 会有很明显的性能提升.
这样PHP就会在/tmp目录下Cache一些Opcode的二进制导出文件, 可以跨PHP生命周期存在.
opcache.file_cache=/tmp

查看phpinfo:

测试结果:

同样的接口从以前的几百毫秒提升到现在的50ms左右

 

安装Composer PHP Warning: copy(): SSL operation failed with code 1.

报错信息

[root@localhost ~]# php -r "copy('https://install.phpcomposer.com/installer', 'composer-setup.php');" PHP Warning:  copy(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed in Command line code on line 1 Warning: copy(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed in Command line code on line 1 PHP Warning:  copy(): Failed to enable crypto in Command line code on line 1 Warning: copy(): Failed to enable crypto in Command line code on line 1 PHP Warning:  copy(https://install.phpcomposer.com/installer): failed to open stream: operation failed in Command line code on line 1 Warning: copy(https://install.phpcomposer.com/installer): failed to open stream: operation failed in Command line code on line 1

解决方法

  • 应该是CA证书验证失败造成的错误,下载个CA证书
[root@localhost ~]# wget http://curl.haxx.se/ca/cacert.pem [root@localhost ~]# mv cacert.pem /usr/local/openssl/ssl/certs/cacert.pem [root@localhost ~]# vim /yourpath/php.ini
  • 修改cafile路径,保存
[openssl]
; The location of a Certificate Authority (CA) file on the local filesystem
; to use when verifying the identity of SSL/TLS peers. Most users should
; not specify a value for this directive as PHP will attempt to use the
; OS-managed cert stores in its absence. If specified, this value may still
; be overridden on a per-stream basis via the "cafile" SSL stream context ; option.
;openssl.cafile=
openssl.cafile=/usr/local/openssl/ssl/certs/cacert.pem

使用nginx配置多个php-fastcgi负载均衡

配置还是非常简单的,充分体现了nginx的强大与配置的简单。

应用的最前端是一台nginx服务器,所有静态的内容都由nginx来处理,而将所有php的 请求都分摊到下游的若干台

运行PHP fastcgi守护进程的服务器中,这样可以以一种廉价的方案来实现对系统负载的分摊,扩展系统的负载能力。

三台php-fastcgi服务器的ip地址分别为:

          172.16.236.110 ,   172.16.236.111,     172.16.236.112

运行php-fastcgi进程时,需要让php-cgi监听到服务器的局域网地址(分别如上所示),而不是之前一般都是监听的

本地地址(127.0.0.1)。

以 172.16.236.110这台服务器为例:

 
/usr/local/php5/bin/php-cgi -b 172.16.236.110:9000

或许你用spawn-fcgi来启动php-fcgi,那么就是这样(供参考,其实也就是修改监听的地址和端口即可):

 
/usr/local/lighttpd/bin/spawn-fcgi -f /usr/local/php5/bin/php-cgi -a 172.16.236.110 -p 9000

又或许你是用php-fpm来管理php-fcgi,那么你需要修改php-fpm的配置:

 
vim  /usr/local/php5/etc/php-fpm.conf

找到这个配置项(其中的地址可能需要根据你自己环境来调整)



<value< span=”” style=”word-wrap: break-word;”> name=”listen_address“>127.0.0.1:9000>

修改为:

<value< span=”” style=”word-wrap: break-word;”> name=”listen_address>172.16.236.110:9000>



修改完毕后,重启你的php-fpm进程。

然后按照上面的步骤,依次修改其他php fastcgi服务器。

php方面的工作暂时就是这些,下面修改nginx。

 
vim  /usr/local/nginx/conf/nginx.conf

在配置文件的http段内增加类似如下的配置:

1
2
3
4
5
upstream myfastcgi { server 172.16.236.110 weight=1; server 172.16.236.111 weight=1; server 172.16.236.112 weight=1; }

我这里三台php fastcgi服务器的权重是相同的,所以其中的weight值都是1,如果你的php fastcgi服务器需要分主次,那么

可以通过调整其weight值来达到目的。比如以第一台服务器为主,其他两台为辅,则就是这样:

1
2
3
4
5
upstream myfastcgi { server 172.16.236.110 weight=1; server 172.16.236.111 weight=2; server 172.16.236.112 weight=2; }

然后找到原来nginx关于php fastcgi配置的部分,比如:

1
2
3
4
5
6
location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; }

将其中的fastcgi_pass那一段改为:



fastcgi_pass myfastcgi;

其中的myfastcgi也就是上面刚刚配置的php fastcgi均衡器的名字了。

完了以后,重启nginx即可。

简单吧,就通过这么几个简单的配置,就可以实现一个经济高效的nginx、多php-fcgi的负载均衡解决方案了。

当然了,这样的方案运用到实际项目中 还需要进行一些细化的配置,主要是php方面还需要进一步配置

php连接mysql是否应该使用存储过程以及优劣势和使用场景

利弊是相对的,使用存储过程来实现不一定是什么“滔天大罪”,这完全取决于系统的规模,扩展性以及产品的发展方向。
通常情况来说,把业务逻辑写到存储过程中不利于系统分层设计和维护,更不利于数据库的迁移(当然没有谁总想着换个数据库玩儿玩儿),这么做的原因很可能是他认为可以提高性能(存储过程的性能确实优于SQL访问的性能),不过为了解决性能问题有很多种方案,这种方式可能会差一些。

先说一下优劣势,再说一下使用场景吧

1、存储过程的优势

(1)、减少连接数

(2)、调用相对程序方比较简单,由DB管理员加,程序方只是需要传递参数即可

(3)、方便DBA查看

2.使用存储过程的劣势

(1)、程序极大耦合,业务一旦更改,需要都进行更改

(2)、牵扯到复杂计算的情况下,需要数据库进行运算,而数据库的优势是存取,循环等逻辑判断服务的情况是数据库的一个硬伤

(3)、调试困难,无法知道运行sql的情况,尤其是数据库有专门DBA的情况

(4)、主从分离的情况无法使用

(5)、无法适应数据库的切割(水平或垂直切割)。数据库切割之后,存储过程并不清楚数据存储在哪个数据库中。

3、使用场景

存储过程只是适用在php和mysql都是同一个人管理的不太进行业务变更的小网站上。稍微复杂一点的网站并不适合存储过程

php安装IMAP依赖

[root@hexu.org imap]$ yum install -y libc-client-devel

[root@hexu.org imap]$ ln -s /usr/lib64/libc-client.so /usr/lib/libc-client.so

3. 进行安装

[root@hexu.org imap]$ /usr/local/php/bin/phpize

[root@hexu.org imap]$ ./configure –with-php-config=/usr/local/php/bin/php-config –with-imap –with-imap-ssl –with-kerberos

[root@hexu.org imap]$ make && make install

4. 最后调整php.ini

[root@hexu.org imap]$ vi /usr/local/php/lib/php.ini

##vi php.ini add following config

[imap]

extension = imap.so

5. 检查是否安装成功

[root@hexu.org imap]# php -v

PHP 5.3.23 (cli) (built: Apr  7 2013 23:20:21) 

Copyright (c) 1997-2013 The PHP Group

Zend Engine v2.3.0, Copyright (c) 1998-2013 Zend Technologies

[root@hexu.org imap]# php -m | grep imap

imap ## 看到这里,说明成功安装了

按上面顺序安装应该不会有报错,如果发现错误根据提示找相应的依赖包安装即可,下面举例安装过程遇到的2个error.

1. 没有安装libc-client-devel导致,按上面第一步安装即可, Error info:

checking for utf8_mime2text signature… new

checking for U8T_DECOMPOSE… 

configure: error: utf8_mime2text() has new signature, but U8T_CANONICAL is missing. This should not happen. Check config.log for additional information.

2. 找不到libc-client.a library, 需要手动添加文件link, Errof info:

checking for crypt in -lcrypt… yes

configure: error: Cannot find imap library (libc-client.a). Please check your c-client installation.

解决方法:

# ln -s /usr/lib64/libc-client.so /usr/lib/libc-client.so

如果出现 Cannot find imap library (libc-client.a).

我们只要执行

# yum install libc-client-devel.x86_64

# ln -s /usr/lib64/libc-client.so /usr/lib/libc-client.so

Nginx负载均衡的优缺点

Nginx的优点是:
1、工作在网络的7层之上,可以针对http应用做一些分流的策略,比如针对域名、目录结构,它的正则规则比HAProxy更为强大和灵活,这也是它目前广泛流行的主要原因之一,Nginx单凭这点可利用的场合就远多于LVS了。
2、Nginx对网络稳定性的依赖非常小,理论上能ping通就就能进行负载功能,这个也是它的优势之一;相反LVS对网络稳定性依赖比较大,这点本人深有体会;
3、Nginx安装和配置比较简单,测试起来比较方便,它基本能把错误用日志打印出来。LVS的配置、测试就要花比较长的时间了,LVS对网络依赖比较大。
3、可以承担高负载压力且稳定,在硬件不差的情况下一般能支撑几万次的并发量,负载度比LVS相对小些。
4、Nginx可以通过端口检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等,并且会把返回错误的请求重新提交到另一个节点,不过其中缺点就是不支持url来检测。比如用户正在上传一个文件,而处理该上传的节点刚好在上传过程中出现故障,Nginx会把上传切到另一台服务器重新处理,而LVS就直接断掉了,如果是上传一个很大的文件或者很重要的文件的话,用户可能会因此而不满。
5、Nginx不仅仅是一款优秀的负载均衡器/反向代理软件,它同时也是功能强大的Web应用服务器。LNMP也是近几年非常流行的web架构,在高流量的环境中稳定性也很好。
6、Nginx现在作为Web反向加速缓存越来越成熟了,速度比传统的Squid服务器更快,可以考虑用其作为反向代理加速器。
7、Nginx可作为中层反向代理使用,这一层面Nginx基本上无对手,唯一可以对比Nginx的就只有lighttpd了,不过lighttpd目前还没有做到Nginx完全的功能,配置也不那么清晰易读,社区资料也远远没Nginx活跃。
8、Nginx也可作为静态网页和图片服务器,这方面的性能也无对手。还有Nginx社区非常活跃,第三方模块也很多。
淘宝的前端使用的Tengine就是基于nginx做的二次开发定制版。
  Nginx的缺点是:
1、Nginx仅能支持http、https和Email协议,这样就在适用范围上面小些,这个是它的缺点。
2、对后端服务器的健康检查,只支持通过端口来检测,不支持通过url来检测不支持Session的直接保持,但能通过ip_hash来解决

深入分析HTTP状态码502(nginx+php-fpm)

我们的一个web项目,由于新上城市增多,导致访问量增大,DB压力增大,作为提供接口的业务方,最近被下游反馈大量请求“502”。

502,bad gateway,一般都是upstream(这里就是php)出错,对于php,造成502的原因常见的就是脚本执行超过timeout设置时间,或者timeout设置过大,导致php进程长时间不能被释放,没有空闲worker进程来接客。

我们的项目就是php执行时间设置过短导致的,对于这种情况,可以先适当增大php的执行时间,先保证清除502,优化的事情毕竟要花更多的时间。

控制php执行时间的选项有两个,在php.ini中 max_execution_time 和php-fpm中 request_terminate_timeout,其中 request_terminate_timeout 可以覆盖 max_execution_time,所以如果不想改全局的php.ini,那只改php-fpm的配置就可以了。

 

下边我就来详细的分析一下为什么php脚本执行超出设置时间会导致nginx返回502。

先来布景,让问题复现:

nginx和php分别只启动一个worker,方便追踪。

php-fpm的request_terminate_timeout设置为3S。

测试脚本test.php

sleep(20); echo 'ok';

go go go:

在浏览器访问www.v.com/test.php,3S后如期出现…404???what???

出师不利啊,赶紧看看nginx的配置文件

这个location配置是当发生5xx错误时跳转到一个好看点的界面,但是我在/usr/share/nginx/html下并没有50x.html这个文件。所以搞了个404出来。这不是很影响我判断问题的准确性?直接注释掉!再次访问,等待3S,终于’正常’的界面出来了。

 

环境好了,下边就上套路,按照web问题的排查套路走一遍,先看看错误日志吧:

nginx:

报错都是 recv() failed (104: Connection reset by peer。

recv时失败了,连接被重置了。为啥连接被重置了?难道一言不合。

我们在看看php-fpm的错误日志:

(注意php-fpm中php_admin_value[error_log]选项指定php的错误日志,会覆盖php.ini中的。但是这里不是看php的错误,而是看php-fpm的错误。php-fpm的错误日志由php-fpm.conf中的error_log选项指定。)

每一次请求都是产生2个WARNING和1个NOTICE:

WARNING:脚本执行超时了,终止了。

WARNING:子进程收到SIGTERM信号退出了。

NOTICE:启了一个新的子进程(因为我设置的pm.min_spare_servers = 1)

看来如果php的worker进程执行超时,不仅终止脚本执行,而且worker进程也会退出。看来nginx的报错连接被重置是因为php的worker进程退出了(在TCP连接中一方如果断掉的话会发送RST给另一方)

 

通过日志已经可以知道php脚本执行超时,worker子进程退出,导致nginx报错Connection reset by peer,下边我们通过strace来看看php和nginx的情况:

php:

1.accept一个nginx的连接请求(socket,bind,listen都在master中完成 ),可以看到nginx的端口是47039,从FD0中读取数据,就是从标准输入中,这个是fast-cgi协议规定的。accept之后的已连接描述符是3。

2.从FD3中读取nginx传递过来的数据,fastcgi协议格式,接收了856字节。为什么read5次呢?

因为fastcgi协议数据包是8字节对齐,由包头和包体组成。并且都是会先发一个request数据包,包含一些请求ID,版本,typpe等信息(包头包体各占8字节),再发一个params数据包,传递get参数和环境变量(包头8字节,包体变长),最后发送一个没有包体只有包头的params数据包,表示参数发送结束(包头8字节)。所以前3个read用来读出request包的包头和包体,还有params包的包头,第四个read是读取真正的数据,最后一个read是读取最后一个params包的包头。所以nginx传递的数据应该是8+8+8+856+8=896字节(和下边nginx的传输bytes能对应上)。注意如果是post方式,还会发送stdin数据包。

3.设置休眠20S,就是php程序中的sleep(20),之后由于进程被终止了,所以后边就没啦。strace程序也退出啦。

nginx:

1.accept到浏览器的请求,可以看到浏览器端的端口是56434,IP是192.168.1.105,已建立连接的FD是3。

2.从FD3中接收数据,HTTP协议。

3.创建一个socket,FD21,用于和php建立连接。

4.连接到FD21,可以看到连接的是本机的9000端口,这里nginx和php-fpm使用IP socket连接方式,nginx和php-fpm部署在一台机器上可以考虑unix domain socket。

5.向FD21写入数据,fast-cgi协议格式,我们看到写入的长度是896,和上边的php接收的长度是对应的。

6.recvfrom函数从FD21中返回 ECONNRESET (Connection reset by peer)

7.向FD9中写入错误信息,可以推断FD9就是nginx错误日志的文件描述符。

8.关闭和FD21的连接。

9.向FD3写入502 Bad Gateway,就是返回给浏览器的信息。

10.向FD8写入一条访问日志,可以推断FD8就是nginx访问日志的文件描述符。

来验证一下nginx访问日志和错误日志的推断。可以看到的确是FD8,FD9,并处于写入模式。

 

那么在这个过程中整个网络包的传输我们不妨也看一下:

通过tcpdump抓包,用神器看比较方便。

因为只想看nginx和php的通讯,在上边又知道nginx的端口是47039,可以通过tcp.srcport==47039过滤出对应的包。

可以看到nginx和php-fpm数据交互的过程:47039->9000建立三次握手,接着向9000发送数据,9000回复ACK,3S后9000回复RST。没毛病。

注意:

SYN,FIN各占一个序列号

ACK,RST不占序列号(28,29两个包的reqnum和acknum都是相同的)

序列号是每一字节加1(29包发送896字节,同时29包seq为4219146879,30包的ack为4219147775,正好相差896)

RST不需要回复。

php安装swoole扩展

swoole是一个PHP的异步、并行、高性能网络通信引擎,使用纯C语言编写,提供了PHP语言的异步多线程服务器,异步TCP/UDP网络客户端,异步MySQL,异步Redis,数据库连接池,AsyncTask,消息队列,毫秒定时器,异步文件读写,异步DNS查询。
Swoole内置了Http/WebSocket服务器端/客户端、Http2.0服务器端。
Swoole可以广泛应用于互联网、移动通信、企业软件、云计算、网络游戏、物联网(IOT)、车联网、智能家居等领域。 使用PHP+Swoole作为网络通信框架,可以使企业IT研发团队的效率大大提升,更加专注于开发创新产品。

注意事项:
1、server.php中的ip地址必须是外网可访问地址 123.57.232.99,不能为localhost

1、安装

# wget https://github.com/swoole/swoole-src/archive/swoole-1.7.6-stable.tar.gz

# tar zxvf swoole-1.7.6-stable.tar.gz

# cd swoole-src-swoole-1.7.6-stable

# /usr/local/php/bin/phpize

  1. #./configure  --enable-zip --with-php-config=/usr/local/php/bin/php-config 
  2. # make
  3. # make install

提示:
Build complete.
Don’t forget to run ‘make test’.

Installing shared extensions: /usr/lib64/php/modules/
说明安装成功

2、php加载swoole扩展

extension=/xxx/xxx/php5.6/lib/php/extensions/no-debug-non-zts-20131226/swoole.so

3、重启服务
service php-fpm restart

4、测试,查看phpinfo信息,如下图所示:

5、代码测试

server.php代码:

# telnet 123.57.232.99 55152 
  • 1

Trying 123.57.232.99…
Connected to 123.57.232.99.
Escape character is ‘^]’.
rr
Swoole: rr
测试
Swoole: 测试

官网方式参考(php7.2.19)使用了这个方式:

安装Swoole框架和扩展

Swoole扩展

到GitHub首页下载Swoole扩展源码,地址:https://github.com/swoole/swoole-src 下载后按照标准的PHP扩展编译方式进行编译和安装。一般是

phpize
./configure
make install 

编译安装完后,修改php.ini加入extension=swoole.so开启swoole扩展。也可以通过dl(‘swoole.so’)动态载入,推荐修改php.ini。


下载swoole_framework源码,地址:https://github.com/swoole/framework。放置到您的workspace目录中即可。swoole_framework是PHP代码,只需要require/include即可,无需编译和安装。

PHP的性能演进(从PHP5.0到PHP7.1的性能速度全评测)

导读:PHP 是 Web 开发最常用的语言,每个大版本的更新都带来不少新特性和性能提升。特别是 PHP 7.0 的发布,带来 PHP
性能飞跃。本文作者对各个 PHP 版本进行了 CPU 性能基准测试,并且带来了PHP下个大版本的消息。本文中文版由高可用架构志愿者翻译。

自 1994 年 Rasmus Lerdorf 创建 PHP 以来, PHP 语言经历了许多改进,其中性能是开发人员在评估新版本时考虑的主要标准之一。

阅读这篇文章,可以了解从 PHP 5 到 7(包括 7.1)的性能提升,同时也将了解到即将加入到 PHP 8 的试验性的 JIT 分支版本的性能。

简介

本文将根据时间作出更新,增加更多信息和基准测试结果,包括尚未发布的新版本,以便更好地了解多年来 PHP 性能演变。如果您有更正或建议改进,请在文后留言。

自 1994 年 Rasmus Lerdorf 创建 PHP 以来, PHP 语言经历了激烈的演进。虽然第一版是一个简单的一人开发的
CGI 程序,Rasmus Lerdorf、Andi Gutmans 和 Zeev Suraski
加入了该语言的第三个版本的开发,并根本性重新设计。从那之后, PHP 开发组也创建并发展起来。

随着项目的发展,由于 PHP 3 天然的可扩展性, PHP 在核心和附加扩展开发的功能得到了蓬勃发展,如网络通信,解析,缓存和数据库支持。

语言本身也在发展,带来了一系列的改进。这包括支持面向对象的结构,例如类,接口, traits,闭包等。

对于许多开发人员来说,仅有新功能是不够的。随着语言越来越受欢迎, PHP 社区对于提供更好性能,可扩展性和更少内存使用的需求越来越强烈。

PHP 开发团队近 20 年来一直致力于解决这些需求,虽然 PHP 3 的引入大大提高了性能,但直到 Andi Gutmans 和 Zeev Suraski 引入 Zend Engine 并发布 PHP 4, PHP 的性能才开始变得正式起来。

2000 年推出的新的内存编译器和执行器模型大大提高了 PHP 的性能(提高了 5 倍甚至 10 倍),并首次被正式的 Web 应用程序和站点所使用。我们可以说,今天 PHP 的成果远远超出了任何人在 PHP 项目诞生时的期望。

PHP 的蓬勃发展增加了改善性能的欲望。幸运的是, Zend Engine 中设计的模型为持续优化性能提供了良好的基础。

虽然 PHP 5.0 没有带来实质性的性能提升,并且在某些情况下甚至比 PHP4 更慢,一个由 Dmitry Stogov
领导的团队在社区的大力帮助下已经在后续版本中不断优化语言,在 PHP 5.6 发布的时候,在大多数情况下,性能提升在 1.5x 和 3x 之间。

2015 年 12 月, PHP 7.0 取得了重大突破。 2016 年 12 月,7.1 版本也带来了一系列增强功能。

PHP 8 性能展望

这是一个前途光明的版本,目前正在开发当中,由 Zend 的 Dmitry Stogov 主导。虽然它是基于 PHP 7.1 版本基础,但实际版本号尚未定义,所以本文称这个版本为“试验 JIT”分支下。

关键功能 JIT(Just-In-Time)编译,是一种将代码转换为另一种字节码(比如运行它的机器 CPU 的本地代码)的技术。 JIT 可以使程序运行更快。

本文涵盖了几个基准测试的结果,从 PHP 5 的第一个版本到 PHP 的试验性 JIT 分支版本,PHP 5 之前的版本性能本文不作介绍。

在写这篇文章的时候,我们很难确定 PHP 8 之前是否会有另一个主要版本,比如 PHP 7.2。但是可以假设在 PHP 8 发布时,它已经包括当前试验版 JIT 分支的强大功能。

PHP 性能评估

本文只运行纯 CPU 任务脚本的基准测试(不需要I / O操作的任务例如访问文件,网络或数据库连接)。

使用的基准测试脚本如下所示:

  1. bench.php 可在PHP源代码的 php-src/Zend 目录
  2. micro_bench.php 也可以在 PHP 源代码发布的 php-src/Zend 目录中找到
  3. mandelbrot.php https://gist.githubusercontent.com/dstogov/12323ad13d3240aee8f1/raw/37fed3beb7e666b70e199bcf361af541b3c30d2d/b.php

基准脚本仅使用每个PHP主要版本的最新小版本运行。因此,测试的版本如下:

  1. 5.0.5
  2. 5.1.6
  3. 5.2.17
  4. 5.3.29
  5. 5.4.45
  6. 5.5.38
  7. 5.6.28
  8. 7.0.13
  9. 7.1.0
  10. PHP-JIT(JIT实验分支)

当然,我想确定,我们在相同的基准上运行所有小版本,例如在 5.3.0 到 5.3.29 之间。结果是有说服力的:性能方面的主要增强不是由小版本带来的,而是主要版本号的变化,例如从 PHP 5.4 到 PHP 5.5,或从PHP 5.6 到 PHP 7。

小版本没有显示任何明显的性能改进。这意味着相同的脚本应该以相同的速度运行,无论您使用 PHP 5.4.0 还是 PHP 5.4.45。

您可以查看基准进程部分,详细说明主机系统的设置,各个基准的运行方式以及如何解释时序结果。

纯 CPU 基准测试结果

这部分给出了每个 PHP 版本的基准测试结果。

每个基准列显示 3 个值:

  • 时间: 执行时间,以秒和毫秒为单位
  • %rel, gain:相对于以前的版本收益的执行时间。 在下面的表格中,例如,%rel。 bench.php 和版本 5.3.29 的收益是 31.89%,意味着该脚本比 5.2.17 版本运行快 31.89%。
  • %abs, gain:与 PHP 5.0 相比脚本运行的收益。 如果你看看bench.php 和试验性的 JIT 分支的这个列的交集,你会注意到,对于这个特定的测试基准,PHP 8 比 PHP 5.0 快 41 倍以上。

纯CPU基准测试的结果如下所示:

CPU基准测试

CPU基准测试


(1)测试不能在 5.3 之前的版本上运行,因为它使用了尚未实现的对象功能。
(2)此列中的结果有点偏颇,因为基准需要至少 PHP 5.3 运行。把它们当成纯粹说明,因为他们不能与 PHP 5.0 性能进行比较。
(3)这是一个 mandelbrot.php 脚本的修改版本,它运行得太快,在 7.1.0 和试验 JIT 分支无法准确的统计时间,我们在脚本中运行计算 100 次而不是 1 次。

纯CPU测试曲线图

当然,这些都是纯 CPU 的基准测试。它们不涵盖 PHP 性能的所有方面,它们可能不代表真实情况。但是结果足够显著,足以说明几个方面的问题:

php增加经纬度地址编码geohash扩展

geohash

php geohash extension (php geohash 扩展)

geohash简介:

geohash是一种地址编码,它能把二维的经纬度编码成一维的字符串。

geohash有以下几个特点:

首先,geohash用一个字符串表示经度和纬度两个坐标。某些情况下无法在两列上同时应用索引 (例如MySQL 4之前的版本,Google App Engine的数据层等),利用geohash,只需在一列上应用索引即可。

其次,geohash表示的并不是一个点,而是一个矩形区域。比如编码wx4g0ec19,它表示的是一个矩形区域。 使用者可以发布地址编码,既能表明自己位于北海公园附近,又不至于暴露自己的精确坐标,有助于隐私保护。

第三,编码的前缀可以表示更大的区域。例如wx4g0ec1,它的前缀wx4g0e表示包含编码wx4g0ec1在内的更大范围。
这个特性可以用于附近地点搜索。首先根据用户当前坐标计算geohash(例如wx4g0ec1)然后取其前缀进行查询 (SELECT * FROM
place WHERE geohash LIKE ‘wx4g0e%’),即可查询附近的所有地点。Geohash比直接用经纬度的高效很多。

编译

git clone https://github.com/shenzhe/geohash.git

执行:
/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config
make
make install

然后把 geohash.so 加入到php.ini中 

方法

/**
 *  $latitude    //纬度
 *  $longitude   //经度
 *  $precision   //精密度, 默认是12
 *  返回 $precision 长度的 string 
 */
geohash_encode($latitude, $longitude, $precision=12);  



/**
 *  $hash    //geohash_encode后的值
 *  返回 array // Array
 *					(
 *					    [latitude] => 39.416916975752
 *					    [longitude] => 100.92223992571
 *					    [north] => 39.416917059571
 *					    [east] => 100.92224009335
 *					    [south] => 100.92223992571
 *					    [west] => 100.92223975807
 *					)
 */
geohash_decode($hash);

/**
 *  $hash    //geohash_encode后的值
 *  返回 在$hash 8个方向的hash值 (顺序:N, NE, E, SE, S, SW, W, NW)
 *  
 *		  NW N NE
 *		    \|/
 *		  W - - E
 *		    /|\
 *		  SW S SE
 * 
 */
geohash_neighbors($hash);

/**
 *  $precision    //精密度
 *  返回 数组,array("width"=>12.0, "height"=>12.0) 
 *  表示矩形的宽和高
 */
geohash_dimension($precision);