商品详情页性能分析:c6 / c8i / c9i(liucheng + strace)
主题:同一商品详情页在阿里云 c6(~150ms)、c8i(~110ms)、c9i(墙钟待同条件复测)上的耗时拆解与三机 strace 对比
数据来源:
- 应用层:
liucheng.log(c6,logRuntime打点)- 系统层:
strace_c6.log、strace_c8i.log、strace_c9i.log(strace -f -T)
配套文档:- product-detail-render-optimization.md(P0/P1 改动方案)
- strace-bottleneck-analysis.md(Redis / md5 / Opcache 细拆)
1. 结论摘要
| 维度 | c6 | c8i | c9i |
|---|---|---|---|
| 墙钟(已知) | ~150ms | ~110ms | 待同条件复测 |
syscall 合计(不含首行 FPM accept 空闲) | 84.3ms | 63.2ms(最优) | 70.4ms |
| poll 网络等待 | 37.6ms | 38.0ms | 39.9ms(三台最高) |
| Redis fd=7 poll | 24.3ms(最慢) | 19.3ms | 20.7ms |
| ES poll(fd=14/13) | 4.7ms | 7.7ms | 10.5ms(最慢) |
| 文件元数据 access+stat+fstat | ~15.6ms | ~7.0ms | ~8.6ms |
empty_loading.png open | 26 | 7 | 7 |
debug logRuntime 写 fd4 | ~282 次 | ~0 | ~0 |
应用层(三台共性,liucheng 仅 c6):{% get_blocks %} ~32ms 仍是最大单点;strace 侧 Redis 重复 GET、md5_file、stat 风暴 在 c8i/c9i 上同样存在,只是 c6 更重。
三机 strace 排序(仅统计请求内 syscall,不含 FPM 等连接):
- c8i:syscall 合计最低(63ms),Redis 等待最短。
- c9i:介于 c8i 与 c6;CPU/文件侧接近 c8i,但 poll 总量与 ES 等待偏高。
- c6:syscall 合计最高;叠加 debug 打点 + 冷 worker + md5 26 次。
优化目标不变:P0 落地后 c6 有望 ~115–120ms;机型差异无法靠升配完全消除,需 get_blocks / Redis 去重 / Opcache 等代码侧优化。
2. 端到端耗时分布(c6 · liucheng.log)
从进控制器到渲染结束约 147ms,与 c6 墙钟 ~150ms 一致。(c8i/c9i 无对应 liucheng,业务路径假定相同。)
| 阶段 | 耗时 | 说明 |
|---|---|---|
| 中间件 + HomeBase | ~26ms | 0 → 25.7ms;utm_source ~2.3ms |
| 控制器 → 开始渲染 | ~5.6ms | 25.7 → 31.3ms;无细打点 |
| Liquid 准备 | ~12ms | 设变量/缓存/filter |
{% get_blocks %} | ~32ms | 72.9 → 104.8ms,应用层最大单点 |
| header / analysis 等 include | ~24ms | header_front_variable ~10.5ms |
| 详情 section + include | ~50ms | 碎片 include 累加 |
{% get_product %} ×2 | ~6–8ms | ES 各 ~3–4ms |
| footer + 收尾 | ~15ms |
2.1 liucheng 最大时间间隙(>1ms)
| 间隙 (ms) | 区间 | 说明 |
|---|---|---|
| 31.9 | get_blocks start → end | P0-1 |
| 10.5 | header_front_variable | 待细拆 |
| 5.9 | get-product 第 1 次 | ES |
| 5.8 | filter/tag → 执行渲染前 | 黑盒 |
| 5.6 | 控制器 → 模板渲染 start | ThemeData 等 |
3. 三机 strace 对比(去掉首行 FPM accept 空闲)
注意:
strace_c9i.log首行accept~25.25s 为 PHP-FPM 等请求,不计入单次详情页处理;下文「syscall 合计」均排除该行及耗时 >1s 的异常行。
3.1 trace 概览
| 指标 | c6 | c8i | c9i |
|---|---|---|---|
| 日志行数 | 4528 | 4361 | 6026 |
| 有效 syscall 次数 | 4526 | 4359 | 6024 |
| syscall 耗时合计 | 84.3ms | 63.2ms | 70.4ms |
FPM accept 空闲(首行) | ~22s(部分 trace) | ~83s(冷启动污染,见旧分析) | ~25.3s |
times 起点 utime(ticks) | 0(偏冷) | 40(warm) | 32(warm) |
debug write(4,…cart_in…) | 282 | 0 | 0 |
普通 write(8,…cart…) | 0 | 7 | 7 |
c9i 比 c8i 多 ~1665 次 syscall,主要在 read(+933)/ fstat / access / open;单次耗时极短(页缓存命中),故 合计仅多 ~7ms,不代表多做了 40% 业务逻辑,更可能是 trace 边界或读路径略长。
3.2 主要 syscall 累计耗时(ms)
| syscall | c6 | c8i | c9i | 说明 |
|---|---|---|---|---|
| poll | 37.64 | 37.97 | 39.90 | 网络等待;c9i 略高 |
| read | 9.44 | 6.09 | 9.75 | c9i 次数多、累计接近 c6 |
| write | 7.56 | 2.36 | 1.91 | c6 含 debug 日志 |
| access | 5.98 | 3.11 | 3.44 | autoload |
| stat | 5.34 | 0.45 | 0.72 | c6 最重 |
| recvfrom | 4.11 | 4.03 | 3.36 | |
| fstat | 3.22 | 2.28 | 3.03 | |
| open | 2.17 | 1.54 | 1.90 |
3.3 按 fd 的 poll(Redis / MySQL / ES)
| 连接 | c6 | c8i | c9i |
|---|---|---|---|
| fd=7 Redis | 24.33ms / 204 poll / 62 send | 19.31ms / 189 / 58 | 20.74ms / 190 / 57 |
| fd=8 MySQL | 6.86ms / 15 / 20 | 8.87ms / 16 / 21 | 6.79ms / 18 / 20 |
| fd=13/14 ES | 4.74ms(fd=14) | 7.74ms(fd=13) | 10.47ms(fd=13) |
| fd=5(短 Redis 等) | 1.69ms | 2.03ms | 1.87ms |
- Redis:c8i 最优 → c9i → c6;与「重复 GET」优化(P0-3)直接相关。
- ES:本次样本 c9i 最慢(10.5ms poll),三台都应做 IP 直连 +
get_product去重(P0-2/P1-4)。 - MySQL:差异 <2ms,不是三机墙钟差距主因。
3.4 文件 IO 与 Opcache 信号
| 文件/模式 | c6 | c8i | c9i |
|---|---|---|---|
empty_loading.png open | 26 | 7 | 7 |
settings_schema.json open | 6 | 6 | 6 |
vendor/.../elasticsearch access | 87 | 87 | 87 |
| access+stat+fstat 合计 | ~15.6ms | ~7.0ms | ~8.6ms |
c8i/c9i 在 asset_url/md5 与 stat 上已接近(7 次 open),c6 仍像 冷缓存 + debug 环境。
4. 三机差异解读
4.1 c6 为何最慢(~150ms)
- 应用层:
get_blocks~32ms(liucheng实锤)。 - debug:
logRuntime→ 282 次写日志(strace fd4)。 - strace:Redis poll 24ms、stat/access 合计 ~15ms、
md526 次。 - worker:
times从 utime=0 起,偏冷启动。
4.2 c8i 为何最快(~110ms)
- syscall 合计 最低(63ms),单次 syscall 更快。
- Redis poll 最短(19ms);
empty_loading7 次(热态)。 - 未开 细粒度
logRuntime;warm worker(utime=40 起)。
4.3 c9i 定位(介于 c8i 与 c6 之间)
| 相对 c8i | 说明 |
|---|---|
| 更慢 | syscall 合计 +7ms;poll +2ms;ES fd=13 +2.7ms |
| 接近 | 无 debug 洪水;empty_loading 7 次;文件元数据 ~8.6ms vs 7ms |
| syscall 次数更多 | +1665 次以 read 为主,单次极快,对墙钟影响有限 |
推断:c9i 若墙钟在 ~115–125ms 属合理区间(需你用关 debug、预热 worker 后 Execution-Time 验证)。不能仅凭机型代数认定一定快于 c8i——本次 trace 中 网络 poll 与 ES 等待反而略差于 c8i。
4.4 测法对齐(三机公平对比)
| 检查项 | 要求 |
|---|---|
APP_DEBUG / logRuntime | 三台一致(建议全关) |
| PHP-FPM worker | 先打 1 次预热,再 strace 第 2 次 |
| strace 解读 | 忽略首行 accept 秒级空闲 |
| 指标 | 记录响应头 Execution-Time P50/P95,与 strace 同一次请求 |
5. 流程优化优先级
与 product-detail-render-optimization.md 一致(与机型无关,三台同收益)。
P0
| 项 | 预期收益 |
|---|---|
P0-1 get_blocks + Redis themeConfigs | ~30ms |
P0-2 TagGetProduct static 缓存 | ~3–4ms |
| P0-3 Redis 请求级去重 / APCu 热点 | ~6–15ms |
P0-4 asset_url md5 缓存 | ~2–3ms |
P1
Opcache、ScriptService 缓存、ES IP 直连等(见优化主文档)。
6. 验证清单
- c6 / c8i / c9i 同条件各 10 次:关 debug、预热 worker、
Execution-TimeP50/P95。 - 补录 c9i 墙钟,与 strace 同一次请求归档。
- P0-1 后看
get_blocks区间是否降至 ~1–2ms。 - P0-3 后三机 fd=7 poll 是否均降至 ~15ms 量级。
- P0-4 后
empty_loading.pngopen 是否 ≈1 次/请求。
7. 原始数据索引
| 资源 | 路径 |
|---|---|
| 应用层(c6) | liucheng.log |
| strace c6 / c8i / c9i | strace_c6.log、strace_c8i.log、strace_c9i.log |
logRuntime | common/services/PerformanceService.php |
get_blocks | extend/liquidExtend/tags/TagGetBlocks.php |
get_product | extend/liquidExtend/tags/TagGetProduct.php |
asset_url | extend/liquidExtend/filters/OemsaasFilter.php |