响应时间分布:

在切换到PHP7之前,我们曾花了不少时间来寻找优化后端的方法。当然,第一步就是从HHVM下手。在试验了几周之后,我们获得了值得关注的结果:在给框架中的JIT热身之后,我们看到速度与CPU使用率上升了三倍。

自定义对象源代码:

系列笔记:Modern PHP 笔记:语言特性Modern PHP 笔记:良好实践Modern PHP
笔记:部署测试和调优

内存使用:

所有这些东西都是用runkit实现的。动态修改代码使项目临时变更有了可能性。

static inline user_object *user_fetch_object(zend_object *obj) { return (user_object *)((char*)(obj) - XtOffsetOf(user_object, std));}/* }}} */ #define Z_USEROBJ_P(zv) user_fetch_object(Z_OBJ_P((zv)))
 // 生成私钥、公钥文件 ~/.ssh/id_rsa 和 ~/.ssh/id_rsa.pub ssh-keygen // 复制公钥到服务器 scp ~/.ssh/id_rsa.pub deploy@100.10.3.1: // 末尾要加':',会复制到家目录 // deploy用户登录服务器 // 确认有~/.ssh目录,没有则创建目录和文件,文件存储允许登录的公钥 touch ~/.ssh/authorized_keys cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys // 修改几个目录和文件的权限,只让deploy用户访问 chown -R deploy:deploy ~/.ssh chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys

图片 1

这一切到位,处理时间减少了一半,从而提高整体响应时间约40%,由于一定量的请求处理时间是花在与数据库和守护进程通信。从逻辑上讲,我们不希望这部分加快切换到php7。除此之外,由于超线程技术,集群的整体负载下降到50%以下,进一步促进了令人印象深刻的结果。广义而言,当负载增加超过50%,HT-engines,而不是作为有用的物理引擎开始工作。但这已经是另一篇文章的主题。此外,记忆的使用,这从来没有一个瓶颈,我们,减少了大约八倍以上!最后,我们节省了机器的数量。换句话说,服务器的数量可以承受更大的负载,从而降低获取和维修设备的费用。在剩余的聚类结果相似,除云上的收益是一个更温和的(大约40%个CPU),由于opcache操作的减少。

来算算我们能节省多少费用呢?大致测算一下,一个Badoo应用服务器集群大概包含600多台服务器。如果cpu使用率减半,我们可以节省大约300台服务器。考虑服务器的硬件成本和折旧,每台大约4000美元。总的算下来我们能节省大约100万美元,另加每年10万的主机托管费。而且这还没有计算对服务云性能的提升带来的价值,这个结果很令人振奋。

另外,您是否也考虑切换到PHP 7.0版本呢?
我们很希望听听您关于此问题的观点,而且非常愿意在下面的评论中回答您的疑问。

Badoo 团队

SoftMocks 可以和
NikitaPopov’s
的PHP-Parser配合:
这个库不是很快(解析速度大概比token_get_all
慢15倍),但他的接口让你绕过语法解析树,并且包含了一个方便的API
用来处理不确定的语法结构。

引用1. php5 to phpng: PHP扩展开发及内核应用: PHP
7中新的Hashtable实现和性能改进: 深入理解PHP7之zval: 官方wiki:
PHP手册: PHP7
使用资源包裹第三方扩展的实现及其源码解读:五、AMS平台升级PHP7的性能优化成果现网服务是一个非常重要而又敏感的环境,轻则影响用户体验,重则产生现网事故。因此,我们4月下旬完成PHP7编译和测试工作之后,就在AMS其中一台机器进行了灰度上线,观察了几天后,然后逐步扩大灰度范围,在5月初完成升级。这个是我们压测AMS一个查询多个活动计数器的压测结果,以及现网CGI机器,在高峰相同TGW流量场景下的CPU负载数据:就我们的业务压测和现网结果来看,和官方所说的性能提升一倍,基本一致。AMS平台拥有不少的CGI机器,PHP7的升级和应用给我们带来了性能的提升,可以有效节省硬件资源成本。并且,通过Apache2.4的Event模式,我们也增强了Apache在支持并发方面的能力。六、小结我们PHP7升级研发项目组,在过去比较长的一个时间段里,经过持续地努力和推进,终于在2016年4月下旬现网灰度,5月初在集群中全量升级,为我们的AMS活动运营平台带来性能上大幅度的提升。PHP7的革新,对于PHP语言本身而言,具有非凡的意义和价值,这让我更加确信一点,PHP会是一个越来越好的语言。同时,感谢PHP社区的开发者们,为我们业务带来的性能提升。

配置虚拟主机

CentOS: /etc/nginx/conf.d/example.conf

 server { listen 80; server_name example.com; index index.php; client_max_body_size 50M; error_log /home/deploy/apps/logs/example.error.log; access_log /home/deploy/apps/logs/example.access.log; root /home/deploy/apps/example.com; location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php { try_files $uri =404; fastcgi_split_path_info ^$; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_index index.php; fastcgi_pass 127.0.0.1:9000; } }

location / {}使用try_files指令查找匹配所请求的URI文件,先查询所请求的URI文件,找不到则查询目录,也找不到会改写URL为index.php开头的,交给location ~ \.php {}处理。把请求交给9000端口处理,前面已经设置PHP-FPM监听9000端口。

  • Puppet
  • Chef
  • Ansible
  • SaltStack

一般在/etc/php5/fpm/,
命令行php运行的是另一个php.ini文件,一般在/etc/php5/cli/

我也在安装目录下lib找到了这个文件。

memory_limit = 128M

这个值可以考虑总共分配内存,和每个PHP进程占用内存,大概算出。也可以用apache
bench或seige做压测

主要是ini文件里一堆opcache开头的配置,用的时候查文档吧

 file_uploads = 1 upload_max_filesize = 10M max_file_uploads = 3

默认同时上传20个,每个2M,不很合适。

 max_execution_time = 5

PHP进程最长用时,默认30秒太长了。如果有长时间运行的任务,要在单独的职程中运行。

PHP中的exec()函数调用bash的at命令。用于派生单独的非阻塞进程,不耽误当前PHP进程。exec()要使用escapeshellarg()函数转义shell参数。比如要生成一个pdf文件,需要等待10分钟,应该单独编写一个php文件create_report.php,让这个文件运行10分钟。

 <?php exec('echo "create_report.php" | at now'); echo 'Report pending...';

create_report.php脚本在单独的后台执行,运营完毕后可以更新数据库或者通过电子邮件把报告发给收件人。

如果要派生很多后台进程,最好用专门的队列。PHPResque等。

php默认的会话处理会拖慢大型程序,因为需要把会话数据存储在硬盘。我们应该保存在内存中,使用memcached或者redis。也便于伸缩,硬盘上数据不适合增加额外服务器。

使用memcashed需要安装PECL扩展,然后更改ini

