常见问题 TerryWu edited this page on 13 Jan · 4 revisions - xxyyboy/php-flame GitHub Wiki

Welcome to the php-flame wiki! 如何设置、启动多进程? 通过指定 FLAME_MAX_WORKERS=N 环境变量,进入“多进程模式”,启动主进程及指定数量 N 个工作进程; 不指定上述环境变量时进入“单进程模式” ;

多进程模式(生产环境) 工作进程崩溃时自动重启; 收集工作进程日志,统一写入日志文件(支持重载); 单进程模式(调试环境) 进程崩溃后不会重启; 日志直接输出到标准错误数据; 请求参数哪去了? $_GET / $_POST 没值啊? 框架采用独立的 HTTP 服务体系,在对应的处理回调函数中存在 class flame\http\client_request 类型的对象作为参数;该类型成员变量(属性)对应读取相应的请求参数;一般可大致对应:

// flame\http\client_request $a = $req->query["a"]; // $_GET["a"] $b = $req->body["b"]; // $_POST["b"] $c = $req->file["c"]; // $_FILE["c"] $path = $req->path; // $_SERVER["REQUEST_URI"]; 可以手动启动协程么? 可以。在需要启动协程的位置,直接使用 flame\go() 函数指定对应回调即可; 需要注意的是,启动协程需要一定量的内存消耗,会受到 php 配置 memory_limit 的限制; 被启动的协程不会立即执行,例如:

flame\go(function() { echo 2; }); echo 1; 将输出 "12";

进程退出为什么需要很长时间? Flame 提供了平滑退出的处理可能,并在要退出时(接收到 SIGTERM/SIGINT 信号)通知用户程序; 上述通知发出后,默认配置 10s 后工作进程没有自主退出时,将被主进程强制杀死;

由于上述流程导致了“退出时间长”的现象;用户可通过以下三种形式缩短这个时间:

// 1. 缩短(设置)退出超时 (v0.12.11+) flame\init("process_name", [ // ... 其他配置 ... "timeout" => 0, // 0 立即退出,可设置 0 ~ 64 秒 ]); // 2. 监听退出通知(并主动退出,需要 v0.12.5+) flame\on("quit", function() { // ... // 其他主动退出、清理 // ... flame\quit(); }); // 3. 重复发送上述信号(进程将立即退出,需要 v0.12.11+) 使用 sleep() / usleep() 函数没有“异步调度”啊? PHP 内置的函数一般均为“同步”的过程,此种过程的函数会完全占用 CPU 导致无法进行“异步调度”; 可以考虑使用 flame\time\sleep($milliseconds) 代替; 框架中提供的函数绝大部分都是“异步”调度型函数,需要进行“等待”时会切换“协程”而非完全阻塞等待;

使用 time()/microtime() 函数不好么? 为什么要用 flame\time\now() 函数? 原则上说内置的 time() 函数会直接调用系统时钟,而框架中提供的 flame\time\now() 使用的是通过一次性系统时钟获取,然后根据 CPU 时钟偏移计算得出的,相较而言其消耗要稍低一些;同时该函数提供的是“毫秒”时间戳,可能会减少从 microtime() 计算的额外代码;

日志文件如何进行 ROTATE 轮转重载? 一般情况下可以按照下述流程进行即可:

按需要的形式重命名或移动现有日志文件(将会被继续写入); 向 FLAME 主进程(flame/m)发送 SIGUSR2 信号(重新创建和打开原日志文件); 为什么日志文件没有被生成、写入或创建? 一般可能存在如下原因导致日志文件无法或不被创建:

单进程模式(即未指定 FLAME_MAX_WORKERS 环境变量)时,不会使用日志文件,如有确实仅需要一个进程可以设置 FLAME_MAX_WORKERS=1 或自行导出到文件 php xxx.php &> xxx.log; 多进程时未指定 logger 参数(参见 flame\init() 相关说明); 指定的 logger 目标文件无权创建或写入; 大文件上传不上来?服务端 HTTP 服务端的 POST 体有限制么? 框架提供的 class flame\http\server 同样遵循对应 PHP 的设置 post_max_size 的限制,其默认值一般是 8M; 同时,一般 web 服务器同样会提供参数进行限制,例如 nginx 使用 client_max_body_size 参数,其默认值一般是 1M;

启动了 32 个进程进行 Kafka 消费,只有几个在工作? 目前 FLAME 实现的消费者使用 group-consumer 消费的模式,实际消费者受限于 Kafka 对应 Topic 的 Partition 分区数量; 例如:当实际分区数量为 8 时,启动超过 8 个工作进程,或更多组进程时,实际上就只有 8 个进程消费; 一般可通过扩展 Kafka 对应 Topic 的 Partition 分区数量来提高实际工作进程的数量;

同时,框架提供了额外的参数 concurrent 可用于在单个消费者内使用协程方式并行消费以提高消费速度; 此参数默认为 8 即启动 8 个协程处理消费出的消息;

为什么我使用 Kafka 生产的消息都写入到了一个 Partition 分区? 消息生产的目标分区由对应的 KEY 决定,并默认使用 consistent_hash + random 的策略对消息进行分区;当生产消息指定了 key 时,对该 key 进行一致性哈希选择目标分区(相同的 key 的消息会被生产到同一个分区);当未指定 key 时 (v0.12.10+),将随机选则一个分区;

如何向 MongoDB 写入 ObjectID / DateTime 类型? 框架提供了与 ObjectID / DateTime 对应的封装类型: flame\mongodb\object_id / flame\mongodb\date_time 分别对应上述两种类型,并在实际写入和读取流程自动进行上述映射的转换过程,即:

$_id = new flame\mongodb\object_id(); $client->col_abc->insert(["_id"=>$_id, "dt"=>new flame\mongodb\date_time()]); $doc = $client->col_abc->one(["_id"=>$_id]); assert($doc["dt"] instanceof flame\mongodb\date_time()); 同时上述两个类型的构造函数分别支持从文本串/毫秒时间戳构建两种类型的对象;

消费 Kafka 资源(内存)占用太高了! 一般是由于驱动底层在本地缓冲了大量的消息(以提高消费速度),可以通过一些设置降低,具体的配置请参考: https://github.com/edenhill/librdkafka/wiki/FAQ#explain-the-consumers-memory-usage-to-me https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md

如何发送一个 OPTIONS 方法的 HTTP 请求? 框架的简化函数 flame/http/get()/flame/http/post()/flame/http/put()/flame/http/delete() 分别对应了 GET/POST/PUT/DELETE 方法 (对应 class flame\http\client 内也存在对应的方法); 如果需要发送其他方法类型的请求,需要自行构造请求对象 class flame\http\client_request 并使用 flame\http\exec() 或 flame\http\client::exec() 函数执行该请求即可,例如:

$req = new flame\http\client_request("http://www.baidu.com"); $req->method = "OPTIONS";

$res = flame\http\exec($req); assert($res->status == 200);