多线程下的fork及写时复制导致的性能问题
这篇讲的是贴吧在将服务从PHP-FPM迁移到HHVM(多线程模型)后,遭遇CPU使用率异常飙升的故障排查过程。问题的根源在于,程序中某个基础库调用exec执行shell命令时,会先fork进程。由于HHVM是多线程架构,其他线程在fork期间的内存写入,会频繁触发Linux内核的“写时复制”机制,导致大量不必要的内存拷贝,从而耗尽CPU资源。 作者详细剖析了写时复制的工作原理,指出在单进程模型(如PHP-FPM)下,fork后立刻exec的场景几乎不会触发复制,效率很高。但在多线程环境中,共享的地址空间让这一优化失效,成为了性能杀手。 为了解决这个问题,HHVM采用了一个巧妙的方案:提前创建一个代理进程池。当需要执行外部命令时,主线程通过管道将任务分派给处于单线程环境的代理进程,由后者去完成fork/exec操作。这样就将可能引发写时复制的操作,安全地隔离在了独立进程中,从根本上规避了性能陷阱。文章从实战故障出发,清晰揭示了多线程与操作系统机制交互时容易被忽视的深水区问题。