Created
November 9, 2014 04:13
-
-
Save reeze/0de831cb5d09d4585ecf to your computer and use it in GitHub Desktop.
BaidLAMP V1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> [百度Lamp技术博客](/) 原创作品,转载时请务必以超链接形式标明文章 [原始出处](http://lamp.baidu.com/2014/11/03/hhvm-in-baidu/) 、作者信息和本声明。否则将追究法律责任。 | |
##背景 | |
HHVM 其前身是hiphop(hphpc),进行php代码->cpp代码->二进制的转换,这个引擎属于静态编译优化,在Facebook应用了4年(2007-2011),但是由于开发、编译、调试、维护并不方便,所以2011年12月Facebook 开始了HHVM的开发和调研; | |
也就是hiphop->hphpi->hhvm的一个发展。 | |
1. HipHop PHP: 将PHP代码翻译成C++代码,然后编译成二进制运行 | |
1. hphpi: 为了解决编译太慢的问题,实现的一个PHP解释器,不过代码和hphpc很多都不一样,有很多的问题 | |
1. HHVM:一个真正的虚拟机,目标是和Zend VM保持兼容。 | |
起初hhvm就是hphpi的一个转型,用于调试使用,性能也就hphpc的一半,但是到了2012年11月是HHVM的一个里程碑,HHVM的性能在此时接近了hphpc,然后便有了2.2超过了hphpc 性能40%,2.3比2.2节约20%的cpu这样的结果(hphpc后期已经不维护) | |
具体HHVM的历史过程可以参见: | |
https://www.facebook.com/notes/facebook-engineering/speeding-up-php-based-development-with-hhvm/10151170460698920 | |
http://hhvm.com/blog/ | |
百度的使用是从2013年11月开始的正式进行HHVM项目启动,通过多部门的合作首先在某业务线进行了对HHVM功能支持、调试、测试后上线收益在60%以上,之后各个业务线也分别使用HHVM,在百度内HHVM的支持和扩展库等目前也比较完善,下面将具体的介绍HHVM在百度的使用。 | |
##使用规模(use scale) | |
* 部署机器的规模超过4000台 | |
* 日均访问HHVM的PV超过了500亿以上(包括了接口调用和用户访问) | |
* cpu使用率节约约40%~60% | |
* 响应时间节约50%~80% | |
响应时间节约一般为计算密集型应用(如smarty渲染,消耗CPU的类型应用),对于IO密集型的应用来说响应时间和CPU一般来说不是正比的(但可以利用并行处理和异步相结合来优化IO密集型的阻塞时间,如pageletServer思想) | |
##部署方式(deploy way) | |
初期使用HHVM时由于功能并不完善,而我们业务的依赖又较多,所以一般在扩展不完全时通过旁路阶段先上线,然后后期功能完善后再进行全量上线,下面我们分别针对2个阶段具体进行介绍: | |
###旁路阶段 | |
{<1>} | |
所谓旁路阶段主要是让HHVM去处理消耗CPU较大的代码,而且耦合特有扩展低的,比如smarty部分占性能的60%,所以我们可以把这块单独的抽取出来放到HHVM中运行,然后旧的逻辑依旧在ZEND运行(此时HHVM的扩展还不完善,这迁移期间可以完善HHVM的扩展开发),相当于一个应用拆成了2个部分运行,那么这时我们就需要考虑如下几个问题: | |
1. ZEND 和 HHVM 通信 | |
1. 容错容灾 | |
**ZEND 和 HHVM 通信:** | |
我们通过curl+共享内存的方式将zend和hhvm连接在一起,curl主要是触发hhvm但是不传输数据,共享内存主要是传数据在2个进程之间,这样curl不用post传数据,数据在内存中传输相应也会提高很多性能,共享内存之前HHVM有个内置的,但是我们业务这边又开发了一个shmop比较通用的扩展来支持共享内存的功能,这样的旁路迁移后,比如在HHVM处理的部分占之前消耗60%,那么我们这一般可以提升性能在30%以上; | |
**容错容灾** | |
1. HHVM 进程状态监控,挂起及时拉起(supervise) | |
1. HHVM 失败后流量切换 | |
我们一般前面有nginx/lighttpd这些web server,如果失败了,一般会通过error_page或者lighttpd的负载容错的措施将失败流量转到ZEND上,保证连接正常(但是延迟会高,也有风险,我将会在全量时说明) | |
1. HHVM状态监控 | |
通过HHVM admin server进行HHVM状态监控,如: | |
check-health (load,queue,funcs,units) | |
vm-tcspace(监控tc状态,一般astub和acode会超出阀值,动态翻译时此值会根据你调用函数更新后进行上涨) | |
当超过一定阀值后会进行报警告知OP,然后进行相应处理 | |
###全量阶段 | |
{<2>} | |
全量阶段主要是在功能完善后(扩展),去掉了共享内存这个中间层,直接上线整个应用,此时的通信就直接是web server连接hhvm,在hhvm失败时进行容错容灾处理(同旁路阶段处理) | |
**<span style="color:red">注:</span>** | |
但是全量后的HHVM如果错误切到ZEND上风险也很大,一般在高峰流量时,HHVM使用一半CPU或者30%左右,但是切换到ZEND 后,一般CPU会被打满,这样就会造成服务拒绝(这样影响也是很大的),后期我们将考虑双HHVM的预案; | |
##扩展开发和框架使用(extension develop and use framwork) | |
###扩展开发 | |
HHVM 虽然性能较好,但是在初期使用中,对于功能和兼容性还是需要做不少工作的,其中扩展开发就是其中的一部分,如下是我们所做的工作: | |
* 开发扩展超过25个(其中包括公司内部扩展和未实现的通用扩展) | |
* 常用的通用扩展 | |
mysqli,mysql,memcached,redis,apc and so on | |
* 可进行开源的扩展 | |
ap(yaf),protobuf,shmop | |
其中ap 为纯php(hack) merge而成; | |
* 扩展测试 | |
php单元测试、cpp单元测试、压力测试、稳定测试、功能测试 | |
### 使用的PHP框架 | |
* smarty | |
模板渲染,使用HHVM一般来说可以提高50%以上性能(但避免使用eval等动态语法) | |
* phpunit | |
扩展php单测框架 | |
## 测试上线 | |
### 上线测试 | |
* 功能测试 | |
diff比较、tcpcopy对比、网络包对比 | |
* 回归测试 | |
引擎回归测试(HHVM单测回归) | |
扩展回归测试(通过单测和QA自动脚本测试) | |
* 性能测试 | |
* 稳定性测试 | |
内存泄露 | |
crash | |
死锁 | |
hanging | |
Warning、异常等对比 | |
### 单元测试标准 | |
* 单测分为php和c++ 2个版本实现,php使用phpunit,c++使用gtest | |
* 函数覆盖率100% | |
* 分支覆盖率超过70% | |
* 使用gtest 生成c++扩展覆盖率 | |
* HHVM引擎patch需要使用HHVM单测框架标准进行编写 | |
##使用问题(use issues) | |
* crash | |
crash 遇到很多情况,线上是不允许出现crash的,我们会预先进行修复,一般crash这类问题修复后我们也都会pull 给官方 | |
* memery leak | |
内存泄露官方和内部扩展其实有一些,我们首先会分析内存泄露点,分析方式一般为:valgrind和jemalloc | |
官方内存泄露发现: | |
1. libevent keeaplive (fixed) | |
1. Init::setting (2.3 fixed) | |
1. define 函数动态变量内存泄露(百度内部fix一部分未提供给官方) | |
1. create_function 内存泄露(百度内部fix一部分未提供给官方) | |
1. uploadFile 功能内存泄露(fixed) | |
* vs zend result different | |
diff 主要分为如下几种: | |
1. hhvm和所有zend 之前见的差异 | |
1. zend 版本之间的差异,由于hhvm支持高版本后,和低版本间差异(如5.3和5.2的差异) | |
* hanging | |
1.代码递归死循环(如pcre + 魔术函数递归) | |
1.死锁 | |
* Performance | |
1. global scope (未将代码放在函数内执行,不执行jit) | |
1. Exception | |
1. 使用eval和create_function动态函数 | |
1. exit 函数 | |
* Jit translate code (datablock) | |
1. stub和maincode超过阀值crash(可通过vm-tcspace监控,后期可通过内部双tc buffer替换,或者双hhvm 进行替换) | |
* nonAuthoritativeRepo | |
1. facebook使用repo 模式,就是线下编译为hhbc,官方说法可以在预热时提高30%-40%性能(其实就是节约了编译时间),但是hhvm却不支持热加载(后续可添加此功能) | |
1.我们使用的是非线下编译,直接去check php 文件,有更新则执行编译+翻译,但是此种方式的问题是,当更新文件过多和更新完触发文件多样性时,所有的work线程就会都进行处理编译+翻译,这样cpu将会一下子被打满,后续我们计划将编译+翻译放到独立线程池处理,通过双buffer替换方式,这样不会由request work处理编译和翻译会减少阻塞 | |
##我们的工作(our job) | |
1. 内部修复超过60个补丁(包括官方拉取的patch到我们内部版本,和bug修复后PR给官方的) | |
1. 我们内部使用2个版本hhvm(2.2和3.0.1),其中facebook不做低版本兼容,我们内部进行了向下兼容 | |
1. 操作系统支持redhat 和centos,无依赖系统独立gcc-4.8.2,可任意部署 | |
1. 修复bugs,更新hhvm版本和定期patch,提升性能,兼容zend和支持新feature | |
##下一步计划(next plan) | |
1. 复用jit translate cache(双buffer替换) | |
1. 编译、emithhbc和翻译jit阶段使用非work模式的多线程模式,采用双buffer替换减少阻塞和cpu消耗 | |
1. hhbc 支持热加载 | |
1. 更新hhvm 3.6版本预计在明年(facebook的工程师预计他们在明年会将hhvm的性能提高在50%-300%之间) | |
1. 实现异步function和异步io模型等 | |
> [百度Lamp技术博客](/) 原创作品,转载时请务必以超链接形式标明文章 [原始出处](http://lamp.baidu.com/2014/11/03/hhvm-in-baidu/) 、作者信息和本声明。否则将追究法律责任。 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment