Skip to content

Instantly share code, notes, and snippets.

@reeze
Created November 9, 2014 04:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save reeze/0de831cb5d09d4585ecf to your computer and use it in GitHub Desktop.
Save reeze/0de831cb5d09d4585ecf to your computer and use it in GitHub Desktop.
BaidLAMP V1
> [百度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>}![](/content/images/2014/10/deploy_1.jpg)
所谓旁路阶段主要是让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>}![](/content/images/2014/10/deploy_2-jpg.png)
全量阶段主要是在功能完善后(扩展),去掉了共享内存这个中间层,直接上线整个应用,此时的通信就直接是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