评注: 一个项目迁移的问题考虑与实现使用。非常之详细.

转: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的开发和调研。

以下为其发展的路线:

  1. HipHop PHP: 将PHP代码翻译成C++代码,然后编译成二进制运行,有很大的性能提升,但开发成本比较大。
  2. hphpi:为了解决编译太慢的问题,其实现的PHP解释器用于提升开发效率,不过代码和hphpc很多都不一样,有很多问题,可能导致线下bug不能发现。
  3. HHVM:真正的虚拟机,目标是和Zend VM保持兼容。

HHVM是HipHop Interpreter的改进版,方便调试使用,性能只有hphpc的一半,但是到了2012年11月, HHVM到了一个里程碑,它的性能接近了hphpc,随后HHVM2.2超过了hphpc,性能比HipHop多40%,HHVM2.3又比HHVM2.2提升20%的性能。

具体HHVM的历史过程可以参见他们的博客,还有官方网站

百度从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个部分分别运行,那么这时我们就需要考虑如下几个问题:

  1. ZEND和HHVM通信方式
  2. 容错容灾:出现问题是怎么避免和降低影响

ZEND 和 HHVM 通信:

我们通过curl+共享内存的方式将zend和hhvm连接在一起,curl用于触发hhvm执行逻辑但是不传输数据,共享内存主要是传数据在2个进程之间,这样curl不用post传数据,数据在内存中传输相应也会提高很多性能,共享内存之前HHVM有个内置的,但是我们业务这边又开发了一个shmop比较通用的扩展来支持共享内存的功能,这样的旁路迁移后,比如在HHVM处理的部分占之前消耗60%,那么我们这一般可以提升性能在30%以上;

容错容灾

  1. HHVM 进程状态监控,挂起及时拉起(supervise)
  2. HHVM 失败后流量切换 我们一般前面有nginx/lighttpd这些web server,如果失败了,一般会通过error_page或者lighttpd的负载容错的措施将失败流量转到ZEND上,保证连接正常(但是延迟会高,也有风险,我将会在全量时说明)

  3. 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本身可能有,我们自己开发的扩展力可能也会有。 如果我们发现了可能的泄露,我们使用jemallocvalgrind来辅助定位问题。比如我们发现了一下的泄露:

  1. libevent keeaplive (fixed)
  2. Init::setting (2.3 fixed)
  3. define 函数动态变量内存泄露(百度内部fix一部分未提供给官方)
  4. create_function 内存泄露(百度内部fix一部分未提供给官方)
  5. uploadFile 功能内存泄露(fixed)

兼容性问题

兼容性问题主要有两种:

  1. HHVM本身的兼容性不够完善:这个可能我们通过一个Hack的方式来避免
  2. 我们使用是PHP5.2,迁移到HHVM之后对应于PHP的版本是5.5,这个时候也是有兼容性差异的。

这类的问题都比较好解决,通过测试一般都是可以发现的。

死锁 hanging

我们在迁移时也发现了死锁的情况,表现是HHVM没办法处理请求,日志不打印,如果此时。

  1. 代码递归死循环(如pcre + 魔术函数递归)
  2. 死锁:比如我们遇到过因为扩展问题导致出core,但是由于HHVM捕获到core后处理时死锁的问题。

性能问题 Performance issue

  1. global scope (未将代码放在函数内执行,不执行jit)
  2. Exception
  3. 使用eval和create_function动态函数
  4. exit 函数
  5. Jit translate code (datablock)
    • stub和maincode超过阀值crash(可通过vm-tcspace监控,后期可通过内部双tc buffer替换,或者双hhvm 进行替换)
  6. nonAuthoritativeRepo
    • Facebook使用repo 模式,就是线下编译为hhbc,官方说法可以在预热时提高30%-40%性能(其实就是节约了编译时间),但是hhvm却不支持热加载(后续可添加此功能) 1.我们使用的是非线下编译,直接去check php 文件,有更新则执行编译+翻译,但是此种方式的问题是,当更新文件过多和更新完触发文件多样性时,所有的work线程就会都进行处理编译+翻译,这样cpu将会一下子被打满,后续我们计划将编译+翻译放到独立线程池处理,通过双buffer替换方式,这样不会由request work处理编译和翻译会减少阻塞

我们的工作(our job)

  1. 内部修复超过60个补丁(包括官方拉取的patch到我们内部版本,和bug修复后PR给官方的)
  2. 维护2个HHVM版本(2.2和3.0.1),Facebook不维护低版本,但是我们内部需要使用,我们进行了向下兼容
  3. 操作系统支持:支持redhat 和centos,无依赖系统独立gcc-4.8.2,可任意部署
  4. 修复Bug、更新hhvm版本和定期patch,提升性能,兼容zend和支持新feature

