本文为原创,转载请注明:http://www.cnblogs.com/gistao/
背景
我们在aws上部署了hhvm,高峰段发现cpu idle降的比较低,只有10-20%,而使用php-fpm的另外一台机器的cpu idle在40-60%,这与hhvm的性能明显不符。
hhvm的cpu截图
分析
使用gperftools和xhprof工具分析函数的CPU耗时分布
gperf截图
xhprof截图
分析发现_addSysInfo函数内竟然调用了一个exec函数,触发了多线程下fork的坑。不过hhvm也已经提供了相应的避免方法:轻进程
HHVM的轻进程
背景
hhvm支持exec函数对应的底层调用是popen,此函数通过创建一个管道,调用 fork 产生一个子进程,执行一个 shell 以运行命令来开启一个进程
由于hhvm是多线程的,为了避免fork引起的大量内存copy带来的开销,hhvm设计了轻进程模式,轻进程也就是只有一个线程的意思
设计思路
1.在hhvm启动的时候,此时只有一个线程即主线程,就fork出配置项LightProcessCount个子进程
2.当php脚本执行exec的时候,hhvm主进程不会执行fork
3.hhvm会根据当前worker的线程id %LightProcessCount 得到相应的”子进程标识“,“子进程标识”用于和先前fork出的子进程打交道
4.“子进程标识”传递命令到对应的子进程,继而在子进程里完成exec相应的功能
5.注意每个”子进程标识“有一把锁,如果锁未释放,则当前worker线程会阻塞
6.在子进程完成exec之前,当前worker线程会阻塞
配置
Server { # Light process has very little forking cost, because they are pre-forked # Recommend to turn it on for faster shell command execution. #LightProcessFilePrefix = ./lightprocess #LightProcessCount = 0 }
LightProcessCount默认是0,hhvm根据此值建立相应数量的轻进程,如需要,建议和ThreadCount保持以致
LightProcessFilePrefix用于子进程和主进程的通信,即Unix domain socket
例子
配置如下
Server { #LightProcessFilePrefix = ./light_process #LightProcessCount = 10 }
hhvm启动后,会启动10个轻进程
gistao 10472 0.0 0.0 346980 15656 ? Ss 17:00 0:00 hhvm-HHVM-2.2/hphp/hhvm/hhvm -vServer.LightProcessFilePrefix=./light_process -vServer.LightProcessCount=10 -m server -vEval.Jit=true -p 8099 gistao 10473 0.0 0.0 346980 15512 ? Ss 17:00 0:00 hhvm-HHVM-2.2/hphp/hhvm/hhvm -vServer.LightProcessFilePrefix=./light_process -vServer.LightProcessCount=10 -m server -vEval.Jit=true -p 8099 gistao 10474 0.0 0.0 346980 15516 ? Ss 17:00 0:00 hhvm-HHVM-2.2/hphp/hhvm/hhvm -vServer.LightProcessFilePrefix=./light_process -vServer.LightProcessCount=10 -m server -vEval.Jit=true -p 8099 gistao 10475 0.0 0.0 346980 15520 ? Ss 17:00 0:00 hhvm-HHVM-2.2/hphp/hhvm/hhvm -vServer.LightProcessFilePrefix=./light_process -vServer.LightProcessCount=10 -m server -vEval.Jit=true -p 8099 gistao 10476 0.0 0.0 346980 15520 ? Ss 17:00 0:00 hhvm-HHVM-2.2/hphp/hhvm/hhvm -vServer.LightProcessFilePrefix=./light_process -vServer.LightProcessCount=10 -m server -vEval.Jit=true -p 8099 gistao 10477 0.0 0.0 346980 15520 ? Ss 17:00 0:00 hhvm-HHVM-2.2/hphp/hhvm/hhvm -vServer.LightProcessFilePrefix=./light_process -vServer.LightProcessCount=10 -m server -vEval.Jit=true -p 8099 gistao 10478 0.0 0.0 346980 15520 ? Ss 17:00 0:00 hhvm-HHVM-2.2/hphp/hhvm/hhvm -vServer.LightProcessFilePrefix=./light_process -vServer.LightProcessCount=10 -m server -vEval.Jit=true -p 8099 gistao 10479 0.0 0.0 346980 15520 ? Ss 17:00 0:00 hhvm-HHVM-2.2/hphp/hhvm/hhvm -vServer.LightProcessFilePrefix=./light_process -vServer.LightProcessCount=10 -m server -vEval.Jit=true -p 8099 gistao 10480 0.0 0.0 346980 15520 ? Ss 17:00 0:00 hhvm-HHVM-2.2/hphp/hhvm/hhvm -vServer.LightProcessFilePrefix=./light_process -vServer.LightProcessCount=10 -m server -vEval.Jit=true -p 8099 gistao 10481 0.0 0.0 346980 15524 ? Ss 17:00 0:00 hhvm-HHVM-2.2/hphp/hhvm/hhvm -vServer.LightProcessFilePrefix=./light_process -vServer.LightProcessCount=10 -m server -vEval.Jit=true -p 8099
同时,在当前运行目录下生成
srwxr-xr-x 1 gistao hhvm 0 Jan 13 17:00 light_process.10470.0 srwxr-xr-x 1 gistao hhvm 0 Jan 13 17:00 light_process.10470.1 srwxr-xr-x 1 gistao hhvm 0 Jan 13 17:00 light_process.10470.2 srwxr-xr-x 1 gistao hhvm 0 Jan 13 17:00 light_process.10470.3 srwxr-xr-x 1 gistao hhvm 0 Jan 13 17:00 light_process.10470.4 srwxr-xr-x 1 gistao hhvm 0 Jan 13 17:00 light_process.10470.5 srwxr-xr-x 1 gistao hhvm 0 Jan 13 17:00 light_process.10470.6 srwxr-xr-x 1 gistao hhvm 0 Jan 13 17:00 light_process.10470.7 srwxr-xr-x 1 gistao hhvm 0 Jan 13 17:00 light_process.10470.8 srwxr-xr-x 1 gistao hhvm 0 Jan 13 17:00 light_process.10470.9