<p>应使用ab压测时同步抓取MySQL processlist和慢查询日志,并通过自定义SQLLogger在SQL中注入路由注释(如/ route=api_users_index /),再结合SELECT * FROM information_schema.PROCESSLIST WHERE INFO LIKE '%route%'和slow_log表过滤定位高并发热点路由及对应数据表。</p>

怎么查 Symfony2 中高并发访问的路由和对应的数据表?
不能靠日志 grep 或手动翻 Profiler —— 那些只反映单次请求,掩盖不了真实压测下的热点路径。关键是要把「HTTP 路由」和「底层 SQL 涉及的表」在时间维度上对齐,再叠加并发粒度统计。
最直接有效的方式是:用 ab 或 wrk 压测时,同步抓取 MySQL 的 processlist 和慢查询日志,并反向映射到 Symfony2 的控制器动作。
- 先确认压测目标路由是否已关闭 debug 模式(
app.php环境),否则 Profiler 的开销会污染 DB 表现 - 在压测命令中带上唯一标识头,例如:
ab -n 2000 -c 50 -H "X-Trace-ID: loadtest-users-index" http://app.local/app.php/api/users - MySQL 侧执行:
SELECT * FROM information_schema.PROCESSLIST WHERE INFO LIKE '%loadtest-users-index%'—— 如果没结果,说明请求根本没打到 DB,问题出在路由解析、权限或缓存层 - 若看到大量
SELECT * FROM user或JOIN order ON user.id = order.user_id,就定位到了核心数据表和关联模式
为什么 Symfony2 的 Profiler 里看不到真实的并发 SQL 调用链?
Profiler 是单请求快照,它记录的是「这个请求执行了哪些 SQL」,但不记录「同一时刻有多少请求正在执行同一条 SQL」。高并发下,真正的瓶颈常出现在连接争抢、锁等待、索引失效导致的临时表堆积,这些在 Profiler 里完全不可见。
必须跳出框架层看数据库真实状态:
-
SHOW STATUS LIKE 'Threads_created';每秒飙升 → 连接池复用失败,检查PDO::ATTR_PERSISTENT => false是否被误设为true -
SHOW PROCESSLIST;中出现大量Locked或Waiting for table metadata lock→ DDL 操作(如加字段)阻塞了读请求,不是代码问题,是发布窗口管理失误 -
SELECT TABLE_NAME, TABLE_ROWS FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'your_db' ORDER BY TABLE_ROWS DESC;确认是否真在查大表(如log_event有 800 万行却没分表)
如何让每个 SQL 查询自动带上路由信息写入 MySQL 慢日志?
MySQL 本身不识别 Symfony2 的路由,但你可以用 init_connect + 应用层注入方式,在每条查询前拼上上下文。Symfony2 不支持原生 query comment,所以得在 Doctrine 层动手脚。
在自定义的 SQLLogger 实现中,于 startQuery() 方法里加入:
public function startQuery($sql, array $params = null, $types = null)
{
$request = $this->requestStack->getCurrentRequest();
$route = $request ? $request->get('_route') : 'unknown';
$sql = sprintf('/* route=%s */ %s', $route, $sql);
// 后续交给 PDO 执行
}这样生成的 SQL 会带注释,慢日志里就能直接过滤:SELECT * FROM mysql.slow_log WHERE sql_text LIKE '%route=api_users_index%';
- 注意:该方式仅在 debug 环境启用,生产环境避免额外字符串拼接开销
- 若用的是 MySQL 5.6+,确保
log_output = 'TABLE',否则文本日志无法高效检索注释 - 别依赖
$_SERVER['REQUEST_URI']—— CLI 命令或异步任务没有该变量,$request->get('_route')更可靠
统计结果不准?可能是 Doctrine 第二级缓存干扰了真实 DB 访问量
如果发现压测时 MySQL 的 Com_select 计数远低于预期,或者 processlist 里几乎看不到对应 SQL,大概率是开启了 Doctrine 二级缓存(比如配了 Redis),查询根本没触达数据库。
验证方法很简单:
- 临时禁用二级缓存:注释掉 config.yml 中
doctrine.orm.entity_managers.default.second_level_cache整段配置 - 清空 Redis:
redis-cli FLUSHDB,再跑一次压测 - 对比两次的
SHOW GLOBAL STATUS LIKE 'Com_select';增量 —— 差值就是被缓存拦截的查询次数 - 若业务确实需要缓存,应改用「集合缓存」而非「实体缓存」,避免缓存穿透后集中击穿 DB
真正难的不是采集数据,而是区分「是 DB 慢,还是 ORM 映射慢,还是网络延迟,还是缓存策略错」——这四者在 Symfony2 里混在一起,必须用 Stopwatch 打点 Repository 层、用 processlist 看连接状态、用 slow_log 查执行计划,三线并进才不会误判。



















