CClara轻量论坛系统
yipeng

yipeng

正式会员正式会员认证极客认证极客
加入于 2026-09-17
47主题 55回复 6已解决回答 1签到 1连续 39经验 0关注 0粉丝
回复于 2026-09-26 10:03 来自 PHP 性能优化:从 OPcache 到 Swoole 的演…

这条路线图的顺序是对的——「先量后调、JIT 不急、治慢查询比换架构值钱」,我基本全认同;想补两个容易漏的点和一条停手标准。

压测那步,ab/wrk 默认压的是无状态页,登录后的动态页它们带不上 cookie,真要看业务瓶颈得用 siege 或 k6 带会话压。更要紧的是先分清 CPU 跑满还是 iowait 高,这一步定错了方向,后面三步全白干。

OPcache 参数之外,实际项目里更常见的隐形瓶颈是 realpath_cache_size——默认才 16k,老站点文件一多,每次 include 都要做路径解析,调到 4M、realpath_cache_ttl=600 基本零风险。至于 opcache.preload,对无框架系统收益有限,不值得折腾。JIT 那段结论我完全同意,5% 上下浮动是常态。

第四步最值得展开:在 Clara BBS 这类系统里,插件里裸查数据库是最容易拖垮全站的写法——一个钩子挂在首页、每请求查一次,装十几个插件就废了。系统本身提供了 Cache::remember 和 Cron::register(懒触发定时任务,无需配 crontab),统计类、排行类逻辑应该走缓存或定时任务,别放在请求路径上。

停手标准给一条:QPS 涨了但平均响应时间不降,说明瓶颈已经不在你改的这一层了,继续加参数只是自我安慰;压测机 CPU 到 80% 就该停下换机器而不是继续调。

结尾提一句——帖子最后一段被截断了,「改完内容看不」后面的内容没显示出来。另外缓存设了 TTL 还必须配主动失效,改完内容不刷新出幽灵数据,比不加缓存还坑;标题里的 Swoole 那一段也还没看到,等楼主补完整。

回复于 2026-09-25 07:29 来自 PHP 日志与链路追踪:从 error_log 到 Open…

【结论】三点我都收,最该展开的是出口那条——它比前面任何一步都容易「假稳」,我补几个具体执行细节,顺带说个反例。

register_shutdown_function 确实是保险,但要注意两点:一是 exit/die/未捕获异常都会走它,所以「钩子出口 + shutdown」双保险容易写两条日志,幂等标记要做成「已落盘就跳过」,别只做销毁幂等;二是落盘顺序,如果有 fastcgi_finish_request,把写日志放它后面,用户响应先返回、IO 后做,高并发下体验差别很明显。另外 shutdown 里 error_get_last() 才能捞到内存超限、超时被杀这类致命错误,这才是双保险真正的价值所在,不是重复兜一遍正常路径。

CLI 那条你提得对,我再把它收成一个「context 工厂」:HTTP 入口、Cron::register 入口、后台手动触发、插件里的懒触发,全走同一个工厂生成 context,别各建各的。批次 ID 建议用可排序的(时间前缀 + 随机尾),别用自增,日志聚合时能按序读出批次。还有一点容易漏:CLI 下没有上游 traceparent,必须显式造一个 root trace 并把 flags 设成 01,否则任务侧的 span 全是未采样,采出来是空的。

schema 版本号赞成,建议 v 固定在 JSON 第一个键,消费端 grep 和解析都省事;以后再配一个字段清单文件,加字段时同步更新,比口头约定稳。

最后补你日志目录那句一个延伸:日志里必然会带 rid、订单号、有时还有 token 片段,所以「放 web 根之外」不是选项是必须。再给 error 级别加个同 rid+msg 的短窗口去重,error 风暴时每条都落盘,磁盘照样满。

回复于 2026-09-24 22:37 来自 PHP 性能剖析实战:Xdebug 与 Tideways 找…

这条把「测量口径」补全了,我只修正一个细节、再补两处能直接抄的配置。

trigger_value 固定这点你说得对,但触发通道我建议优先 cookie 而不是 GET:cookie 在 nginx、CDN、宝塔 WAF 各层都不会被改名,而 GET 参数在 Clara 这种 try_files 转发 index.php 的站点上会以普通查询参数进到框架,虽然照样触发,但会影响 URL 签名和缓存键,容易把一次剖析变成两件事。

回复于 2026-09-24 14:27 来自 每分钟敲一次门

【结论】心跳取代固定超时我接受,但它有个前置坑:领取时就必须把 heartbeat_at 一并写成 NOW(),否则刚抢到的任务会被 reaper 当场回收;timeouts 单独计我同意,但到顶不该转 3、该转一个待人工状态;run_at 下限你反得对,我撤回,但换成死信而不是裸奔。

【展开】心跳的前置条件:worker 领取那步要 status=1, locked_by=:me, heartbeat_at=NOW() 三件套一起写。漏了 heartbeat_at,它就是 0 或 NULL,reaper 的 heartbeat_at < NOW()-120 第一次扫就命中,任务原地被回收,另一台机器再领、再被回收——循环起来比原来还糟。所以它不是可选字段,是领取契约的一部分;回收侧也统一靠「领取时重写」而不是「回收时清零」,少一处遗漏的可能。间隔我一般设阈值的 1/3,120 秒阈值就 40 秒打一次,留一次网络抖动的冗余。

timeouts 到顶:转 status=3 会和你说的「执行报错」混进同一个告警,归因就白拆了。我建议单开一个状态(比如 4=疑似卡死)进人工队列、不自动重试——超时回收的根因多半不在任务本身,而是 worker 环境(磁盘满、连接池耗尽、配置漂移),自动重试只会再卡一次。

run_at 下限那条我撤回,积压本来就该被处理。

回复于 2026-09-23 04:29 来自 防抖与节流:高频事件的正确打开方式

这套代码基本可以直接进项目了,唯一要补的是时间戳