咱们为何要迁移PHP到HHVM

咱们为何要迁移PHP到HHVM

程序员日志 · 2014-12-26 18:33php

咱们为何要迁移PHP到HHVM

简介


该调研是2013年10月份作的,目标是寻找更好的PHP引擎,来代替百度各产品线正在使用的PHP 5.2。html

环境说明


机器环境:前端

  • cpu: Intel(R) Xeon(R) CPU E5-2620 0 @ 2.00GHz, 12核。git

  • 内存:64G程序员

引擎:github

  • php 5.2.17 (当时百度所用版本)web

  • php 5.5.4 (当时最新版本)json

  • hhvm 2.3-dev (当时最新版本)ubuntu

为了公平起见,三个引擎都采用-O2的编译优化选项。后端

加速器:

  • php5.2.17:采用eaccelerator

  • php5.5.4:eacc不可用,采用自带的zend opcache

  • hhvm:内置opcode缓存,开启jit

扩展:

因为目前的百度扩展只有不多移植到了hhvm,因此为了公平起见,其它百度扩展也在php5.2和php5.5中禁用,而采用纯php的方式实现,实践证实采用纯php实现性能并未有太大损失。

性能


下面用了不一样的场景,来比较PHP引擎的性能。

场景一:纯cpu计算

用php官方提供的测试脚本:

  • bench.php : https://github.com/php/php-src/blob/master/Zend/bench.php

  • micro_bench.php : https://github.com/php/php-src/blob/master/Zend/micro_bench.php

  • 第三方提供的测试脚本bench_third.php : http://www.php-benchmark-script.com/

测试结果以下:

引擎 bench.php 耗时 micro_bench.php 耗时 bench_third.php 耗时
php5.2 6.692s 41.890s 9.226s
php5.5 3.609s 14.972s 5.893s
hhvm 0.579s 5.832s 2.869s

分析:php历次新版本对性能都有优化,所以php5.5在纯cpu计算上比php5.2有明显优点。而hhvm采用jit机制,将php转化为本地代码执行,因此性能上比执行opcode的php5.5还要快上不少。

结论:对于纯cpu型计算,hhvm>>php5.5>>php5.2。

场景二:简单http服务

简单的http服务即由一个简单的php逻辑接口层加一个后端C模块(或通用存储)构成的服务,这里用了百度内部一个实际的简单服务为例。

简单作了一下性能测试,client并发10,client与service同机部署,service与后端C模块不一样机部署。结果以下:

引擎 平均响应时间 Cpu idle Qps
php5.2 3.6ms 50% 1900
php5.5 2.9ms 60% 2500
hhvm 2.0ms 60% 3900

分析:对于简单http服务,自身也有一部分的逻辑计算,除此以外,hhvm是webserver与php引擎一体化,不须要 webserver->php这一层的开销,所以在响应时间和qps上有更明显的优点。因为C模块后端自己响应时间较短(1ms),因此不一样引擎的 总体响应时间的区别就比较明显。

结论:简单http服务,在qps上hhvm>>php5.5>php5.2,在响应时间上,除掉后端服务耗时,也是hhvm>>php5.5>php5.2。

场景三:产品前端UI

这里用了贴吧的最新版ui,串行访问后端。

采用20个并发,测试结果以下:

引擎 总体耗时 除访问后端以外的耗时 idle qps
php5.2 520ms 127ms 50% 40
php5.5 500ms 107ms 45% 45
hhvm 470ms 72ms 65% 50

分析:ui大部分时间消耗在后端服务访问,这方面引擎不起做用。而另外一方面,除后端服务外的耗时也很高,这部分对cpu消耗较大,致使qps较低。

显然,这个效果并非很符合咱们的预期,为了达到理想的qps,咱们须要想方法进一步下降除后端以外的耗时。

首先咱们在PHP5.2下运行xhprof,找出了一些较耗时的函数,并进行了优化:

  1. 去掉没必要要的编码转换,减小15ms

  2. 去掉没必要要的warning日志,耗时减少4.3ms

  3. 改进xss转码函数实现,耗时减小1.8ms

经过上面几个优化,HHVM下ui的耗时降到了52ms,其中模板耗时34ms。可是这样仍不使人满意,如何进一步优化呢?

既然上面的xhprof是在PHP5.2下执行的,那咱们尝试直接在HHVM下运行xhprof会如何?结果发现,HHVM下xhprof的结果与PHP5.2下有很大不一样,发现了一些新的优化点,进行了优化:

  1. 有好几个函数会在每一个请求中重复计算一样的信息,加上apc cache以后,耗时减少16ms

  2. 用户自定义的errorHandler,很耗时去掉后耗时减少7ms

  3. 去掉一些debug日志,耗时减少1ms

经过上面的优化,咱们将HHVM下ui的耗时降到了26ms。那么,一样的优化,做用在PHP5.2或PHP5.5下又如何呢?

引擎 优化前 业务优化后
php5.2 127ms 103ms
php5.5 107ms 87ms
hhvm 72ms 26ms