使用较少的块发送更所数据,下面是等凑够4096字节再发

 out_buffering = 4096 implict_flush = false

php会缓存应用使用的文件路径,这样每次包含或导入文件时就无需不断搜索包含路径了。这个缓存叫真实路径缓存。realpath_cache_size
= 64k

  • 让部署变得简单
  • 部署结果可预知
  • 部署可逆

capistrano运行在本地设备,通过ssh与远程服务器通信。

图片 2

响应时间分布:

/* 定义 */typedef int64_t zend_long;/* else */typedef int32_t zend_long;

类型

静态语言,通常都要编译,编译器提供类型检查和错误报告,通常更稳定。缺点是要先编译,反馈回路长。

动态语言,通常解释执行,在运行时发现错误。迭代速度快,反馈及时。缺点是,没有类型检查,缺少内在的准确性。

介绍

我们成功的把我们的应用迁移到了php7上面(数百台机器的集群),而且运行的很好,据说我们是第二个把如此规模的应用切换到php7的企业,在切换的过程我们发现了一些php7字节码缓存的bug,庆幸的是这些bug现在已经被修复了,现在我们把这个激动人心的消息分享给所有的php社区:php7现在已经可以稳定的运行在商用环境上,而且比以前更加节省内存,性能也有的很大的提高。

图片 3

下面我会详细的介绍下我们是如何把应用前移动php7的,我们在这中间遇到的问题及处理情况,还有最终的结果。但首先让我们回头看看一些更常见的问题:

Web项目的瓶颈在于数据库持久化这是一个常见的误解。一个设计良好的系统应该是平衡的:当访问量增长时,由系统的各个部分分摊这些压力,同样的,当达到系统阀值时,系统的所有组件(不仅仅包括硬盘数据库,还有处理器和网络)共同分摊压力。基于这个事实,应用集群的处理能力才应该是最重要的因素。在很多项目中,这种集群由数以百计甚至数以千计的服务器组成,这是因为花时间去调整集群的处理能力更加经济实益(我们因此节省一百多万)。

PHP的Web应用,处理器的消耗跟其他动态高级语言一样多。但是PHP开发者面对着一个特别的障碍(这让他们成为其他社区恶意攻击的的受害者):缺少JIT,至少没有一个像C/C++语言那样的可编译文本的生成器。PHP社区无力在核心项目框架上去实现一个类似的解决方案更是树立了一种不良的风气:主要的开发成员开始整合他们的解决方案,所以HHVM在Facebook上诞生了,KPHP在VKontakte上诞生,还有其他类似的方案。幸运地是,在2015年,随着PHP7的正式发布,PHP要开始”Grow
up”啦。虽然还是没有JIT,但很难去评定这些改变在”engine”中有多重要。现在,尽管没有JIT,PHP7可以跟HHVM相匹敌( Benchmarks
from the LightSpeed
blog  or PHP
devs
benchmarks)。新的PHP7体系架构将会让JIT的实现变得简单。

在Badoo的平台开发者已经非常关注近些年出现的每一次问题,包括HHVM试点项目,但是我们还是决定等待很有前途的PHP7的到来。现在我们启动了已经基于PHP7的Baboo!这是一个史诗般的项目,拥有300多万行的PHP代码,并且经历了60000次的测试。我们为了处理这些挑战,提出了一个新的PHP引用测试框架(当然,也是开源的),并且在整个过程中节省了上百万美元。

间接访问对象变量,属性和方法。并再次,危险在于,该行为可以更改“静默”。对于那些寻找更多的信息,版本间的差异进行了详细的描述在这里。

/* 数组举例 */zval *arr;zend_parse_parameters(ZEND_NUM_ARGS() , "a", arr_qos_req);if (arr){ zval *item; zend_string *key; ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(arr), key, item) { /* ... */ }}/* 获取到item后,可以通过下面的api获取long、double、string值 */zval_get_long(item) zval_get_double(item) zval_get_string(item) 

可选:

实践出真知

很明显我们需要一种简单快速的方法在任何数量以及类型的服务器上切换php版本。要启用的话,所有指向CLI-interpreter的代码路径都替换成了
/local/php,相应的,是/local/php5或者/local/php7。这样的话,要在服务器上改变php版本,需要改变链接(为cli脚本操作设置原子操作是很重要的),停止php5-fpm,然后启动php7-fpm。在nginx中,我们使用不同的端口为php-fpm和启动php5-fpm,php7-fom设置两个不同的upstream,但我们不喜欢复杂的nginx配置。

