──Swoole 是“扩展层重写运行时行为”,不是直接魔改 PHP 源码。──────────────────────────────────────────────────────────── Hyperf 是“基于 Swoole 的框架层工程化”,基本不碰 PHP 内核。 ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────── --- 先把“改造 PHP 内核”这句话讲明白 很多人说 Swoole/Hyperf 改了 PHP 内核,实际分两层:1. 真内核(Zend Engine) - PHP 解释执行器、内存管理、变量模型这些。 - Swoole通常不改 php-src 本体,而是通过扩展接口“插进去”。2. 运行模型 - 传统 PHP-FPM:请求来 ->执行 ->进程回收(短生命周期) - Swoole:常驻进程 + Reactor 事件循环 + 协程调度(长生命周期) - 这个变化很大,所以大家体感像“内核被改了”。 --- Swoole 的底层改动点(大白话)1)进程模型改了 - 传统:FPM worker 一次处理一个请求。 - Swoole:Master + Manager + Worker(可选 TaskWorker),常驻内存。 - 意义:少了反复启动销毁,吞吐更高。2)IO 模型改了 - 用 epoll/kqueue 做事件驱动(Reactor)。 - 一个 worker 能同时管理大量连接。 - 意义:高并发连接不靠无限加进程。3)协程调度加进来了 - 协程是用户态轻量任务,不是系统线程。 - 遇到 IO 等待自动切走,先跑别的协程。 - 意义:一个进程里同时跑很多请求任务。4)阻塞函数 Hook - 把部分阻塞调用(sleep、stream、socket、curl 等)替换/劫持为协程友好版本。 - 关键配置:hook_flags=>SWOOLE_HOOK_ALL - 意义:业务代码写法接近同步,底层异步并发。5)生命周期语义变了 - FPM:请求结束,内存大部分跟着清。 - Swoole:常驻,静态变量/单例/全局状态会“留着”。 - 意义:性能上来,但状态污染和内存泄漏风险也上来。 --- Hyperf 的“改动点”(大白话) Hyperf 主要是框架层,不是 C 内核层: - DI 容器、AOP、注解/属性、协程上下文、连接池、中间件、服务治理。 - 全部建立在 Swoole 提供的协程/网络能力上。 - 它做的是“把协程服务器工程化、规范化”,不是重写 Zend VM。 一句话: Swoole 改“发动机工作方式”,Hyperf 改“整车工程化和驾驶体验”。 --- 最佳方式(生产可落地)1. 不要直接全量从 FPM 跳协程化,先做边缘服务(网关/API)试点。2. 用“多进程 + 每进程协程”混合模型:既有隔离,又有并发效率。3. 统一三件套:连接池、超时、熔断/限流。4. 禁用危险写法:请求级状态放全局变量/静态变量。5. 压测看 P99/P999,不只看 QPS。6. 能用 Hyperf 就别自己裸写全套治理能力,框架能省很多线上坑。 --- 完整代码1:Swoole 原生版(展示“底层改造效果”) 文件:swoole_server.php<?php declare(strict_types=1);if(!extension_loaded('swoole')){fwrite(STDERR,"Please install swoole/open-swoole extension.\n");exit(1);}$server=new Swoole\Http\Server('127.0.0.1',9501);$server->set(['worker_num'=>4, // 多进程'max_request'=>10000,'enable_coroutine'=>true, // 协程'hook_flags'=>SWOOLE_HOOK_ALL, // 阻塞IO协程化'log_level'=>SWOOLE_LOG_INFO,]);$server->on('Start',function(Swoole\Http\Server$server){echo"Swoole server started: http://127.0.0.1:9501\n";echo"Master PID: {$server->master_pid}\n";});$server->on('WorkerStart',function(Swoole\Http\Server$server, int$workerId){echo"Worker #{$workerId} started, PID=".posix_getpid().PHP_EOL;});$server->on('Request',function(Swoole\Http\Request$req, Swoole\Http\Response$res){$begin=microtime(true);$sleep=isset($req->get['sleep'])?(float)$req->get['sleep']:0.2;$sleep=max(0.0, min($sleep,2.0));// 协程 sleep,不阻塞整个 worker Swoole\Coroutine::sleep($sleep);// 演示并发IO:3个协程并行$results=[];$wg=new Swoole\Coroutine\WaitGroup();for($i=1;$i<=3;$i++){$wg->add();go(function()use($i,&$results,$wg){Swoole\Coroutine::sleep(0.05*$i);// 模拟外部IO$results[]="io_task_{$i}_done";$wg->done();});}$wg->wait();$costMs=(int)((microtime(true)-$begin)*1000);$res->header('Content-Type','application/json;charset=utf-8');$res->end(json_encode([ 'ok'=>true,'model'=>'multi-process+coroutine','worker_pid'=>posix_getpid(),'worker_id'=>$req->server['worker_id']??-1,'io_results'=>$results,'cost_ms'=>$costMs,'time'=>date('Y-m-d H:i:s'),],JSON_UNESCAPED_UNICODE));});$server->start();运行: php swoole_server.php 压测示例: ab-n2000-c200"http://127.0.0.1:9501/?sleep=0.2"--- 完整代码2:Hyperf 风格最小可运行(核心文件) ▎ Hyperf 项目通常用骨架创建,这里给最小关键代码,你放进标准 Hyperf skeleton 就能跑。 ▎ 核心是:Controller + 路由 + Server 配置。 config/autoload/server.php<?php declare(strict_types=1);use Hyperf\Server\Server;use Swoole\Constant;return['servers'=>[['name'=>'http','type'=>Server::SERVER_HTTP,'host'=>'0.0.0.0','port'=>9501,'sock_type'=>SWOOLE_SOCK_TCP,'callbacks'=>[Constant::EVENT_REQUEST=>[Hyperf\HttpServer\Server::class,'onRequest'],],'settings'=>['worker_num'=>4,'enable_coroutine'=>true,'hook_flags'=>SWOOLE_HOOK_ALL,'max_request'=>10000,],],],];config/routes.php<?php declare(strict_types=1);use Hyperf\HttpServer\Router\Router;use App\Controller\DemoController;Router::get('/demo',[DemoController::class,'index']);app/Controller/DemoController.php<?php declare(strict_types=1);namespace App\Controller;use Hyperf\HttpServer\Contract\RequestInterface;use Hyperf\HttpServer\Contract\ResponseInterface;use Swoole\Coroutine;class DemoController{publicfunctionindex(RequestInterface$request, ResponseInterface$response){$begin=microtime(true);$sleep=(float)$request->input('sleep',0.2);$sleep=max(0.0, min($sleep,2.0));Coroutine::sleep($sleep);$costMs=(int)((microtime(true)-$begin)*1000);return$response->json(['ok'=>true,'framework'=>'hyperf','pid'=>getmypid(),'cost_ms'=>$costMs,'time'=>date('Y-m-d H:i:s'),]);}}运行(在 Hyperf 项目根目录): php bin/hyperf.php start 请求:curl"http://127.0.0.1:9501/demo?sleep=0.3"--- 迁移到 Swoole/Hyperf 最容易翻车的点(最关键) - 把“请求内临时数据”放进静态变量/单例属性。 - 用了没协程化的阻塞客户端,导致并发掉光。 - 没有连接池和超时,慢请求把协程池拖死。 - 没有做上下文隔离(日志 trace_id 串请求)。 --- 结论就一句: Swoole 的核心是运行时模型升级(常驻 + 事件循环 + 协程 + Hook),Hyperf 的核心是把这套能力工程化;最佳落地是“多进程兜底隔离 + 协程提升 IO 并发 + 严格状态隔离”。