下一步计划(next plan)

  1. 提交更多内部补丁到开源社区:我们任然有一部分Patch没有提交到官方,后续会把这些Patch进行提交。
  2. 复用jit translate cache:解决JIT超限问题
  3. 编译、emithhbc和翻译jit阶段使用非work模式的多线程模式,采用双buffer替换减少阻塞和cpu消耗
  4. hhbc 支持热加载
  5. 实现异步function和异步io模型等
  6. 更新hhvm 3.6版本预计在明年(Facebook工程师预计在明年会将hhvm的性能提高50%-300%)

后续完成后会在本站发表相关的技术细节。

转: HHVM at Baidu的更多相关文章

  1. HHVM,高性能的PHP执行引擎

    HHVM (HipHop Virtual Machine) 是 Facebook 开源的 PHP 执行引擎. HHVM 采用一种JIT(just-in-time)的编译机制实现了高性能,同时又保持对 ...

  2. Google和Baidu常用的搜索技巧--转

    原文链接:http://mp.weixin.qq.com/s?__biz=MjM5NTY0MTY1OQ==&mid=2654509772&idx=1&sn=754454e374 ...

  3. WordPress插件--WP BaiDu Submit结构化数据插件又快又全的向百度提交网页

    一.WP BaiDu Submit 简介 WP BaiDu Submit帮助具有百度站长平台链接提交权限的用户自动提交最新文章,以保证新链接可以及时被百度收录. 安装WP BaiDu Submit后, ...

  4. 我离baidu.com有几跳

    一.背景 最近,读了网易游戏面试经验(三) - cotyb - 博客园之后,自己尝试着在windows下tracert了一下baidu.com,结果如下图一所示,发现从tracert的结果看,似乎一直 ...

  5. 如何获取google地图、baidu百度地图的坐标

    google:打开google地图-->查找目的地-->右键:此位置居中-->地址栏键入javascript:void(prompt('',gApplication.getMap() ...

  6. 提高Baidu Map聚合的效率

    百度的MAP的例子里提供了一个聚合效果,地址是http://developer.baidu.com/map/jsdemo.htm#c1_4 ,效果图如下图: 这个效果很赞,但效率很低,当数据量达到50 ...

  7. HHVM和Hack

    1. HHVM(http://hhvm.com)  全称是Hip Hop Virtual Machine,是一个PHP引擎. 2.Hack(http://hacklang.org) 一门新的服务器端语 ...

  8. hhvm之轻进程

    本文为原创,转载请注明:http://www.cnblogs.com/gistao/ 背景 我们在aws上部署了hhvm,高峰段发现cpu idle降的比较低,只有10-20%,而使用php-fpm的 ...

  9. 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 ...

随机推荐

  1. Intent 传数据

    Intent作为android重要的组件其重要性不言而喻,这里说说他是怎么传递简单数据和对象 Intent的具体概念就不讲解了!网上有很多的 传递简单的数据(例如String,float等) 传递对象 ...

  2. git/github 使用

    原文:http://www.cnblogs.com/fnng/archive/2011/08/25/2153807.html git/github学习笔记 Posted on 2011-08-25 2 ...

  3. 使用Canvas把照片转换成素描画

    原文:http://www.alloyteam.com/2012/07/convert-picture-to-sketch-by-canvas/ 腾讯的alloy team写的一个素描效果,挺不错的. ...

  4. vs2013修改默认的开发环境

    可能会有朋友和我一样,当安装完VS完成之后,没有选择默认的开发模板,在后面添加新项目时,总是不能选择默认的开发语言,下面给出个简单步骤,记录一下以备用. 看图吧 1.工具>导入和导出设置 2.选 ...

  5. gulp安装和使用简介

    一. gulp和grunt对比 grunt目前的工作流程:读文件.修改文件.写文件——读文件.修改文件.写文件——... gulp目前的工作流程:读取文件——修改文件——修改文件...——写文件 二. ...

  6. Win8增加了快速启动功能......

    (从已经死了一次又一次终于挂掉的百度空间人工抢救出来的,发表日期 2014-05-11) Win8增加了快速启动功能,能让计算机尽快的启动进入Windows界面.win8的这种快速启动功能只会在“关机 ...

  7. Linux 网络编程 高级套接字

    一.套接字选项: 有以下3中方式可以对套接字选项进行设置: getsockopt 和 setsockopt 函数 fcntl函数 ioctl函数 getsockopt和setsockopt函数用于获得 ...

  8. windows下安装,配置gcc编译器

    在Windows下使用gcc编译器: 1.首先介绍下MinGW MinGW是指仅仅用自由软件来生成纯粹的Win32可运行文件的编译环境,它是Minimalist GNU on Windows的略称. ...

  9. 安卓高手之路之 WindowManager

    安卓中的画面不是纯粹由window组成.而是改成了window+view的组织模式.window是一个顶层窗口的概念.view就相当于在window内的控件.而subwindow则是依附于window ...

  10. cocos2dx 读取json及解析

    ball.json 数据例如以下: { "entities": [ { "entity": { "TapOpposite": 0, &quo ...