使人失望。。。究其缘由,是由于在php下耗时在各函数的分布至关分散,即便优化个别函数,也难以有大辐提高。

而在hhvm下,因为引擎自己性能较高,所以一些原来实现得不合理而比较耗时的函数就突显出来了,所以针对这些函数进行优化,能够取得更加明显的效果。

结论:对于产品前端UI,引擎能够在必定程度上优化响应时间和qps,hhvm>php5.5>php5.2,如再结合一些针对hhvm的优化,能够大幅提高hhvm下的qps。

兼容性


语言兼容性


语言方面的兼容性来自两个方面:

php不一样版本的语法差别

hhvm是基于php5.4的语法标准,所以,hhvm和php5.5与咱们目前用的php5.2都存在语法差别,php5.5差别更大一些。

目前所遇到的差别个数以下:

引擎 影响处理结果 不影响结果,打warning
php5.5 1个 1个
hhvm 1个 1个

全部差别可见这里:

  • http://www.php.net/manual/en/migration53.php

  • http://www.php.net/manual/en/migration54.php

  • http://www.php.net/manual/en/migration55.php

hhvm与zend引擎之间的实现差别

因为是两套不一样实现,所以hhvm与zend引擎也有差别。

目前遇到的差别数以下:

影响处理结果 不影响结果,打warning
2个 0个

hhvm文档也提到了一些差别:https://github.com/facebook/hhvm/blob/master/hphp/doc/inconsistencies

结论:整体上,hhvm与php5.5在语言方面与php5.2都存在一些差别,而且对处理结果形成影响。不过,大部分的差别都会致使执行时报fatal或warning,咱们只需根据相应提示修改代码便可,改动成本不大。

扩展兼容性


php5.5

将原百度用到的扩展在php5.5下编译,大部分能编译经过,少数编译失败:

  1. 升级到最新版本可解决,5个

  2. 修改代码解决,2个

hhvm

hhvm内置了不少经常使用的第三方扩展,所以对于第三方扩展,基本无须迁移。主要须要考虑的是百度扩展的迁移。

hhvm编写扩展有两种方式:

1、静态编译

  1. 编写扩展的idl文件(json格式)

  2. 根据idl自动生成代码框架

  3. 填充代码框架,实现本身的逻辑

  4. 从新编译hhvm

缺点:

  1. 现有百度扩展须要从新改造,与获取输入参数、返回结果相关及其它调用到php.h中的api的地方都须要重写。这是主要的成本。

  2. hhvm的api目前还不太稳定,2.1.0下编写的扩展,在2.2.0下就编译不经过了。。

优势:

  1. 新扩展编写,比在zend下编写更加方便,hhvm提供相似于boost variant的api,处理输入输出很方便

2、动态加载(HNI:hhvm native interface)

  1. 编写函数声明.php(语法与php很像)

  2. 编写函数实现.cpp

  3. hphpize && cmake . && make,只须单独编译扩展

动态加载更为方便,所以推荐使用这种方式编写扩展。

3、ZendCompatLayer

hhvm正在实现一个ZendCompatLayer,即兼容zend扩展的一个层,实现zend引擎相关api,以方便现有扩展迁移到hhvm。具体见:https://github.com/facebook/hhvm/blob/master/hphp/doc/php.extension.compat.layer

按照其描述,zend扩展能够不作太多修改,便可迁移到hhvm。

  1. 尝试开启ZendCompatLayer功能,并编译包中自带的yaml扩展,确认ZendCompatLayer已经可用

  2. 尝试使用ZendCompatLayer编译两个百度扩展,发现不少问题,好比连接时缺乏各类函数、加载不了ini、调用不了minit/rinit等函 数、gcc版本不兼容、原扩展不支持多线程环境等等,通过各类修改hhvm和扩展代码,终于跑通,但成本很高,并且稳定性很难保障。

  3. 测试了一下ZendCompatLayer的性能,用一个包含string, int和嵌套数组的数组,反复调用一个百度扩展作打包解包,结果以下:

耗时 实现方式
199 ms HNI
769 ms HNI+ZendCompat
348 ms php5.2

结论:ZendCompatLayer目前还不完善,不少api未实现,另外性能还较差,对性能要求高的扩展仍是建议用hhvm原生方式实现,而长尾扩展能够用ZendCompatLayer,减小迁移与维护成本。

结论:php5.5对扩展保持较好的兼容性,迁移成本不高。hhvm目前扩展迁移成本较高,不过若是有ZendCompatLayer,也能大大减少迁移成本,能够等ZendCompatLayer完善以后,再作进一步调研。

系统兼容性


php5.5对操做系统基本没有什么要求。

hhvm对系统要求较高,须要在ubuntu/centos下编译、运行,百度大部分机器不符合条件。。

不过,通过研究后发现,能够经过打包so方式,让hhvm能在百度机器运行,上面的测试都是在百度机器上进行的,没有发现什么问题。

根据一样的原理,经过打包依赖so和头文件,也能让hhvm在百度机器上编译,已经成功编译。