在执行完以上的清单后,我们接着在预发布环境运行Selenium
测试,这个阶段暴露更多我们早期没注意到的问题。这些问题涉及到PHP代码(比如,我们不再使用过期全局变量$HTTP_RAW_POST_DATA,取而代之是
file_get_contents(“php://input”))以及扩展(这里存在各种不同类型的段错误)。
修复完早期发现的问题和重写单元测试(这个过程中我们也发现若干隐藏在解析器的BUG比如这里)后,进入到我们称为“隔离”发布阶段。这个阶段我们在一定数量的服务器上运行新版PHP。一开始我们在每个主要PHP集群(Web后台,移动APP后台,云平台)上只启动一个服务,然后在没有错误出现情况下,一点一点增加服务数量。云平台是第一个完全切换到PHP7的大集群,因为这个集群没有php-fpm需求。
fpm 集群必须等到我们找到或者Dmitri
Stogov修复了OpCache问题。之后,我们也会将fpm集群切换到PHP7。

现在看下结果,简单的说,他们是非常出色的。在这里,你能看到响应时间图,包括内存消耗和我们的最大的集群(包括263服务器)的处理器的使用情况,以及在
Prague 数据中心的移动应用后端的使用。

下面我会详细的介绍下我们是如何把应用前移动php7的,我们在这中间遇到的问题及处理情况,还有最终的结果。但首先让我们回头看看一些更常见的问题:

引用声明:本文为CSDN原创投稿文章,未经许可,禁止任何形式的转载。
作者:徐汉彬、王默涵、廖声茂、匡素文、廖增康、巫泽敏,以上为腾讯增值产品部平台开发中心——PHP7升级研发项目组核心成员。
责编:钱曙光,关注架构和算法领域,寻求报道或者投稿请发邮件qianshg@csdn.net,另有「CSDN
高级架构师群」,内有诸多知名互联网公司的大牛架构师,欢迎架构师加微信qshuguang2008申请入群,备注姓名+公司+职位。
推荐:
PHP开发者的百科全书——PHP知识图谱QQ会员活动运营平台,是QQ会员增值运营业务的重要载体之一,承担海量活动运营的Web系统。AMS是一个主要采用PHP语言实现的活动运营平台,
CGI日请求3亿左右,高峰期达到8亿。然而,在之前比较长的一段时间里,我们都采用了比较老旧的基础软件版本,就是PHP5.2+Apache2.0。尤其从去年开始,随着AMS业务随着QQ会员增值业务的快速增长,性能压力日益变大。于是,自2015年5月,我们就开始规划PHP底层升级,最终的目标是升级到PHP7。那时,PHP7尚处于研发阶段,而我们讨论和预研就已经开始了。一、PHP7的学习和预研1.
HHVM和JIT
2015年就PHP性能优化的方案,有另外一个比较重要的角色,就是由Facebook开源的HHVM。HHVM使用JIT的编译方式以及其他技术,让PHP代码的执行性能大幅提升。据传,可以将PHP5版本的原生PHP代码提升5-10倍的执行性能。
HHVM起源于Facebook公司,Facebook早起的很多代码是使用PHP来开发的,但是,随着业务的快速发展,PHP执行效率成为越来越明显的问题。为了优化执行效率,Facebook在2008年就开始使用HipHop,这是一种PHP执行引擎,最初是为了将
Fackbook的大量PHP代码转成
C++,以提高性能和节约资源。使用HipHop的PHP代码在性能上有数倍的提升。后来,Facebook将HipHop平台开源,逐渐发展为现在的
HHVM。
HHVM成为一个PHP性能优化解决方案时,PHP7还处于研发阶段。曾经看过部分同学对于HHVM的交流,性能可以获得可观的提升,但是服务运维和PHP语法兼容有一定成本。有一阵子,JIT成为一个呼声很高的东西,很多技术同学建议PHP7也应该通过JIT来优化性能。2015年7月,我参加了中国PHPCON,听了惠新宸关于PHP7内核的技术分享。实际上,在2013年的时候,惠新宸和Dmitry就曾经在PHP5.5的版本上做过一个JIT的尝试。PHP5.5的原来的执行流程,是将PHP代码通过词法和语法分析,编译成opcode字节码,然后,Zend引擎读取这些opcode指令,逐条解析执行。而他们在opcode环节后引入了类型推断,然后通过JIT生成ByteCodes,然后再执行。于是,在benchmark中得到非常好的结果,实现JIT后性能比PHP5.5提升了8倍。然而,当他们把这个优化放入到实际的项目WordPress中,却几乎看不见性能的提升。原因在于测试项目的代码量比较少,通过JIT产生的机器码也不大,而真实的WordPress项目生成的机器码太大,引起CPU缓存命中率下降。
总而言之,JIT并非在每个场景下都是点石成金的利器,而脱离业务场景的性能测试结果,并不一定具有代表性。
从官方放出Wordpress的PHP7和HHVM的性能对比可以看出,两者基本处于同一水平。2.PHP7在性能方面的优化PHP7是一个比较底层升级,比起PHP5.6的变化比较大,而就性能优化层面,大致可以汇总如下:
将基础变量从struct变为union,节省内存空间,间接减少CPU在内存分配和管理上的开销。
部分基础变量采用内存空间连续分配的方式,降低CPU Cache
Miss的发生的概率。CPU从CPU
Cache获取数据和从内存获取,它们之间效率相差可以高达100倍。举一个近似的例子,系统从内存读取数据和从磁盘读取数据的效率差别很大,CPU
Cache Miss类似遇到缺页中断。
通过宏定义和内联函数,让编译器提前完成部分工作。无需在程序运行时分配内存,能够实现类似函数的功能,却没有函数调用的压栈、弹栈开销,效率会比较高。
… …
更多更详细关于PHP7的介绍,有兴趣的同学可以查看:《PHP7革新与性能优化》3.AMS平台技术选型的背景就提升PHP的性能而言,可以选择的是2015年就可直接使用的HHVM或者是2015年底才发布正式版的PHP7。会员AMS是一个访问量级比较大的一个Web系统,经过四年持续的升级和优化,积累了800多个业务功能组件,还有各种PHP编写的公共基础库和脚本,代码规模也比较大。
我们对于PHP版本对代码的向下兼容的需求是比较高的,因此,就我们业务场景而言,PHP7良好的语法向下兼容,正是我们所需要的。因此,我们选择以PHP7为升级的方案。二、PHP7升级面临的风险和挑战对于一个已经现网在线的大型公共Web服务来说,基础公共软件升级,通常是一件吃力不讨好的工作,做得好,不一定被大家感知到,但是,升级出了问题,则需要承担比较重的责任。为了尽量减少升级的风险,我们必须先弄清楚我们的升级存在挑战和风险。
于是,我们整理了升级挑战和风险列表:
Apache2.0和PHP5.2这两个2008-2009年的基础软件版本比较古老,升级到Apache2.4和PHP7,版本升级跨度比较大,时间跨度相差7-8年,因此,兼容性问题挑战比较高。实际上,我们公司的现网PHP服务,很多都停留在PHP5.2和PHP5.3的版本,版本偏低。
AMS大量使用自研tphplib扩展,tphplib很早在公司内部就没有人维护了,这个扩展之前只有PHP5.3和PHP5.2的编译so版本,并且,部分扩展没有支持线程安全。支持线程安全,是因为我们以前的Apache使用了prefork模式,而我们希望能够使用Apache2.4的Event模式。
语法兼容性问题,从PHP5.2到PHP7的跨度过大,即使PHP官方号称在向下兼容方面做到99%,但是,我们的代码规模比较大,它仍然是一个未知的风险。
新软件面临的风险,将Apache和PHP这种基础软件升级到最新的版本,而这些版本的部分功能可能存在未知的风险和缺陷。
部分同学可能会建议采用Nginx会是更优的选择,的确,单纯比较Nginx和Apache在高并发方面的性能,Nginx的表现更优。但是就PHP的CGI而言,Nginx+php-ftpm和Apache+mod_php两者并没有很大的差距。另一方面,我们因为长期使用Apache,在技术熟悉和经验方面积累更多,因此,它可能不是最佳的选择,但是,具体到我们业务场景,算是比较合适的一个选择。三、版本升级实施过程1.高跨度版本升级方式从一个2008年的Apache2.0直接升级到2016年的Apache2.4,这个跨度过于大,甚至使用的的配置文件都有很多的不同,这里的需要更新的地方比较多,未知的风险也是存在的。于是,我们的做法,是先尝试将Apache2.0升级到Apach2.2,调整配置、观察稳定性,然后再进一步尝试到Apach2.4。所幸的是,Apache是一个比较特别的开源社区,他们之前一直同时维护这两个分支版本的Apache,因此,即使是Apache2.2也有比较新的版本。于是,我们先升级了一个PHP5.2+Apache2.2,对兼容性进行了测试和观察,确认两者之间是可以比较平滑升级后,我们开始进行Apache2.4的升级方案。PHP5.2的升级,我们也采用相同的思路,我们先将PHP5.2升级至PHP5.6,然后再将PHP5.6升级到PHP7,以更平滑的方式,逐步解决不同的问题。于是,我们的升级计划变为:Apache2.4编译为动态MPM的模式,根据现网风险等实时降级。Prefork、Worker、Event三者粗略介绍:prefork,多进程模式,1个进程服务于1个用户请求,成本比较高。但是,稳定性最高,不需要支持线程安全。
worker,多进程多线程模式,1个进程含有多个worker线程,1个worker线程服务于1个用户请求,因为线程更轻量,成本比较低。但是,在KeepAlive场景下,worker资源会被client占据,无法响应其他请求。
event,多进程多线程模式,1个进程也含有多个worker线程,1个worker线程服务于1个用户请求。但是,它解决了KeepAlive场景下的worker线程被占据问题,它通过专门的线程来管理这些KeepAlive连接,然后再分配“工作”给具体处理的worker,工作worker不会因为KeepAlive而导致空等待。
关于Event模式的官方介绍: 开启动态切换模式的方法,就是在编译的时候加上:
–enable-mpms-shared=all从PHP5.2升级到PHP5.6相对比较容易,我们主要的工作如下:
清理了部分不再使用的老扩展 解决掉线程安全问题 将cmem等api编译到新的版本
PHP代码语法基于PHP5.6的兼容
部分扩展的同步调整。apc扩展变为zend_opcache和apcu,以前的apc是包含了编译缓存和用户内存操作的功能,在PHP比较新版本里,被分解为独立的两个扩展。从PHP5.6升级到PHP7.0的工作量就比较多,也相对比较复杂,因此,我们制定了每一个阶段的升级计划:
技术预研,PHP7升级准备。
环境编译和搭建,下载相关的编译包,搭建完整的编译环境和测试环境。
兼容升级和测试。PHP7扩展的重新编译和代码兼容性工作,AMS功能验证,性能压测。
线上灰度。打包为pkg的安装包,编写相关的安装shell安装执行代码。然后,灰度安装到现网,观察。
正式发布。扩大灰度范围,全量升级。因为从PHP5.2升级到PHP5.6的过程中,很多问题已经被我们提前解决了,所以,PHP7的升级主要难点在于tphplib扩展的编译升级。
涉及主要的工作包括: PHP5.6的扩展到PHP7.0的比较大幅度改造升级
兼容apcu的内存操作函数的改名。PHP5的时候,我们使用的apc前缀的函数不可用了,同步变为apcu前缀的函数。语法兼容升级。实际上工作量不算大,从PHP5.6升级到PHP7变化并不多。我们大概在2016年4月中旬份完成了PHP7和Apache的编译工作,
4月下旬进行现网灰度,5月初全量发布到其中一个现网集群。2.升级过程中的错误调试方法在升级和重新编译PHP7扩展时,如果执行结果不符合预期或者进程core掉,很多错误都是无法从error日志里看见的,不利于分析问题。可以采用以下几种方法,可以用来定位和分析大部分的问题:
var_dump/exit
从PHP代码层逐步输出信息和执行exit,可以逐步定位到异常执行的PHP函数位置,然后再根据PHP函数名,反查扩展内的实现函数,找到问题。这种方法比较简单,但是效率不高。
gdb –p/gdb c
这种方法主要用于分析进程core的场景,我们采用的编译方式,是将mod_php,使用gdb
–p来监控Apache的服务进程。 命令:ps aux|grep 调试指定进程: 命令:gdb
-p使用c进行捕获,然后构造能够导致core的web请求:Apache通常是多进程模式,为了让问题比较容易复现,可以在里修改参数,将启动进程数修改为1个。当然还有一种更简单的方法,因为Apache本身就支持单进程调试模式的。
./apachectl -k start -X -e debug 然后再通过gdb –p来调试就更简单一些。
通过strace命令查看Apache进程具体在做了些什么事情,根据里面的执行内容,分析和定位问题。
strace -Ttt -v -s1024 -f -p pid
备注:执行这些命令,注意权限问题,很可能需要root权限。四、PHP5.6到PHP7.0扩展升级实践记录1.
数据类型的变化zval
php7的诞生始于zval结构的变化,PHP7不再需要指针的指针,绝大部分zval**需要修改成zval*。如果PHP7直接操作zval,那么zval*也需要改成zval,Z_*P()也要改成Z_*(),ZVAL_*(var,
…)需要改成ZVAL_*(var,
…),一定要谨慎使用符号,因为PHP7几乎不要求使用zval*,那么很多地方的也是要去掉的。
ALLOC_ZVAL,ALLOC_INIT_ZVAL,MAKE_STD_ZVAL这几个分配内存的宏已经被移除了。大多数情况下,zval*应该修改为zval,而INIT_PZVAL宏也被移除了。

全局配置

CentOS主配置文件:/etc/php-fpm.conf建议修改默认配置:

 emergency_restart_threshold = 10 // 指定时间内,失效的PHP-FPM子进程超过这个值,让PHP-FPM主进程优雅重启 emergency_resttart_interval = 1m // 指定时间跨度

更改测试基础设施

我们为我们在Badoo上做测试感到特别骄傲。我们部署服务器的PHP代码到产品环境,每天两次,每次部署包含20-50份任务量(我们使用功能分支Git和自动化紧JIRA集成版本)。鉴于这种时间表和任务量,我们没有办法不选择自动测试。目前,我们大约有6万个单元测试,约50%的覆盖率,其运行在云上,平均2-3分钟(参见我们的文章了解更多)。除了单元测试,我们使用更高级别的自动测试,集成和系统测试,并为网页做了Selenium测试,为手机客户端做了Calabash测试。作为一个整体,这使我们能够迅速达成与结论有关的代码,每个具体版本的质量,并应用相应的解决方案。

切换到新版本的解释器是一个充满潜在问题的重大变化,所以所有测试工作都是极其重要的。为了弄清我们到底做了什么,以及我们如何设法做到这一点,让我们来看看近几年测试开发在Badoo上是如何演变的。

通常,当我们开始考虑实施产品测试(或在某些情况下,已经开始实施的话)时,在测试过程中我们会发现他们的代码“并没有达到测试阶段”。出于这个原因,在大多数情况下,开发者在写代码时要牢记,代码的可测试性是很重要的。架构师应允许用单元测试去取代调用和外部依赖对象,以便代码测试能与外部环境相隔离。当然,毫无疑问这是一个备受憎恨的要求,很多程序员认为写“可测试性”的代码是完全不可接受的。他们认为,这些限制完全不顾“优秀代码”的标准而且通常不会取得成功。你能想象到,大量不按规则编写的代码,导致测试为了等“一个更好的时机”被延迟,或者通过运行小型测试来满足并且在测试结果被推迟,或实验者为了使自己运行的小测试能够通过,只做了能够通过的那部分(也就是指测试没有产生预期的结果)。
我并不是说我们公司是一个例外,从一开始,我们的项目也未执行测试。因为依然有几行代码在生产过程中正常运作,带来效益,所以正如文献中建议的,如果只是为了运行测试重写代码将是一件愚蠢的事情。那将占用太长的时间,花费太多。

幸运的是我们有一个很棒的工具来解决“未测试代码”的大问题——runkit。当脚本在运行时,这个
PHP
扩展允许你对方法、类及函数进行增、删、改的操作。此工具还有很多其它的功能但我们这里用不到它们。从
2005 年到 2008 年这个工具由 Sara Goleman(就职于
Facebook,有趣的是他在做 HHVM 方向的工作)开发和支持了多年。从 2008
年至今则由 Dmitri Zenovich (带领 Begun 和 Mail.ru
的测试部门)进行维护。我们也对这个项目做了些许贡献。

同时,runkit
是一个非常危险的扩展,它允许你在使用它的脚本在运行的时候对常量、函数及类进行修改。就像是一个允许你在飞行中重建飞机的工具。runkit
有直达 PHP “心脏”的权力,一个小错误或缺陷就能让一切毁掉,导致 PHP
失败或者你要用很多时间来查找内存泄漏或做一些底层的调试。尽管如此,这个工具对于我们的测试还是必要的:不需要做大的重构来完成项目测试只能在程序运行的时候改变代码来实现。

但是在切换到PHP7的时候发现runkit带来了很大麻烦,因为它并不支持新的版本。我们当然也可以在新版本中添加支持,但是从长远考虑,这看起来并不是最可靠的解决途径。因此我们选择了其他方法。

最适合的方法之一就是从runkit迁移到uopz。后者也是PHP的扩展,有着(与runkit)类似的功能性,于2014年正式推出。我在Wamba的同事建议使用uopz,它将有很好的速度体验。顺便说一下uopz的维护者就是Joe
Watkins(First Beat
Media公司,英国)。不幸的是我们迁移到uopz的测试程序无论怎样都无法成功运行。在某些地方总会发生致命的错误,出现在段错误中。我们提交了一些报告,但很遗憾他们并没有动作(e.g.
)。为了解决这种困境而重写测试程序的付出将会非常高昂,即使重写了也很容易再次暴露出问题。

鉴于我们不得不重写大量的代码,而且还要依赖于runkit和uopz这种不知道有没有问题的项目。很明显,我们有了结论:我们应该重写我们的代码,而且要尽可能独立。我们也承诺将尽一切可能来避免今后发生类似的问题,即使我们最终切换到HHVM或任何类似的产品。最终我们做出来了自己的框架。
我们的系统名为“SoftMocks”,“soft”意思是纯php实现,未使用扩展。该项目目前是一个开源的php库。
SoftMocks不跟PHP引擎绑定,它是在运行中动态重写代码,功能类似于Go语言的AOP!框架。
以下功能在我们的代码里已经测试过:

  1. override类方法
  2. 覆盖函数执行结果
  3. 更改全局常量或类常量的值
  4. 类新增方法

所有这些东西都是用runkit实现的。动态修改代码使项目临时变更有了可能性。

我们没有更多篇幅来讨论关于SoftMocks的细节,但我们计划写一篇关于这个主题的文章。
这里我们给出一些关键点:

  • 通过重写中间函数来适配原有的用户代码。因此所有的包含操作将自动被中间函数重写。
  • 在每一个用户定义的方法内都增加了是否有重写的检查。如果存在重写,相应的重写代码就会被执行。
    原来直接函数调用的方式将被通过中间函数调用的方式所替换;这样内嵌函数和用户自定义函数都能被执行到。
  • 对中间函数的动态调用将覆盖代码中变量的访问权限

SoftMocks 可以和 Nikita Popov’s
的 PHP-Parser 配合:
这个库不是很快(解析速度大概比token_get_all
慢15倍),但他的接口让你绕过语法解析树,并且包含了一个方便的API
用来处理不确定的语法结构。

现在让我们回到本文主题:切换到PHP 7.0版本。
 当我们通过SoftMocks把整个项切换过来后,我们依然有1000多个测试需要手动处理。你可以说这还不算太差的结果,和我们在开始时提到的60000个测试相比的话。
和runkit相比,测试速度没有下降,所以SoftMocks并没有性能问题。
为了公平起见,我们认为uopz 明显的快很多。

尽管PHP7包含了许多新功能,但是仍然存在一些与老版本兼容的问题。首要的解决办法是阅读官方的移植文档,之后我们会马上明白如果不去修改现有代码,我们将会面对的不仅仅是在生产环境中遇到致命的未知错误并且由于升级后代码的改变,我们无法在日志中查找到任何信息。这将会导致程序无法正常运行。

Badoo中有许多PHP代码仓库,其中最大的有超过2百万行代码。此外,我们还使用PHP实现了很多功能,从网站业务逻辑到手机应用后段再到集成测试和代码部署。就目前来说,我们的情况很复杂,毕竟Badoo有很长的历史,我们使用它已经快十年了,最不幸的是仍然有采用PHP4的环境在运行。在Badoo中,我们不推荐用‘just
stare at it long
enough’的方式来发现问题。一套所谓的’Brazilian’系统将代码部署在生产环境,你需要等待直到它发生错误,这很容易引发大面积用户在使用中遇到业务上的错误,使其不明原因。综上所诉,我们开始寻找一种方法能自动发现不兼容的地方。

最初,我们试图用IDE的,这是开发者中很受欢迎,但不幸的是,他们要么不支持PHP7的语法和特征,要么没有函数可以在代码中找到所有的明显的危险的地方,发现所有明显危险的地方。进行了一些研究(如谷歌搜索)后,我们决定尝试php7mar工具,它是用PHP实现一个静态代码分析仪。这PHP7工具使用起来非常简单,很快工程,并为您提供了一个文本文件。当然,它不是万能的;
找特别是精心隐藏的问题点。尽管如此,该实用程序帮助我们铲除约
90%的问题,大大加快和简化了准备 PHP7 的代码的过程。

对我们来说,最常遇到的和潜在危险的问题是以下内容:

  • 在func_get_arg()以及func_get_args的行为变化()。在PHP的第5版本中,这些功能中的传输的时刻返回参数值,但在七个版本发生这种情况的时刻时func_get_args()被调用。换句话说,如果函数内func_get_args前参数变量的变化()被调用,则该代码的行为可以由五个版本不同。同样的事情发生时,应用程序的业务逻辑坏了,但并没有什么在日志中。
  • 间接访问对象变量,属性和方法。并再次,危险在于,该行为可以更改“静默”。对于那些寻找更多的信息,版本间的差异进行了详细的描述在这里。

     

  • 使用保留类名。在PHP7,可以不再使用布尔,整型,浮点,字符串,空,真假类名称。,是的,我们有一个空的类。它的缺席实际上使事情变得更容易,但因为它常常导致错误。

     

  • 使用引用许多潜在的问题的foreach结构被发现了。由于我们试图早不改变迭代数组中的foreach或虽在其内部指针数,几乎所有的人都表现在版本5和7相同。

剩余的不兼容性的情况下也很少遇到了 (像 ‘e’
修饰符在正则表达式),或他们固定的一个简单的替换
(例如,现在所有构造函数应该被命名为
__construct()。类名称不允许使用)。
但是,我们即使在开始修复代码之前,我们很担心,一些开发商做一些必要的兼容性变化,其他人会继续写不符合
PHP7 的代码。为了解决这一问题,我们把 pre-receive 钩在已更改的文件
(换句话说,确保语法匹配 PHP7) 上执行 php7-l 在每一个 git
存储库中。这并不能保证不会有任何兼容性问题,但它不会清除主机问题。在其他情况下,开发人员只是不得不变得更加专注。除此之外,我们开始在
PHP7 上运行的测试整个集并与 PHP5 的结果进行了比较。

此外,开发者不允许使用任何PHP7的新功能,例如,我们没有禁止老版本的预接收钩子
php5
-l。这允许我们让代码兼容PHP5和PHP7。为什么这个很重要?因为除了php代码的问题之外,还有PHP7极其自身扩展的一些潜在的问题(这些都可以证实)。并且不幸的是,不是所有的问题都可以在测试环境中重现出来;有一些我们只在产品的大负载时才见过。

我并不是说我们公司是一个例外,从一开始,我们的项目也未执行测试。因为依然有几行代码在生产过程中正常运作,带来效益,所以正如文献中建议的,如果只是为了运行测试重写代码将是一件愚蠢的事情。那将占用太长的时间,花费太多。

字符串类型PHP5.6版本中使用char* +
len的方式表示字符串,PHP7.0中做了封装,定义了zend_string类型:

capistrano的工作方式

capistrano会在远程服务器中保存之前部署的应用,而且每次部署的版本放在各自的目录中。capistrano还会创建一个current/目录,通过符号连接指向当前部署的应用所在的目录。当部署应用时,capistrano会首先从git仓库获取最新代码,然后把代码放到realeases/的一个新子目录,然后把current/符号连接指向新目录。

  • Deployer
  • Magallanes
  • Rocketeer

从长远来看,测试省钱,省精力

  • 开发前:把测试工具当做项目开发的重要依赖
  • 开发中,每个功能都要编写并运行测试
  • 开发后,编写新测试,确保修补缺陷的方式是正确的

单元测试和功能测试

  • 单元测试:使用PHPUnit或者PHPSpec
  • 测试驱动开发: 编写之前写测试,再开发,然后再写测试,再开发
  • 行为驱动开发: 编写故事,描述应用的表现。
    • SpecBDD:也是单元测试,使用人类能读懂的语言。比如PHPUnit风格测试命名为testRenderTemplate(),
      等价SpecBDD命名为itRendersTheTemplate(),
      而且会使用诸如$this->shouldReturn()、$this->shouldbe()之类易于理解的辅助方法。
    • StoryBDD:类似,但是更多关注整体行为。StoryBDD用于测试产品经理的需求(要生成报告,并且电子邮件发送给用户),SpecBDD测试开发的需求(这个类方法只能接收一个数组)

术语:PHPUnit测试在一起组成测试用例(test
case),测试用例在一起组成测试组件(test
suite),PHPUnit会使用测试运行程序(test runner)运行测试组件。

一个测试用例是一个PHP类(且以Test结尾,文件名以Test.php结尾),扩展自PHPUnit_Framework_TestCase类。测试用例中有一些以test开头的公开方法,一个方法是一个测试,在方法中我们断言会发生什么事。断言可能通过也可能失败,目标是使断言都通过。

测试运行程序默认使用命令行运行程序,调用phpunit命令。

HHVM的试验

在切换到PHP7之前,我们曾花了不少时间来寻找优化后端的方法。当然,第一步就是从HHVM下手。在试验了几周之后,我们获得了值得关注的结果:在给框架中的JIT热身之后,我们看到速度与CPU使用率上升了三倍。

另一方面,HHVM 被证实有一些严重的缺点:

  • 部署困难而且慢。在部署过程中,你不得不首先启动JIT-cache。当机器启动的时候,它不能负载产品流量,因为所有的事情进行的相当慢。HHVM
    团队同样不推荐启动并行请求。顺便一提,大量聚类操作在启动阶段并不快速。此外,对于几百个机器构成的大集群你必须学习如何分批部署。这样体系结构和部署过程相当繁琐,而且很难估算出所需要的时间。对于我们来说,部署应该尽可能简单快捷。我们的开发者将在同一天提供两个开发版并且释出许多补丁。
  • 测试不便。我们非常依赖runkit扩展,但是它在HHVM中却不可用。稍后我们将详细介绍runkit,但是无需多言,它是一个能让你几乎随心所欲更改变量、类、方法、函数行为的扩展。这是通过一个抵达PHP核心的集成来实现的。HHVM引擎仅仅显示了略微相像的PHP外观,但是他们各自的核心十分不同。鉴
    于扩展的特定功能,在HHVM上独立地实现runkit异常困难,而且我们不得不重写数万测试用例以确保HHVM和我们的代码正确的工作。这看起来似乎不
    值得。公平的说,我们以后在处理所有其他选项时也会遇到同样的问题,而且我们在迁移到PHP7时仍然要重做许多事情包括摆脱runkit。但是以后会更多。
  • 兼容性。主要问题是不完全兼容PHP5.5(参考此处)
    ,并且不兼容现有的扩展(许多PHP5.5的)。这些所有的不兼容性导致了这个项目的明显缺点:
    HHVM
    不是被大社区开发的,相反只是Facebook的一个分支。在这种情况下公司很容易不参考社区就修改内部规则和标准,而且大量的代码包含其中。换句话说,
    他们关起门来利用自己的资源解决了问题。因此,为了解决相似的问题,一个公司需要有Facebook一样的资源不仅投入最初的实现同样要投入后续支持。这
    个提议不仅有风险而且可能开销很大,所以我们决定拒绝它。
  • 潜力。尽管Facebook是一个大公司而且拥有无数顶尖程序员,我们仍然怀疑他们的HHVM开发者比整个PHP社区更强。我们猜想PHP的类似于HHVM的东西会很快出现,而前者将慢慢淡出我们的视野。

让我们耐心等待PHP7。

切换到新版本的PHP7解释器是一个重要和艰难的过程,我们准备建立一个精确的计划。这个计划包括三个阶段:

  • 修改PHP构建/部署的基础设施和为大量的扩展调整现有的code
  • 改变基础设施和测试环境
  • 修改PHP应用程序的代码。

我们稍后会给出这些这些阶段的细节。

PHP的Web应用,处理器的消耗跟其他动态高级语言一样多。但是PHP开发者面对着一个特别的障碍(这让他们成为其他社区恶意攻击的的受害者):缺少JIT,至少没有一个像C/C++语言那样的可编译文本的生成器。PHP社区无力在核心项目框架上去实现一个类似的解决方案更是树立了一种不良的风气:主要的开发成员开始整合他们的解决方案,所以HHVM在Facebook上诞生了,KPHP在VKontakte上诞生,还有其他类似的方案。幸运地是,在2015年,随着PHP7的正式发布,PHP要开始”Grow
up”啦。虽然还是没有JIT,但很难去评定这些改变在”engine”中有多重要。现在,尽管没有JIT,PHP7可以跟HHVM相匹敌(Benchmarks
from the LightSpeed
blogorPHP
devs
benchmarks)。新的PHP7体系架构将会让JIT的实现变得简单。

/* 7.0zval结构源码 *//* value字段,仅占一个size_t长度,只有指针或double或者long */typedef union _zend_value { zend_long lval; /* long value */ double dval; /* double value */ zend_refcounted *counted; zend_string *str; zend_array *arr; zend_object *obj; zend_resource *res; zend_reference *ref; zend_ast_ref *ast; zval *zv; void *ptr; zend_class_entry *ce; zend_function *func; struct { uint32_t w1; uint32_t w2; } ww;} zend_value;struct _zval_struct { zend_value value; /* value */ union { 。。。 } u1;/* 扩充字段,主要是类型信息 */ union { … … } u2;/* 扩充字段,保存辅助信息 */};

禁用密码,禁止根用户登录

这样最安全

 // /etc/ssh/sshd_config PassWordAuthentication 设置为no PermitRootLogin 设置为no

PHP FastCGI Process Manager(PHP
FastCGI进程管理器)。它会创建一个主进程,控制何时以及如何把HTTP请求转发给一个或多个子进程处理。PHP-FPM还需控制何时创建、销毁PHP子进程。

图片 4

测试不便。我们非常依赖runkit扩展,但是它在HHVM中却不可用。稍后我们将详细介绍runkit,但是无需多言,它是一个能让你几乎随心所欲更改变量、类、方法、函数行为的扩展。这是通过一个抵达PHP核心的集成来实现的。HHVM引擎仅仅显示了略微相像的PHP外观,但是他们各自的核心十分不同。鉴
于扩展的特定功能,在HHVM上独立地实现runkit异常困难,而且我们不得不重写数万测试用例以确保HHVM和我们的代码正确的工作。这看起来似乎不
值得。公平的说,我们以后在处理所有其他选项时也会遇到同样的问题,而且我们在迁移到PHP7时仍然要重做许多事情包括摆脱runkit。但是以后会更多。

zend_hash_exists、zend_hash_find对所有需要字符串参数的函数,PHP5.6中的方式是传递两个参数,而PHP7.0中定义了zend_string,因此只需要一个zend_string变量即可。返回值变成了zend_bool类型:

  • 共享服务器
  • 虚拟私有服务器VPS
  • 专用服务器
  • PaaS

RUsage (CPU 时间):

我们稍后会给出这些这些阶段的细节。

zend_string和char*的转换:

使用SSH密钥对认证方式登录远程设备时,远程设备随机创建一个消息,使用公钥加密,然后把密文发给本地设备,本地设备收到密文后使用私钥解密,然后把解密后的消息发给远程服务器。远程服务器验证解密后的消息之后,再赋予你访问服务器的权限。

图片 5

对中间函数的动态调用将覆盖代码中变量的访问权限

数组

hack两者兼有

hack基本兼容PHP

查了下最新的情况,PHP7性能卓越,Hack优势不明显了,前景不明。

以上就是这本书的精华,不过瘾的话强烈推荐购买。欢迎交流

引擎和扩展的变化

在Badoo中, 我们有积极的支持和更新的PHP分支,我们在PHP7正式版release之前我们就已经开始切换到php7了. 所以我们不得不在我们的代码树经常整合(rebase)PHP7上游的代码,以便它来更新每个候选发布版。我们每天在工作中所用的补丁和自定义的code都需要在两个版本之间进行移植。

下载和构建依赖库、扩展程序、还包括PHP 5.5和7.0的构建这些过程都是自动化的完成的。这不仅简化了我们目前的工作,也预示着未来:在版本7.1出来时,
也许这一切(解析引擎和扩展等等)都已经准备到位了;

如上所述,我们将注意力转向扩展。我们提供超过70种扩展,已经比基于我们产品改写的开源产品的半数还要多。

为了尽快能够切换到它们,我们已经决定开始同时进展两件事情。第一个是逐一重写各个关键扩展,包括blitz模板引擎,共享内存/APCu中的数据缓存,pinba数据分析采集器,以及其他内部服务的自定义扩展(总的来说,我们已经通过自己的力量完成大概20种扩展的重写了)。

第二个是积极的清理仅仅在架构中那些非关键部分使用的扩展,让整个架构更加简洁。我们已经迅速清理了11种扩展,都是那些无足轻重的!

另外,我们也同那些维护主要开放扩展的作者,一起积极地讨论PHP7的兼容性(特别感谢xdebug的开发者Derick
Rethans)。

我们迟点将进入更详细的关于移植PHP7扩展的技术细节。

开发者已经对PHP7中的内部API做了大量修改,意味着我们可以修改大量的扩展代码了。

下面是几个最重要的变更:

  • zval * ->
    zval。在早期的版本中,zval一直为新变量来分配内存,但是现在引入了栈。
  • char * ->
    zend_string。PHP7的引擎使用了更先进的字符串缓存机制。理由是,当字符串与自身的长度同时存储时,新的引擎可以将普通字符串完整的转换为zend-string格式。
  • 数组API的改变。zend_string作为key来使用,同时基于双向链表的数组实现方法也被替代为普通的数组,需要强调的是,数组占用一个大的文件块,而不是很多小的空间。

所有这些都可以从根本上减少小型内存分配的数量,结果是,提高PHP引擎2%的速度。

我们能够注意到,所有这些修改都至少需要改变所有的扩展(即使不是完全重写)。虽然我们可以依赖内置扩展的作者进行必要的修改,我们也当然有责任自己修改他们,虽然工作量很大。由于内部API的修改,使得只修改一些代码段变得简单。

不幸的是,引入使代码执行速度提升的垃圾回收机制让引擎变得更加复杂并且变得更加难以定位问题。涉及到OpCache的问题。在缓存刷新期间,当可用于别的进程的已缓存的文件字节码在此时损坏,就会导致崩溃。这就是它从外部看起来的样子(zend_string):使用方法名或者常量突然崩溃并且垃圾就会出现。

鉴于我们使用了大量的内部扩展,其中许多处理都是专门针对字符串的,我们怀疑这个问题与如何使用字符串在内部扩展有关。我们写了大量的测试,并进行了大量的实验,但没有得到我们预期的结果。最后,我们从PHP引擎开发人员 Dmitri
Stogov 那里寻求了帮助。
他的第一个问题是“你有没有清除缓存?”我们解释说,事实上,我们每一次都在清除缓存。在这一点上,我们意识到这个问题并不在我们这里,而是opcache。我们很快就转载了这一案例,这有助于我们在几天内回复并解决这个问题。在7.0.4版本,这个修复没有出来,就不可能使php7进入稳定产品。

override类方法

其中,PHP7在zend_hash.h中定义了一系列宏,用来操作数组,包括遍历key、遍历value、遍历key-value等,下面是一个简单例子:

安装

PHPUnit用于测试,用composer安装;XDebug用于生成覆盖度信息,是PHP扩展,用包管理器安装。

紧接着,书中有一个具体的测试用例,用的时候找更详细的blog看看吧

原生提供钩子,可以集成github仓库,每次提交后,都能自动测试,并在多个版本中测试。

指的是分析应用的性能。

什么时候使用?

当遇到性能瓶颈时再使用。

  • 在开发环境:XDebug。它的结果人类读不懂,需要KCacheGrind或者WinCacheGrind形象化展示。
  • 在生产环境:XHprof,使用XHGUI展示结果。

为节省资源,配置成触发执行,具体配置略

接下来讨论的是PHP的未来。

传统的PHP解释器是Zend Engine, HHVM(Hip Hop Virtual
Machiane)由Facebook开发,目的是提高性能,HHVM先把PHP代码转换成字节码,然后缓存字节码,然后使用JIT编译器(Just
in
Time)转换并优化成x86_64机器码。这样传统的解释型语言就有了一些编译型语言的速度。JIT提供了很多底层性能优化。

HHVM和Zend Engine是等价的。相当于PHP+PHP-FPM。

HHVM配置也是用php.ini文件

推荐使用Supervisord监控,HHVM挂掉后立即重启。

他们把自己看做PHP的方言,为PHP引入了新的数据类型和结构,以及静态类型。

CPU 加载 (%)-移动后台集群

我们的系统名为“SoftMocks”,“soft”意思是纯php实现,未使用扩展。该项目目前是一个开源的php库。
SoftMocks不跟PHP引擎绑定,它是在运行中动态重写代码,功能类似于Go语言的AOP!框架。

整型直接切换即可:long-zend_long

因为使用密码登陆有漏洞,尽量使用SSH密钥对认证。SSH密钥对登录流程如下:

char *
->Zend_string。
PHP7的引擎使用了更先进的字符串缓存机制。理由是,当字符串与自身的长度同时存储时,新的引擎可以将普通字符串完整的转换为zend-string格式。

图片 6

从PHP转向Hack

<?php改成<?hh

另外,我们也同那些维护主要开放扩展的作者,一起积极地讨论PHP7的兼容性(特别感谢xdebug的开发者Derick
Rethans)。

/* 例子 */zend_string * key; key = zend_string_init("key",sizeof("key"), 0);zend_bool res_key = zend_hash_exists(itmeArr, key);

一般选择nginx。因为apache为每个PHP请求派生一个子进程,比较耗资源。

使用引用许多潜在的问题的foreach结构被发现了。由于我们试图早不改变迭代数组中的foreach或虽在其内部指针数,几乎所有的人都表现在版本5和7相同。

/* 例子 */struct clogger_object { CLogger *logger; zend_object std;// 放在后面};/* 使用偏移量的方式获取对象 */static inline clogger_object *php_clogger_object_from_obj(zend_object *obj) { return (clogger_object*)((char*)(obj) - XtOffsetOf(clogger_object, std));}#define Z_USEROBJ_P(zv) php_clogger_object_from_obj(Z_OBJ_P((zv)))/* 释放资源时 */void tphp_clogger_free_storage(zend_object *object TSRMLS_DC){ clogger_object *intern = php_clogger_object_from_obj(object); if (intern-logger) { delete intern-logger; intern-logger = NULL; } zend_object_std_dtor(intern-std);}

配置进程池

让各个PHP-FPM进程池都以指定的操作系统用户和用户组的身份运行,每个PHP用户一个非根用户,这样查看和管理都很方便。

引擎和扩展的变化

zend_string *str;char *cstr = NULL;size_t slen = 0;//.../* 从zend_string获取char* 和 len的方法如下 */cstr = ZSTR_VAL(str);slen = ZSTR_LEN(str);/* char* 构造zend_string的方法 */zend_string * zstr = zend_string_init("test",sizeof("test"), 0);

目标:安装Web服务器,以便接收HTTP请求;设置并管理一组PHP进程,处理PHP请求,进程可以与web服务器通信。

内存使用:

/* 例如 */zend_string *zstr;if (zend_parse_parameters(ZEND_NUM_ARGS() , "S", zstr) == FAILURE){ RETURN_LONG(-1);}

然后作者展示了一个登陆VPS的例子:需要ssh登陆、创建非根用户管理web服务器,不要使用root

对我们来说,最常遇到的和潜在危险的问题是以下内容:

PHP7.0中,将zend_rsrc_list_entry结构升级为zend_resource,在新版本中只需要修改一下参数名称即可。二级指针宏,即Z_*_PPPHP7.0中取消了所有的PP宏,大部分情况直接使用对应的P宏即可。zend_object_store_get_object被取消根据官方wiki,可以定义如下宏,用来获取object,实际情况看,这个宏用的还是比较频繁的:

适合在一台电脑中登录远程,多台不适合。

最适合的方法之一就是从runkit迁移到uopz。后者也是PHP的扩展,有着(与runkit)类似的功能性,于2014年正式推出。我在Wamba的同事建议使用uopz,它将有很好的速度体验。顺便说一下uopz的维护者就是Joe
Watkins(First Beat
Media公司,英国)。不幸的是我们迁移到uopz的测试程序无论怎样都无法成功运行。在某些地方总会发生致命的错误,出现在段错误中。我们提交了一些报告,但很遗憾他们并没有动作(e.g.https://github.com/krakjoe/uopz/issues/18)。为了解决这种困境而重写测试程序的付出将会非常高昂,即使重写了也很容易再次暴露出问题。

struct _zend_string { zend_refcounted_h gc; zend_ulong h; /* hash value */ size_t len; char val[1];};

现在让我们回到本文主题:切换到PHP 7.0版本。
 当我们通过SoftMocks把整个项切换过来后,我们依然有1000多个测试需要手动处理。你可以说这还不算太差的结果,和我们在开始时提到的60000个测试相比的话。
和runkit相比,测试速度没有下降,所以SoftMocks并没有性能问题。
为了公平起见,我们认为uopz 明显的快很多。

/* php7.0 zend_object 定义 */struct _zend_object { zend_refcounted_h gc; uint32_t handle; zend_class_entry *ce; const zend_object_handlers *handlers; HashTable *properties; zval properties_table[1];};

使用保留类名。在PHP7,可以不再使用布尔,整型,浮点,字符串,空,真假类名称。,是的,我们有一个空的类。它的缺席实际上使事情变得更容易,但因为它常常导致错误。

zend_object是一个可变长度的结构。因此在自定义对象的结构中,zend_object需要放在最后一项:

Author

发表评论

电子邮件地址不会被公开。 必填项已用*标注