Yii框架不原生支持链路追踪与分布式事务自动透传,需手动在Application::init()或beforeAction()中生成trace_id并显式注入日志、HTTP头、SQL注释及MQ消息中,确保端到端一致性;本地事务无法感知跨库状态,分布式事务需依赖2PC等外部协调机制。

Yii 框架本身不内置链路追踪(Tracing)和分布式事务的自动跨服务追踪能力,也没有原生支持 OpenTracing / OpenTelemetry 的集成点。想实现请求级全链路追踪 + 分布式事务问题定位,必须手动注入上下文、传递 trace_id,并配合外部组件协同排查。
如何在 Yii 中注入和透传 trace_id
关键在于拦截请求入口、生成唯一 trace_id,并在后续所有日志、远程调用、数据库操作中显式携带。不能依赖框架自动传播。
-
trace_id应在Application::init()或Controller::beforeAction()中生成(如用bin2hex(random_bytes(8))),并存入\Yii::$app->params['trace_id']或自定义TraceContext组件 - 所有
Yii::info()/Yii::error()日志调用必须显式拼接'trace_id' => \Yii::$app->params['trace_id'],否则日志无法关联 - 调用其他服务(cURL、gRPC、消息队列)时,需手动在 HTTP Header(如
X-Trace-ID)、MQ 消息 headers 或 payload 中写入该trace_id - 数据库查询(尤其是跨库事务)建议在 SQL 注释中插入 trace_id:
/* trace_id=abc123 */ UPDATE orders SET status=1 WHERE id=123,方便在慢日志或 DBA 工具中反查
为什么 Yii 的本地事务日志看不出分布式问题
因为 CDbTransaction 或 yii\db\Transaction 只管理单个 Connection 实例的 begin/commit/rollback,它完全感知不到其他数据库连接是否成功——$trans1->commit() 和 $trans2->commit() 是两个独立操作,没有协调者记录失败时序。
- 常见错误现象:
DB1 提交成功,DB2 抛异常回滚,但 DB1 已不可逆提交→ 这不是 Yii 的 bug,是 2PC 缺失导致的必然结果 - 排查时翻
runtime/logs/app.log只能看到「DB1 commit OK」和「DB2 exception」两条孤立日志,中间无因果标记 - 真正需要的是:在事务块外统一打点,例如
Yii::info(['event' => 'tx_start', 'trace_id' => $tid, 'dbs' => ['db1','db2']]),并在每个commit/rollback后补对应事件 - 若用了 XA(如 MySQL 的
XA START),注意PDO::ATTR_ERRMODE必须设为PDO::ERRMODE_EXCEPTION,否则XA COMMIT失败会被静默吞掉
排查分布式事务失败时,优先检查这三处
多数“事务看似没回滚”问题,根源不在 Yii 代码逻辑,而在环境或配置断层。
-
mysql是否开启innodb_support_xa = ON?Windows 下 PDO_MYSQL 扩展可能禁用 XA 支持,报错XAER_RMFAIL时先换 Linux 环境验证 - 多个数据库连接是否使用了相同事务隔离级别?比如
db1是REPEATABLE READ,db2是READ COMMITTED,会导致幻读判断不一致,补偿逻辑误判 - 消息队列(如 RabbitMQ/Kafka)消费者是否开启了 auto-commit?若消费后未手动
ack就 crash,消息会重发,造成重复执行 —— 此时看到的“数据不一致”其实是幂等缺失,不是事务失败
链路追踪和分布式事务排查,在 Yii 里从来不是“配个组件就生效”的事。最易被忽略的是 trace_id 的端到端一致性:从 Nginx 的 $request_id 到 PHP-FPM 的 $_SERVER['HTTP_X_TRACE_ID'],再到 MQ headers、SQL 注释、日志字段,任意一环漏传,整条链就断了。


