内核方面,hhvm要求至少2.6.32系统,百度大部分系统都符合要求。

结论:系统兼容性上,php5.5和hhvm都没有什么问题。

配置兼容性


php5.5对php.ini保持兼容,但php-fpm.conf则变成ini格式,原来的php-fpm.conf须要修改,而且php-fpm也被编译成一个单独的可执行文件,而再也不和php-cgi共用。

hhvm的配置是一种新的hdf格式,并且其配置项都不相同,不必定每一个php.ini配置都能找到对应的配置项,不过常见的都有。新版hhvm也支持指定php.ini文件了,不过仍然不能支持全部配置项。

hhvm是webserver与php一体化,webserver的常见功能,如rewrite、简单防攻击、proxy、日志、静态文件服务也都 有。所以webserver的相关配置也要成hhvm的配置格式。不过如今HHVM也支持fastcgi模式了,因此这个已经不成问题。

结论:配置兼容性上php5.5更好一些。不过配置文件也并很少,人工改形成本也不是很高,所以这方面问题并不大。

新功能


php从5.3到5.5增长了不少新功能,具体能够见:

  • http://www.php.net/manual/en/migration53.php

  • http://www.php.net/manual/en/migration54.php

  • http://www.php.net/manual/en/migration55.php

整体上可归纳为语法更灵活,功能更丰富。

hhvm的语法基于5.4,库的支持也不如php5.5丰富。但hhvm提供了几个功能,可能对性能优化会有很大帮助:

  1. StartupDocument:能够在启动时执行该文件,在此文件中作一些全局初始化工做,并将结果变量经过apc传递给worker线程。这样咱们将一些重复的初始化工做放到该文件,避免每一个请求都执行一样的工做。

  2. ThreadDocuments:能够用后台线程执行一个文件,作一些好比信息收集、定时更新之类的操做,避免在每一个请求中执行相应过程,影响在线请求的响应时间。

  3. Pagelet Server/Xbox Server:能够启动一个子Server,子Server维护一个线程池,主Server能够将一些计算任务分发给子Server异步执行,从而实现并 行化。我尝试了一下这个功能,利用xbox server很方便地就实现了并行调用后端服务的功能,确实很方便,并且这个机制是通用的,不只后端调用能够并行,本地计算也能够并行,能够考虑将模板并 行渲染?呵呵。

  4. 多线程架构:这其实不算一个功能,而是hhvm多线程架构给咱们带来的自然便利。由于在同一个进程内,内存共享会很方便,访问速度更快,而像一些好比链接池的功能,也变得能够实现。

上述功能的介绍详见:

  • https://github.com/facebook/hhvm/blob/master/hphp/doc/server.documents

  • https://github.com/facebook/hhvm/blob/master/hphp/doc/threading

开发者支持


php5.5的开发者支持很好,文档全,api很是稳定。

相比之下,hhvm的开发者支持目前还比较弱,文档不多,不少地方要本身摸索,api还不太稳定,不过hhvm的社区很活跃,github有不少人在提issue和patch,hhvm官方团队也很给力,迭代速度很快,每8周发布一个稳定版本。

整体结论


整体上,使用php5.5,性能会有必定提高,迁移成本较小。

使用hhvm,性能会有很大提高,但迁移成本会较大,主要是扩展方面的迁移成本。


UPDATE

看这里的结论很明显,百度大部分产品线使用了HHVM,由于咱们相信资源的节约对于 咱们这么大规模的应用收益很大。

读到这里,你可能会有疑问思考你到底要不要升级到HHVM?你想知道PHP7对比怎么样?

这里是你须要迁移HHVM的缘由:

  1. 你如今服务器成本比较大,想要节约成本,或者流量持续增加资源不足。

  2. 你须要比较透明的提高性能

  3. 你没有什么自有扩展,或者有时间迁移扩展(扩展迁移到HHVM的成本很低,后面会作相关的介绍)

  4. 你想使用Hack语言

  5. 或者大家想尝试新的技术

一样,这也有不建议迁移HHVM的缘由:

  1. 你的服务器及流量不多

  2. 你的业务很稳定,没有性能上的要求

  3. 大家是土豪,机器随便堆,预算一大把

这还有一些答疑:

  • Q: 有人提到运维成本的问题,HHVM真的不容易运维么?

  • A: HHVM的多线程模型是相对PHP-FPM不稳定,可是有很是多的进程守护解决方案能够很好的解决, 这个不是个问题,以百度如今的运维来看比较稳定。

  • Q:PHP7的性能不是已经不错了么?为何还要迁移到HHVM?

  • A:首先PHP7还处于开发状态,首先迁移大版本的风险仍是有的,至少如今考虑是不靠谱的,若是愿意等, 能够等到PHP7出来之后来进行对比。看看哪一个更适合你,目前这个阶段HHVM是比PHP更优的选择。

作大家的测试(Do Your Own Benchmarking)

若是大家决定迁移了,那么开始前也建议作一次大家业务相关的评测,以确保收益在预期范围内。

相关文章
相关标签/搜索