转: HHVM at Baidu
评注: 一个项目迁移的问题考虑与实现使用。非常之详细.
转:http://lamp.baidu.com/2014/11/04/hhvm-in-baidu/
在这之前我们介绍了我们为什么要迁移PHP到HHVM, 本文将介绍HHVM在百度的应用情况以及我们遇到的问题及经验。
背景
HHVM前身是HipHop PHP,HipHop通过将php代码->cpp代码->二进制的转换来提升性能, Facebook应用了4年(2007-2011),但是由于开发、编译、调试、维护不方便, 2011年12月Facebook开始了HHVM的开发和调研。
以下为其发展的路线:
- HipHop PHP: 将PHP代码翻译成C++代码,然后编译成二进制运行,有很大的性能提升,但开发成本比较大。
- hphpi:为了解决编译太慢的问题,其实现的PHP解释器用于提升开发效率,不过代码和hphpc很多都不一样,有很多问题,可能导致线下bug不能发现。
- HHVM:真正的虚拟机,目标是和Zend VM保持兼容。
HHVM是HipHop Interpreter的改进版,方便调试使用,性能只有hphpc的一半,但是到了2012年11月, HHVM到了一个里程碑,它的性能接近了hphpc,随后HHVM2.2超过了hphpc,性能比HipHop多40%,HHVM2.3又比HHVM2.2提升20%的性能。
百度从2013年11月开始正式启动PHP业务到HHVM的迁移,通过多部门合作首先在某业务线进行了HHVM的迁移,上线后性能提升了60%以上,之后其他业务线也跟进迁移HHVM。经过各大产品的迁移积累的经验,百度内部目前的HHVM技术支持及扩展库等都比较完善了,下面将具体介绍HHVM在百度的使用情况。
使用规模及收益(Deployment Scale & Results)
- 部署机器规模超过4000台+
- 日均访问HHVM的PV超过了500亿以上(包括了接口调用和用户访问)
- CPU使用率节约40%~60%
- 响应时间减少50%~80%
对于CPU计算密集型的业务来说收益最为明显,CPU的节约和响应时间相关比较大,而对于IO密集型的应用来说可能没有线性关系。(但是可以利用并行处理和异步化来优化IO密集型的应用,比如使用HHVM提供的异步操作进行,以后会单独介绍这一块)。
迁移方式(Migration)
对于一个新的技术来说,通常是会存在一些问题的,为了保证迁移的顺利,我们的迁移并不是一口气全部迁移过去的,迁移方式也采用的渐进式,一来通过在线运行的方式积累经验,二来减少因为不稳定对已有服务的影响。
我们的迁移经历了两个过程:旁路阶段及全量阶段。下面介绍我们迁移时的做法。
旁路阶段
所谓旁路阶段是我们的业务任然使用Zend PHP,但是一小部分功能使用HHVM来做,主要的业务通过RPC的方式来进行通信。这样运行环境就隔离开了。

比如我们为了确认迁移的收益,我们使用HHVM去处理消耗CPU较大,而且比较容易迁移的代码,比如Smarty渲染占了我们业务性能的60%,所以我们把这个逻辑单独抽取出来放到HHVM中运行,其他的逻辑依旧在Zend运行,也就是把应用拆成了2个部分分别运行,那么这时我们就需要考虑如下几个问题:
- ZEND和HHVM通信方式
- 容错容灾:出现问题是怎么避免和降低影响
ZEND 和 HHVM 通信:
我们通过curl+共享内存的方式将zend和hhvm连接在一起,curl用于触发hhvm执行逻辑但是不传输数据,共享内存主要是传数据在2个进程之间,这样curl不用post传数据,数据在内存中传输相应也会提高很多性能,共享内存之前HHVM有个内置的,但是我们业务这边又开发了一个shmop比较通用的扩展来支持共享内存的功能,这样的旁路迁移后,比如在HHVM处理的部分占之前消耗60%,那么我们这一般可以提升性能在30%以上;
容错容灾
- HHVM 进程状态监控,挂起及时拉起(supervise)
HHVM 失败后流量切换 我们一般前面有nginx/lighttpd这些web server,如果失败了,一般会通过error_page或者lighttpd的负载容错的措施将失败流量转到ZEND上,保证连接正常(但是延迟会高,也有风险,我将会在全量时说明)
HHVM状态监控 通过HHVM admin server进行HHVM状态监控,如: check-health (load,queue,funcs,units) vm-tcspace(监控tc状态,一般astub和acode会超出阀值,动态翻译时此值会根据你调用函数更新后进行上涨) 当超过一定阀值后会进行报警告知OP,然后进行相应处理
全量阶段

全量阶段主要是在功能完善后(扩展),去掉了共享内存这个中间层,直接上线整个应用,此时的通信就直接是web server连接hhvm,在hhvm失败时进行容错容灾处理(同旁路阶段处理)
注:
但是全量后的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对比、网络包对比
- 性能测试:确保性能符合预期
- 稳定性测试:确保没有:
- 内存泄露
- crash
- Hang住
- 错误日志
遇到的问题及经验
一下总结我们在迁移和维护HHVM的过程终于到的问题及经验。
我们遇到的问题主要有:
- crash
- 内存泄露
- 死锁
- 兼容性问题
- 性能问题
下面只是简单的汇总,后续会考虑把问题追查的过程和方法分享出来。
Crash
我们在线下测试的时候也会遇到一些Crash,我们争取在线下修复这些crash,如果是HHVM本身的Bug,我们会将修复提交给官方。
HHVM使用的时单进程多线程模型,不像PHP-FPM的多进程,如果程序crash了会导致服务挂掉,这里建议使用supervior这种进程监护程序来保证即使是HHVM崩溃了也能即使的帮你重启程序,减少因为crash而导致影响服务。
内存泄露
为了确保服务的稳定性我们会在线下进行压测,来提前发现内存泄露,内存泄露HHVM本身可能有,我们自己开发的扩展力可能也会有。 如果我们发现了可能的泄露,我们使用jemalloc及valgrind来辅助定位问题。比如我们发现了一下的泄露:
- libevent keeaplive (fixed)
- Init::setting (2.3 fixed)
- define 函数动态变量内存泄露(百度内部fix一部分未提供给官方)
- create_function 内存泄露(百度内部fix一部分未提供给官方)
- uploadFile 功能内存泄露(fixed)
兼容性问题
兼容性问题主要有两种:
- HHVM本身的兼容性不够完善:这个可能我们通过一个Hack的方式来避免
- 我们使用是PHP5.2,迁移到HHVM之后对应于PHP的版本是5.5,这个时候也是有兼容性差异的。
这类的问题都比较好解决,通过测试一般都是可以发现的。
死锁 hanging
我们在迁移时也发现了死锁的情况,表现是HHVM没办法处理请求,日志不打印,如果此时。
- 代码递归死循环(如pcre + 魔术函数递归)
- 死锁:比如我们遇到过因为扩展问题导致出core,但是由于HHVM捕获到core后处理时死锁的问题。
性能问题 Performance issue
- global scope (未将代码放在函数内执行,不执行jit)
- Exception
- 使用eval和create_function动态函数
- exit 函数
- Jit translate code (datablock)
- stub和maincode超过阀值crash(可通过vm-tcspace监控,后期可通过内部双tc buffer替换,或者双hhvm 进行替换)
- nonAuthoritativeRepo
- Facebook使用repo 模式,就是线下编译为hhbc,官方说法可以在预热时提高30%-40%性能(其实就是节约了编译时间),但是hhvm却不支持热加载(后续可添加此功能) 1.我们使用的是非线下编译,直接去check php 文件,有更新则执行编译+翻译,但是此种方式的问题是,当更新文件过多和更新完触发文件多样性时,所有的work线程就会都进行处理编译+翻译,这样cpu将会一下子被打满,后续我们计划将编译+翻译放到独立线程池处理,通过双buffer替换方式,这样不会由request work处理编译和翻译会减少阻塞
我们的工作(our job)
- 内部修复超过60个补丁(包括官方拉取的patch到我们内部版本,和bug修复后PR给官方的)
- 维护2个HHVM版本(2.2和3.0.1),Facebook不维护低版本,但是我们内部需要使用,我们进行了向下兼容
- 操作系统支持:支持redhat 和centos,无依赖系统独立gcc-4.8.2,可任意部署
- 修复Bug、更新hhvm版本和定期patch,提升性能,兼容zend和支持新feature
下一步计划(next plan)
- 提交更多内部补丁到开源社区:我们任然有一部分Patch没有提交到官方,后续会把这些Patch进行提交。
- 复用jit translate cache:解决JIT超限问题
- 编译、emithhbc和翻译jit阶段使用非work模式的多线程模式,采用双buffer替换减少阻塞和cpu消耗
- hhbc 支持热加载
- 实现异步function和异步io模型等
- 更新hhvm 3.6版本预计在明年(Facebook工程师预计在明年会将hhvm的性能提高50%-300%)
后续完成后会在本站发表相关的技术细节。
转: HHVM at Baidu的更多相关文章
- HHVM,高性能的PHP执行引擎
HHVM (HipHop Virtual Machine) 是 Facebook 开源的 PHP 执行引擎. HHVM 采用一种JIT(just-in-time)的编译机制实现了高性能,同时又保持对 ...
- Google和Baidu常用的搜索技巧--转
原文链接:http://mp.weixin.qq.com/s?__biz=MjM5NTY0MTY1OQ==&mid=2654509772&idx=1&sn=754454e374 ...
- WordPress插件--WP BaiDu Submit结构化数据插件又快又全的向百度提交网页
一.WP BaiDu Submit 简介 WP BaiDu Submit帮助具有百度站长平台链接提交权限的用户自动提交最新文章,以保证新链接可以及时被百度收录. 安装WP BaiDu Submit后, ...
- 我离baidu.com有几跳
一.背景 最近,读了网易游戏面试经验(三) - cotyb - 博客园之后,自己尝试着在windows下tracert了一下baidu.com,结果如下图一所示,发现从tracert的结果看,似乎一直 ...
- 如何获取google地图、baidu百度地图的坐标
google:打开google地图-->查找目的地-->右键:此位置居中-->地址栏键入javascript:void(prompt('',gApplication.getMap() ...
- 提高Baidu Map聚合的效率
百度的MAP的例子里提供了一个聚合效果,地址是http://developer.baidu.com/map/jsdemo.htm#c1_4 ,效果图如下图: 这个效果很赞,但效率很低,当数据量达到50 ...
- HHVM和Hack
1. HHVM(http://hhvm.com) 全称是Hip Hop Virtual Machine,是一个PHP引擎. 2.Hack(http://hacklang.org) 一门新的服务器端语 ...
- hhvm之轻进程
本文为原创,转载请注明:http://www.cnblogs.com/gistao/ 背景 我们在aws上部署了hhvm,高峰段发现cpu idle降的比较低,只有10-20%,而使用php-fpm的 ...
- Baidu set to lose leading role in digital advertising _china daily
advertising: n,广告 Online search giant Baidu Inc is set to loset its top spot in the nation's booming ...
随机推荐
- java/android线程池详解
一,简述线程池: 线程池是如何工作的:一系列任务出现后,根据自己的线程池安排任务进行. 如图: 线程池的好处: 重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销. 能有效控制线程池的最大并 ...
- 获取oracle 表字段,表名,以及主键之类等等的信息
数据库版本号:select * from v$version 数据库名:select * from v$instance 注意: 我在C#项目中查询语句的时候报“ORA-00911: 无效字符” 的错 ...
- uva193 - Graph Coloring
Graph Coloring You are to write a program that tries to find an optimal coloring for a given graph. ...
- 【转】Python字符编码详解
转自:http://www.cnblogs.com/huxi/archive/2010/12/05/1897271.html 1. 字符编码简介 1.1. ASCII ASCII(American S ...
- Codeforces Educational Codeforces Round 3 A. USB Flash Drives 水题
A. USB Flash Drives 题目连接: http://www.codeforces.com/contest/609/problem/A Description Sean is trying ...
- android获取/更改gps和WIFI状态
一.WIFI状态的获取和更改 适用于 SDK1.0 , SDK1.5 1.获取WIFI状态 方法1:通过WifiManager进行操作 1WifiManager wifiManager = (Wifi ...
- Redis for Windows(C#缓存)安装和使用
Redis for Windows(C#缓存)安装和使用 前言 前段时间写过两篇简单的有关Memcached缓存的相关文章,当然了只是入门的如何使用而已.最近这两天又发现了Redis这个神奇的东西,之 ...
- 使用iOS手势UIGestureRecognizer
UIKit中包含了UIGestureRecognizer类,用于检测发生在设备中的手势.UIGestureRecognizer是一个抽象类,定义了所有手势的基本行为,它有下面一些子类用于处理具体的手势 ...
- wp上一款应用的出生与死亡
起因 因为自己买了个wp手机,所以对于微软的这个wp系统还是非常喜欢,无奈软件质量不高,过年前便买了个wp的开发者帐号,不是很贵,还想着为wp的生态系统做点贡献.无奈工作繁忙,一直没有机会去做.但是自 ...
- 推荐几个可以与PhoneGap很好搭配的UI框架
- xui.js:可以被视作是jquery在phonegap上的替代品,挺好用的- jq.mobi:同上,不过体积比xui.js要大,一般还是用xui.js- jq.ui:jq.mobi配套的UI框架 ...