本文目标是让接手者从“页面报错/消息没消费/数据不对”出发,在最短路径内判断问题属于入口、运行时、配置、数据、缓存、消息还是外部系统。
命令默认用于本机 Colima 开发环境。预发与生产只做受控只读排查,不在文档中记录账号、密码、Cookie、Token、内部主机地址或客户隐私数据。

1. 业务目标

一套可用的 DGJ 本地联调环境必须证明五件事:

  1. 浏览器请求确实进入本地 OpenResty。
  2. OpenResty 把 PHP 请求交给本地 php74:9000。
  3. PHP 读取的是预期代码、配置和会话。
  4. MySQL、Redis、RabbitMQ 等依赖连接到预期环境。
  5. 请求能够通过业务单号或 RequestId 追到日志和数据结果。

“容器启动了”只证明进程存在,不等于业务环境正确。

2. 适用场景

现象首先查看
dgj2.localhost 打不开Docker context、OpenResty、80 端口、证书/配置
502 / 504PHP-FPM、FastCGI、PHP fatal、外部调用超时
登录页能开,业务页跳回登录Session、Redis、账号状态、环境数据库
改代码不生效代码挂载、分支/worktree、FPM/opcache、请求实际主机
数据库连接失败mysql57 状态、配置挂载、架构兼容
接口返回旧数据Redis/Mongo/ES 缓存与环境混用
MQ 不消费RabbitMQ、消费者进程、destination/routing key、日志目录
本地无法收到外部回调使用预发联调或受控重放,不伪造业务成功
找不到日志先确认 LOGPATH 和 logger 的 logPath/channel
页面与预发结果不同比较代码版本、配置、数据、外部依赖和缓存五层

3. 项目和运行时路径

资源路径
DGJ2 代码/Users/zhoujiangbin/code/docker-dev-env/www/dgj2.0
Docker 开发栈/Users/zhoujiangbin/code/docker-dev-env
Compose 主文件docker-compose.yml
Colima overridedocker-compose.colima.yml
标准启动脚本scripts/start_saas_dgj.sh
OpenResty DGJ 配置services/openresty/conf.d/dgj2.conf
PHP 7.4 配置services/php/conf/php.ini、services/php/conf/version/74/*
DGJ 配置挂载容器内 /data/configs/dgj
DGJ 业务日志容器内 /data/logs/dgj
DGJ Session容器内 /data/sessions/dgj
上传目录容器内 /data/uploads

4. 本地运行架构

flowchart LR
    B[浏览器 / curl] -->|dgj2.localhost:80| N[OpenResty]
    N -->|FastCGI| P[php74 : 9000]
    P --> CODE["/www/dgj2.0"]
    P --> CFG["/data/configs/dgj"]
    P --> DB[(mysql57)]
    P --> R[(redis)]
    P --> MQ[(rabbitmq)]
    P --> M[(MongoDB 可选)]
    P --> EXT[预发/本地外部服务]
    P --> LOG["/data/logs/dgj"]

OpenResty 的 DGJ server:

server_name: dgj2.localhost
root: /www/dgj2.0
PHP upstream: php74:9000

本地 OpenResty 访问日志当前配置为关闭,错误日志在 OpenResty 容器日志目录中。因此“没有 access log”不等于请求没有到达。

5. 核心服务

容器作用必要性
openrestyHTTP 入口和 FastCGI 转发必需
php74CodeIgniter/PHP-FPM 与 CLI 消费者必需
mysql57DGJ 业务数据库必需
redisSession、缓存、锁、幂等必需
rabbitmqMQ 生产和消费MQ 联调必需
mongodbApp/OpenAPI 日志、部分商品和会话对相关场景必需
elasticsearch商品搜索搜索联调必需
kafka260机器人/特定消息场景对相关场景必需

启动 DGJ 主链只需要先拉起前五个,其他依赖按业务场景增加。

6. Docker Context

本机已经从 Docker Desktop 迁移到 Colima。命令应显式指定:

DOCKER_CONTEXT=colima docker ps

不要根据 docker ps 的空结果直接判断容器不存在;未指定 context 时可能查到默认 Docker socket。

6.1 首次体检

docker context ls
colima status
DOCKER_CONTEXT=colima docker version
DOCKER_CONTEXT=colima docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'

判断:

输出含义
Colima running 且 client/server 都有版本Docker daemon 可用
context 不存在但 socket 存在修复 context,不要启动 Docker Desktop
容器 Restarting先看容器日志,不能继续业务验证
容器 Exited检查配置、挂载、端口和证书

7. 标准启动

优先使用项目已有脚本:

cd /Users/zhoujiangbin/code/docker-dev-env
DOCKER_CONTEXT=colima ./scripts/start_saas_dgj.sh

只启动 DGJ 基础依赖:

cd /Users/zhoujiangbin/code/docker-dev-env
DOCKER_CONTEXT=colima docker compose \
  -f docker-compose.yml \
  -f docker-compose.colima.yml \
  up -d php74 mysql57 redis rabbitmq openresty

start_saas_dgj.sh 还会处理 SAAS、本地域名映射、证书信任、Xdebug 配置和 MQ 日志目录,适合 DGJ/SAAS 联调。

8. 启动后的最小验收

curl -sS -o /tmp/dgj2_login.html \
  -w 'HTTP %{http_code} bytes %{size_download}\n' \
  --max-time 15 \
  http://dgj2.localhost/index.php/passport/login/index

DOCKER_CONTEXT=colima docker exec php74 php -v
DOCKER_CONTEXT=colima docker exec php74 sh -lc \
  'netstat -tlnp 2>/dev/null | grep :9000 || true'

预期:

  • 登录页 HTTP 200。
  • PHP 版本为项目兼容的 7.4。
  • PHP-FPM 监听 9000。
  • OpenResty 与 PHP 容器都在同一 Compose 网络中。

9. 五层健康检查

flowchart TD
    A[请求失败] --> B{域名能访问吗}
    B -->|否| C[OpenResty/端口/hosts]
    B -->|是| D{PHP页面能执行吗}
    D -->|否| E[FastCGI/FPM/PHP fatal]
    D -->|是| F{数据库可用吗}
    F -->|否| G[mysql57/配置/账号]
    F -->|是| H{Session和缓存可用吗}
    H -->|否| I[Redis/库号/key]
    H -->|是| J{业务依赖可用吗}
    J -->|否| K[MQ/Mongo/ES/外部服务]
    J -->|是| L[进入业务逻辑排查]

不能跳过基础设施直接改业务代码。

10. OpenResty 排查

DOCKER_CONTEXT=colima docker ps -a --filter name=openresty
DOCKER_CONTEXT=colima docker logs --tail 200 openresty
DOCKER_CONTEXT=colima docker exec openresty openresty -t

常见问题:

现象原因处理
80 端口占用另一 Nginx/Docker Desktop/本地服务找到占用者,避免双栈同时启动
SSL key too small旧本地证书不兼容重新生成 2048 位含 SAN 的本地证书
502php74:9000 不通查 FPM 和容器网络
404root/try_files/URI 不符查 dgj2.conf 和实际路径
配置测试失败挂载文件语法错误修复宿主机源文件再重启

11. PHP-FPM 排查

DOCKER_CONTEXT=colima docker ps -a --filter name=php74
DOCKER_CONTEXT=colima docker logs --tail 200 php74
DOCKER_CONTEXT=colima docker exec php74 php -m
DOCKER_CONTEXT=colima docker exec php74 php --ini
DOCKER_CONTEXT=colima docker exec php74 sh -lc 'ls -ld /www/dgj2.0 /data/configs/dgj /data/logs/dgj'

项目关键 PHP 限制来自挂载配置:

配置当前文件基线
max_execution_time300 秒
memory_limit256M
post_max_size100M
upload_max_filesize50M

导入、导出、报表超时时,需要同时检查 Nginx、FPM、PHP 和外部服务,不是只改一个值。

12. Xdebug

Colima override 把以下文件只读挂载进 php74:

services/php/conf/version/74/docker-php-ext-xdebug.ini

关键规则:

  • Xdebug 3 使用 xdebug.mode=debug。
  • 请求自动尝试连接 IDE。
  • 客户端端口和宿主机名称由挂载配置指定。
  • 容器内直接改 ini 会在重建后丢失,应改宿主机源文件。

检查:

DOCKER_CONTEXT=colima docker exec php74 php --ri xdebug
DOCKER_CONTEXT=colima docker exec php74 sh -lc 'tail -n 100 /tmp/xdebug.log 2>/dev/null || true'

断点不进时依次看:请求是否打到本地、Xdebug 是否加载、IDE 是否监听、路径映射是否 /www/dgj2.0。

13. 环境变量与配置优先级

CodeIgniter 环境由 CI_ENV 决定,未设置时默认为 development。

配置来源可能包括:

仓库 application/config/*.php
+ application/config/{ENVIRONMENT}/*.php(存在时优先)
+ 容器挂载 /data/configs/dgj
+ 环境变量和常量
+ 远程/中心服务配置

13.1 配置文件地图

配置文件
数据库application/config/database.php + 外部配置挂载
Redisapplication/config/redis.php
RabbitMQapplication/config/mq.php
Mongoapplication/config/mongodb.php
Elasticsearchapplication/config/elasticsearch.php
路由application/config/routes.php
App APIapplication/config/appapis.php
老 OpenAPIapplication/config/apis.php
SAAS APIapplication/config/SaasApis.php
表常量application/config/tables.php
功能开关/版本application/config/env.php、version.php 等

13.2 不泄密地确认环境

只输出主机别名、库名、端口和环境名,不输出密码/Token:

DOCKER_CONTEXT=colima docker exec php74 php -r '
echo "CI_ENV=".(getenv("CI_ENV") ?: "development").PHP_EOL;
echo "PHP=".PHP_VERSION.PHP_EOL;
'

数据库配置建议通过已有只读查询 Skill 验证 SELECT DATABASE(),不要直接 cat 配置文件到终端记录。

14. 六类入口

入口定位方法基类/处理器
PC 页面/Ajax路由 + Controller 方法BaseController
App/PDA codeappapis.phpBaseAppController、App Service
老 OpenAPIapis.php + OpenServiceBaseService
Inner APIController 路径BaseApiController
MQdestination + routing keycontrollers/tasks/*Notify.php
CLI/定时任务php index.php tasks/...CLI Controller
flowchart TD
    A[拿到请求信息] --> B{入口类型}
    B -->|URL| C[routes.php -> Controller]
    B -->|transCode/reqCode| D[apis.php/appapis.php -> Service]
    B -->|MQ event| E[MqEventEnums -> tasks Consumer]
    B -->|CLI| F[tasks Controller method]
    C --> G[Service -> Model/Provider]
    D --> G
    E --> G
    F --> G

15. PC 请求定位

rg -n "目标路径|目标方法" application/config/routes.php application/controllers
rg -n "function 目标方法" application/controllers
rg -n "目标Service|目标Model" application/controllers application/Services application/service

PC 请求常依赖登录 Session、站点 sid、用户 uid、菜单权限和账号状态。未登录 curl 与浏览器登录请求不能直接比较。

15.1 浏览器复现记录

保留:

请求 URL、方法、Content-Type、状态码、耗时、业务 code/message、RequestId、sid、业务单号、请求时间

Cookie 和完整请求头只保存在受控本地环境,不贴进文档或群聊。

16. App / PDA 请求定位

BaseAppController:

  1. 读取 JSON body。
  2. 根据 reqCode 选择 appApi/app 或 pdaApi/app 日志。
  3. 记录 URI 与请求体。
  4. 校验 sign、data、reqCode、uid。
  5. 校验签名、登录和设备。
  6. 合并业务数据与用户上下文。
  7. 尝试写 Mongo dgj_app_log。
sequenceDiagram
    participant C as App/PDA
    participant A as BaseAppController
    participant L as 文件日志
    participant M as Mongo dgj_app_log
    participant S as 业务Service
    C->>A: JSON reqCode/uid/sign/data
    A->>L: URI + request_body
    A->>A: 参数/签名/登录/设备校验
    A->>M: 请求与用户上下文
    A->>S: businessData
    S-->>C: 业务响应

16.1 安全债

旧签名实现包含硬编码共享签名材料。文档不记录其值;维护建议:迁移到配置中心、支持轮换和版本、避免在签名失败消息中回显签名。

17. 老 OpenAPI 定位

OpenService 处理 transCode:

apis.php 映射 -> application/service/api/{path}.php -> BaseService::service

请求有 requestId 时:

  • Redis 使用 NX + 10 分钟 TTL 防并发重复。
  • Mongo dgj_api_log 保存请求和处理状态。
  • 处理成功后把日志状态改为成功。
flowchart TD
    A[OpenAPI 请求] --> B[校验 transCode/reqCode/targetCode]
    B --> C{有 requestId}
    C -->|是| D[Redis 10分钟请求锁]
    D --> E[Mongo dgj_api_log]
    C -->|否| F[直接映射 Service]
    E --> F
    F --> G[业务执行]
    G --> H[更新 Mongo status]
    G --> I[释放请求锁]

重复请求排查必须同时看 Redis 锁和 Mongo 状态,不能只重发。

18. Inner API 定位

BaseApiController 支持 JSON 和表单,读取 Request-Id、Shipper、Inspire-Api-User 等头,并记录 URI、body、header。

安全注意:当前日志会记录完整 header/body,联调时必须对内部 Token、用户信息和文件 URL 脱敏。

常用日志:

/data/logs/dgj/inner/api-YYYY-MM-DD.log

实际文件名由 Monolog RotatingFileHandler 生成,以环境中的文件为准。

19. MQ 入口定位

rg -n "事件名" application/KzData/Enums/MqEventEnums.php
rg -n "事件名|registryCallback" application/controllers/tasks
rg -n "事件名|send.*Mq|publish" application/Services/Mq/MqSer.php application/Services/SyncOrder

消费者启动形态:

DOCKER_CONTEXT=colima docker exec -it php74 \
  php /www/dgj2.0/index.php tasks/OrderCenterNotify/consume

替换为目标 Controller。启动前必须确认连接的是本地/开发 RabbitMQ,避免本地消费者误消费预发或生产消息。

20. CLI / 定时任务定位

DOCKER_CONTEXT=colima docker exec php74 \
  php /www/dgj2.0/index.php tasks/FlashSaleTask/refreshGoodsStatus

执行前:

  1. 阅读方法确认参数和默认范围。
  2. 确认数据库、Redis、MQ 环境。
  3. 对批量任务先找 dry-run、分页或单 ID 参数。
  4. 记录开始/结束时间和影响行数。
  5. 不在生产直接运行本地未经审核的任务。

21. 日志体系总览

层位置用途
OpenResty error容器 /var/log/nginx/nginx.dgj2.error.log502、配置、FastCGI
PHP/FPM容器 /var/log/php、docker logs php74Fatal、扩展、FPM
CodeIgniterLOGPATH 下框架日志框架错误,阈值当前偏错误级
MonologLOGPATH/{logPath}/{channel}-日期.log业务、Provider、Consumer
Mongo App 日志dgj_app_logApp/PDA 请求
Mongo OpenAPI 日志dgj_api_log请求幂等和处理状态
MQ SDK 日志/data/logs/kzmq/*Producer/Consumer 传输
Kibanalogstash-YYYY-MM-DD预发/生产集中日志

22. LOGPATH 规则

index.php 按操作系统定义:

运行方式LOGPATH
Linux/Darwin/data/logs/dgj
Windowsapplication/logs

本地 PHP 运行在 Linux 容器中,所以日志写 /data/logs/dgj,该目录由 Compose 挂载到宿主机数据目录。直接看仓库 application/logs 通常只能看到占位文件。

23. Monolog 文件规则

调用:

KzLogger::getLogger($logPath, $channel)

目标:

LOGPATH/{logPath}/{channel}.log

由于使用 RotatingFileHandler,实际落盘会带日期后缀。每行格式:

[时间][级别][channel] RequestId#...# 消息 context

常用目录:

目录内容
providers/外部 HTTP 调用
inner/Inner API、机器人、账户等
appApi/App 请求
pdaApi/PDA 请求
OrderCenterNotify/订单中心回调
PayCenterNotify/支付回调
robot_v2/IM/机器人 V2
debug/历史调试日志,谨慎使用

24. RequestId

KzLogger 默认生成 16 位随机 RequestId;KzLoggerInstance 自动在每条消息前加:

RequestId#{requestId}#

部分 Inner API 从 Request-Id header 读取,但必须调用 KzLogger::setRequestId 才能保证所有 logger 统一。异步回调可使用强制同步已创建 logger 的模式。

flowchart LR
    A[网关/调用方 Request-Id] --> B[Controller 读取]
    B --> C[KzLogger::setRequestId]
    C --> D[Controller 日志]
    C --> E[Service 日志]
    C --> F[Provider 日志]
    C --> G[MQ payload/headers]

当前并非所有链路都完成 RequestId 透传,排查时仍需组合业务单号、sid、事件名和时间窗口。

25. 日志搜索顺序

1. 业务单号/支付流水/任务号。
2. RequestId / traceId / messageId。
3. sid + 精确时间窗口。
4. Controller/Consumer/Provider channel。
5. 错误文案。

本地示例:

DOCKER_CONTEXT=colima docker exec php74 sh -lc \
  'rg -n "业务单号|RequestId#目标ID#|错误文案" /data/logs/dgj 2>/dev/null | tail -n 120'

若容器没有 rg,改用限定目录和关键词的 grep -R,避免扫整个磁盘。

26. Provider 日志

BaseProvider 默认记录 URL、headers、data 和响应,并生成一次本地请求 ID。

排查外部调用:

业务请求日志 -> Provider 请求日志 -> Provider 响应/异常 -> 下游日志 -> 回调日志

风险:请求头、Token、手机号、银行卡、UserSig 等可能进入日志。查询和分享前必须脱敏。

27. 数据库联调

优先使用统一只读脚本:

php /Users/zhoujiangbin/.codex/skills/dgj-sql-query-runner/scripts/query_dgj_sql.php \
  --env dev \
  --sql "SELECT 1"

27.1 分表

查询前从 Model/常量确认:

物理表 = 基础表名 + '_' + sid % 分片数

常见分片数包括 16、32、64、128,不能凭记忆猜后缀。

rg -n "SUB_NUM|%.*sid|setSubTable|tableName" application/models application/config/tables.php

27.2 数据证据链

flowchart LR
    A[主单] --> B[业务明细]
    B --> C[库存/资金流水]
    C --> D[实时结果]
    A --> E[MQ/外部单号]
    E --> F[下游状态]
    C --> G[报表/DWD]

不要只查一张主表就下结论。

28. MySQL 容器排查

DOCKER_CONTEXT=colima docker ps -a --filter name=mysql57
DOCKER_CONTEXT=colima docker logs --tail 200 mysql57
DOCKER_CONTEXT=colima docker inspect mysql57 --format '{{.State.Status}} {{.State.ExitCode}} {{.State.Error}}'

若持续 Restarting:

  1. 看最后一次退出错误。
  2. 检查 Colima 磁盘空间。
  3. 检查数据卷权限和 MySQL 5.7 架构兼容。
  4. 不删除数据卷,不执行重建数据目录。
  5. 必要时先做只读备份/恢复评估。

29. Redis 联调

Redis 承担:Session、权限缓存、商品集合、请求锁、任务锁、活动购物车等。

安全查询:

DOCKER_CONTEXT=colima docker exec redis redis-cli PING
DOCKER_CONTEXT=colima docker exec redis redis-cli INFO keyspace
DOCKER_CONTEXT=colima docker exec redis redis-cli --scan --pattern '明确前缀*' | head

禁止:

KEYS *
FLUSHALL / FLUSHDB
对未知 key 直接 DEL
把真实 session/token 值贴到文档

29.1 Request 锁

老 OpenAPI 使用 requestId 的 Redis NX 锁,TTL 10 分钟。若请求失败后立即重试提示重复,需要判断锁是否应由正常回调释放,不能直接删 key 掩盖业务未完成。

30. Session 排查

PC 登录依赖 Session 和 Redis/文件配置。跳回登录时检查:

1. 浏览器 Cookie 是否属于 dgj2.localhost。
2. PHP 读取的 SESSION_PATH/Redis 库是否正确。
3. sid/uid/role/login 字段是否完整。
4. 账号、门店、菜单权限是否可用。
5. 是否命中维护、逾期锁站或安全状态。
6. OpenResty 与 PHP 的 Host/HTTPS 判断是否一致。

不要把预发 Cookie 复制进本地长期使用。

31. RabbitMQ 联调

基础检查:

DOCKER_CONTEXT=colima docker exec rabbitmq rabbitmq-diagnostics ping
DOCKER_CONTEXT=colima docker exec rabbitmq rabbitmqctl list_queues name messages consumers
DOCKER_CONTEXT=colima docker exec rabbitmq rabbitmqctl list_bindings source_name destination_name routing_key

31.1 消费者不工作

flowchart TD
    A[消息未消费] --> B{RabbitMQ可用}
    B -->|否| C[容器/磁盘/配置]
    B -->|是| D{队列有消费者}
    D -->|否| E[启动正确CLI Consumer]
    D -->|是| F{binding命中}
    F -->|否| G[核对destination/routing key]
    F -->|是| H{消息反复重投}
    H -->|是| I[查NACK异常和前置数据]
    H -->|否| J[查ACK后业务事务/幂等]

消息重放前保存原 payload、messageId、routing key、headers 和原消费结果。

32. MQ 日志目录

启动脚本会准备:

/data/logs/kzmq/producer/inspiremq.topic

如果 Producer 因日志目录权限失败:

DOCKER_CONTEXT=colima docker exec php74 sh -lc \
  'mkdir -p /data/logs/kzmq/producer/inspiremq.topic && chmod -R 0777 /data/logs/kzmq'

0777 是当前本地兼容处理,不应直接复制到生产权限设计。

33. Mongo 联调

相关集合:

集合用途
dgj_app_logApp/PDA 请求日志
dgj_api_log老 OpenAPI 请求和状态
每站商品集合商品搜索/缓存
机器人会话集合/表具体实现按版本确认

查询要求:

  • 按 requestId、业务单号、时间窗口和 sid 限定。
  • 不导出完整请求头、签名和用户隐私。
  • “Mongo 写失败被 catch”时,文件日志可能有请求但集合没有记录。

34. Elasticsearch 联调

检查顺序:

索引存在 -> mapping -> 文档存在 -> refresh -> 查询 DSL -> 站点查询开关 -> 前端缓存

只读命令示意:

curl -sS 'http://本地ES/_cat/indices?v'
curl -sS 'http://本地ES/索引/_search' \
  -H 'Content-Type: application/json' \
  --data '{"size":1,"query":{"term":{"sku_id":"目标SKU"}}}'

实际地址从配置读取,不把线上地址写入命令记录。

35. 外部系统本地联调

本地通常无法自然收到支付中心、订单中心、OA、调拨中心等回调。

选择顺序:

  1. 使用系统官方开发/预发环境完成真实联调。
  2. 使用已有 Consumer 的受控 resend/test 方法,先阅读实现。
  3. 用本地 RabbitMQ 发送脱敏、唯一的测试消息。
  4. 对纯查询接口使用 Mock。
  5. 不直接调用业务回调方法伪造已支付/已出库结果,除非测试数据完全隔离且有回滚方案。

36. Mock 原则

可以 Mock不应随意 Mock
商品只读查询真实支付成功
地址解析真实退款完成
报表只读响应库存正式扣减/释放
AI/OCR 结果OA 正式审批
通知发送外部订单受理状态

Mock 必须覆盖成功、明确失败、超时、空响应和字段缺失,不是只返回固定成功。

37. 代码改了不生效

flowchart TD
    A[改动不生效] --> B{请求打到本地吗}
    B -->|否| C[域名/代理/Host/浏览器环境]
    B -->|是| D{容器看到新文件吗}
    D -->|否| E[检查SOURCE_DIR挂载]
    D -->|是| F{当前分支/worktree正确吗}
    F -->|否| G[定位真实代码目录]
    F -->|是| H{FPM/opcache缓存}
    H -->|是| I[安全重启php74/openresty]
    H -->|否| J[查路由开关和新旧服务分流]

检查:

pwd
git branch --show-current
git status --short
DOCKER_CONTEXT=colima docker exec php74 sh -lc \
  'stat /www/dgj2.0/目标文件.php && rg -n "新代码特征" /www/dgj2.0/目标文件.php'

38. 404 排查

1. 请求 Host 是否是 dgj2.localhost。
2. OpenResty root 是否 `/www/dgj2.0`。
3. URI 是否需要 `/index.php/`。
4. `routes.php` 是否有显式路由。
5. Controller 文件、类名、方法名大小写是否匹配。
6. App/OpenAPI 是否通过 code 映射,而不是直接 URL 方法。
7. 新旧服务转发开关是否把请求转走。

39. 500 / Fatal 排查

DOCKER_CONTEXT=colima docker logs --tail 200 php74
DOCKER_CONTEXT=colima docker exec php74 sh -lc \
  'find /data/logs/dgj -type f -mmin -10 -print | xargs -r tail -n 80'

优先看第一条 fatal 的文件和行号,不要被后续 502、空响应或前端 JSON 解析错误带偏。

40. 502 / 504 排查

状态常见原因
502FPM 未监听、容器网络、PHP 进程崩溃、FastCGI 配置
504PHP 执行过久、外部接口超时、数据库慢查询、导入导出大文件

时间线:

OpenResty 时间 -> PHP 请求开始 -> SQL/Provider 开始 -> 外部返回/超时 -> PHP 响应

用 RequestId 对齐每段耗时。

41. 数据不对排查

1. 确认环境和 sid。
2. 确认业务主键和分表。
3. 查主单与明细状态。
4. 查库存/资金过程流水。
5. 查实时结果表。
6. 查 Redis/Mongo/ES 缓存。
7. 查 MQ/外部系统状态。
8. 查报表同步时点。

不要把缓存清除当成数据修复。

42. 日志找不到排查

flowchart TD
    A[没有日志] --> B{代码走到 logger 吗}
    B -->|否| C[入口/路由/前置校验]
    B -->|是| D{LOGPATH 是哪里}
    D --> E["/data/logs/dgj"]
    E --> F{logPath/channel正确吗}
    F -->|否| G[按 KzLogger 调用反查]
    F -->|是| H{目录权限/日期后缀}
    H --> I[容器挂载和 RotatingFileHandler]

反查命令:

rg -n "KzLogger::getLogger\(" application/目标目录

43. 请求成功但无业务变化

可能原因:

  • 业务响应只表示“已受理”。
  • 本地事务回滚但 Controller 仍包装了旧响应。
  • 幂等判断提前返回。
  • 事件进入延迟队列。
  • 外部副作用失败。
  • 写入了另一个 sid 的分表。
  • 代码走了新微服务而不是本地 Service。

必须对照主单、明细、流水、消息、外部单号五层证据。

44. MQ 消费成功但数据不对

1. 确认 ACK 是业务成功还是“不可重试错误也 ACK”。
2. 查消息 payload 和业务版本。
3. 查幂等记录是否把新消息当重复。
4. 查原状态是否合法。
5. 查事务提交状态。
6. 查事务后的库存/资金/MQ 副作用。
7. 查乱序消息是否覆盖新状态。

45. 本地与预发差异矩阵

维度本地预发
代码当前工作区已部署分支/构建
数据库本地或显式选择环境共享预发数据
Redis/MQ可本地隔离多服务共享
外部回调通常不自然到达可真实联调
日志容器文件/Mongo远程文件/Kibana
并发单人低并发多人、多实例
定时任务通常手动可能真实运行

复现差异前先把这六项填完整。

46. 预发请求日志

预发页面请求可能只是 DGJ 网关入口,真实错误来自拆分后的采购/销售服务。

排查顺序:

页面路径 -> 本地代码映射 Provider -> DGJ provider 日志 -> 下游 request/provider 日志 -> request_id -> 响应

使用现有 Skill:

dgj-preprod-request-log-inspector
preprod-log-inspector
kz-bastion-log-inspector

远程查询只读,不在知识库保留主机账号和凭据。

47. Kibana

使用 kibana-log-query-runner,按绝对时间、关键词和 RequestId 查询 logstash-YYYY-MM-DD。

推荐关键词组合:

业务单号 + event/routing key + RequestId + Controller/Provider 名

查询结果只总结时间、host、source、事件和错误,不复制完整 Cookie、Token 和大响应体。

48. 时间与时区

项目在 index.php 设置 Asia/Shanghai。Kibana、数据库、MQ header 和外部系统可能使用 UTC 或毫秒时间戳。

每次排查记录:

用户看到的时间 + 时区
DGJ 日志时间 + 时区
数据库 createTime/modifyTime
MQ occurredAt / broker 时间
外部系统时间

不要用模糊的“刚才”“下午”跨系统找日志。

49. Git 与分支安全

git branch --show-current
git status --short
git log -1 --oneline
git diff -- 目标文件

规则:

  • 不覆盖用户未提交改动。
  • 不在 staging 分支直接提交业务改动。
  • 确认实际运行目录不是另一个 worktree。
  • 合并前检查公共文件影响面。
  • 不用 git reset --hard、checkout -- 清理未知改动。

50. PHP 基础验证

DOCKER_CONTEXT=colima docker exec php74 \
  php -l /www/dgj2.0/application/目标文件.php

DOCKER_CONTEXT=colima docker exec php74 \
  php /www/dgj2.0/index.php 目标CLI入口

项目没有统一覆盖所有业务的自动化测试框架时,至少完成:语法、接口正常样本、异常样本、数据库断言、日志和副作用核对。

51. 联调样本规范

每个样本记录:

环境:local/dev/staging
代码分支和 commit:
业务 sid:
业务单号/活动ID/任务号:
请求时间:
RequestId/traceId/messageId:
入口 URL/transCode/event:
请求摘要(脱敏):
预期状态:
实际响应:
数据库证据:
缓存/MQ/外部证据:
是否需要清理:

52. 一次完整联调流程

sequenceDiagram
    participant D as 开发者
    participant H as 本地HTTP/MQ入口
    participant L as DGJ日志
    participant DB as MySQL/Redis/Mongo
    participant E as 外部系统
    D->>D: 确认context/分支/配置
    D->>H: 发唯一测试请求
    H->>L: 记录RequestId和业务键
    H->>DB: 事务/缓存/锁
    H->>E: HTTP或MQ
    E-->>H: 响应/回调
    H->>DB: 最终状态和副作用
    D->>L: 按RequestId核对时间线
    D->>DB: 只读核对主单、明细、流水
    D->>D: 清理测试数据或保留证据

53. 安全要求

风险要求
生产配置混入本地配置切换可逆,运行时验证目标环境
日志泄密Token、Cookie、签名、手机号、银行卡、UserSig 脱敏
本地消费生产 MQ启动 Consumer 前确认 broker
直接改线上数据默认只读,修复需审核和回滚
Redis 全库操作禁止 KEYS/FLUSH,按前缀和业务键
测试支付/退款使用隔离测试单和官方测试通道
重放消息先验证业务幂等,保留原消息
调试开关不把 debug 绕签名/绕权限带入生产

54. 已确认代码风险

等级风险影响
P0旧 App 签名材料硬编码无法安全轮换,源码泄露影响大
P1BaseApp/Inner/Provider 记录完整请求和 header敏感信息进入日志
P1App Mongo 日志写失败被空 catch文件有请求但 Mongo 无证据,且无告警
P1多套 RequestId 生成/读取未统一透传跨服务追踪断链
P1OpenResty access log 关闭入口命中需靠错误日志/应用日志/临时观测
P2CI log_threshold=1框架层信息日志有限,依赖 Monolog
P2本地 MQ 日志目录依赖宽权限初始化重建容器后可能再次失败
P2本地与预发外部依赖混合测试污染和结果不可复现

55. 环境故障修复边界

以下情况优先修环境,不改 DGJ 业务代码:

  • OpenResty 证书不兼容。
  • PHP 扩展/Xdebug ini 语法错误。
  • MySQL 容器无法启动。
  • Docker context 指向错误 daemon。
  • 日志目录/Session 目录权限错误。
  • 容器内 hosts 未映射本地域名。

以下情况才进入业务代码:

  • 请求已到正确 Controller,参数和环境正确。
  • 业务表/缓存/消息证据指向逻辑错误。
  • 相同数据可稳定复现。
  • 已排除外部服务和同步延迟。

56. 日常体检命令

cd /Users/zhoujiangbin/code/docker-dev-env

DOCKER_CONTEXT=colima docker ps --format \
  'table {{.Names}}\t{{.Status}}\t{{.Ports}}'

curl -sS -o /dev/null -w 'DGJ %{http_code} %{time_total}s\n' \
  --max-time 10 \
  http://dgj2.localhost/index.php/passport/login/index

DOCKER_CONTEXT=colima docker exec redis redis-cli PING
DOCKER_CONTEXT=colima docker exec rabbitmq rabbitmq-diagnostics ping
DOCKER_CONTEXT=colima docker exec php74 php -v

如果任一项失败,先处理对应基础层,再开始业务联调。

57. 常用代码检索

# URL / Controller
rg -n "目标路径|目标方法" application/config/routes.php application/controllers

# App / OpenAPI 映射
rg -n "目标code" application/config/appapis.php application/config/apis.php application/config/SaasApis.php

# MQ
rg -n "事件名" application/KzData/Enums/MqEventEnums.php application/controllers/tasks application/Services/Mq

# 日志文件归属
rg -n "KzLogger::getLogger|RequestId" application/目标目录

# 表和分片
rg -n "表常量|SUB_NUM|setSubTable" application/config/tables.php application/models

# 外部 Provider
rg -n "目标路径|requestSer|requestSerAsync" application/Providers application/Services

58. 故障报告模板

现象:
环境 / Docker context:
分支 / commit:
入口与请求时间:
sid / 业务单号:
RequestId / messageId:
HTTP 状态与业务 code:
第一条错误日志:
Controller -> Service -> Model/Provider:
数据库/缓存/MQ证据:
外部系统证据:
已排除项:
根因:
修复:
补偿:
回归:
遗留风险:

59. 回归矩阵

层必测
HTTP200、404、500、超时、登录失效
参数JSON、表单、空字段、非法签名、重复 requestId
数据库正常、无记录、分表、事务回滚、重复键
Redis命中、未命中、锁冲突、TTL、连接失败
MQ正常、重复、乱序、NACK、延迟、死信
外部 HTTP成功、业务失败、超时、空响应、部分成功
日志RequestId 连贯、错误可见、敏感字段脱敏
多环境本地/预发配置与数据不混用

60. 发布前检查清单

  • [ ] Docker context 明确为 Colima。
  • [ ] OpenResty、php74、mysql57、redis、rabbitmq 均健康。
  • [ ] 登录页和目标接口都命中本地代码。
  • [ ] 当前分支、commit、dirty files 已记录。
  • [ ] PHP 容器能看到最新文件。
  • [ ] 数据库、Redis、MQ、外部服务环境已逐项确认。
  • [ ] 请求使用唯一测试业务键。
  • [ ] RequestId/业务单号能定位 Controller、Service、Provider/Consumer 日志。
  • [ ] 主单、明细、流水、缓存、MQ、外部状态已核对。
  • [ ] 重复、乱序、超时和回滚场景已测试。
  • [ ] 日志和截图中没有 Cookie、Token、签名或客户隐私。
  • [ ] 测试数据已清理或标记。
  • [ ] 不需要的本地 Consumer 已停止。
  • [ ] 环境改动有切回方法。

61. 证据文件

主题代码/配置证据
环境、LOGPATHindex.php
CI 日志阈值application/config/config.php
Monolog 与 RequestIdapplication/Components/KzLogger.php、KzLoggerInstance.php
PC/Inner/GPDAapplication/core/BaseController.php
App/PDA 日志与校验application/core/BaseAppController.php
OpenAPI 幂等application/service/OpenService.php、application/core/BaseService.php
Docker 服务和挂载docker-compose.yml、docker-compose.colima.yml
OpenResty 路由services/openresty/conf.d/dgj2.conf
启动和本地修复scripts/start_saas_dgj.sh
路由和接口映射application/config/routes.php、appapis.php、apis.php
MQ 入口application/KzData/Enums/MqEventEnums.php、application/controllers/tasks/*

62. 待补齐

  1. 一键输出容器、HTTP、PHP、DB、Redis、RabbitMQ 和日志目录健康状态的脚本。
  2. 统一从 HTTP header 到 Service、Provider、MQ 和下游的 traceId。
  3. BaseApp、BaseApi 和 BaseProvider 的集中日志脱敏器。
  4. 本地 Mock Server 和可复用的订单/支付/配送契约样本。
  5. 每类 Consumer 的本地启动清单和进程守护方式。
  6. Mongo/ES/Kafka 按业务场景启动的标准脚本。
  7. OpenResty 可按需开启的脱敏 access log。
  8. 本地测试数据命名、隔离和清理规范。

63. 一句话记忆

先证明请求进入了正确的本地代码和正确的环境,再用 RequestId + sid + 业务单号串联日志、主明细、缓存、消息和外部状态;没有这条证据链,就不要急着改代码或改数据。

请求-日志-数据变更追踪卡

多入口请求链路

场景调用方与入口请求载荷/上下文Controller/ConsumerService/Provider汇合点最终业务事实
Web/PC 联调浏览器/curlhost、URI、cookie/session、form/JSON路由目标 Controller领域 Servicerequest ID + 业务单号本地 DB 业务事实
Inner/App/OpenAPIcurl/调用方服务header/signature/API code、sidBaseApi/App/OpenAPI适配 Service外部/来源单号与 PC 共用领域事实
MQ/CLIBroker/命令行destination/event/message;task 参数tasks/*Notify/TaskConsumer/补偿 Servicemessage/task ID异步状态和副作用
外部服务本地 Provider本地单号、请求参数调用方BaseProvider 子类request ID + 外部单号外部受理与回调

日志证据矩阵

| 链路段 | 日志来源 | 可检索锚点 | 成功信号 | 失败信号 | 与下一段关联方式 | | --- | --- | --- | --- | --- | --- | --- | | 环境/路由 | Web 访问日志、CI_ENV、routes/apis/appapis | host、URI、API code、request_id | 命中本地目标方法 | 请求去了错误容器/环境/路由 | 类方法进入应用日志 | | 应用 | LOGPATH/application/logs、KzLogger | request ID、sid、业务单号、类方法 | Service 完成/commit | exception、rollback、错误码 | 单号查数据库 | | 数据库/缓存 | SQL 慢错日志、只读查询、Redis/ES | PK、单号、cache key/index | 主明细和派生值一致 | 表/库/分片错、缓存旧 | 业务键进入 MQ/Provider | | MQ/外部 | Consumer/Provider 两端日志 | message ID、routing key、外部 request/order ID | ACK/对方成功/回调完成 | NACK、timeout、对方未收到 | 外部键映射本地单号 |

环节数据变更台账

步骤代码位置事务读取事实写入表/缓存/MQ字段或数量变化回查证据
确认环境config/env/database/redis/mq事务外CI_ENV、容器、host、配置名无零业务变化进程环境、只读连接目标
重放请求目标 Controller事务外到业务事务脱敏请求、header、用户站点请求日志输入 -> 标准上下文curl 响应、request ID
业务落库目标 Service本地事务旧状态/数量/金额主明细/流水old -> new 或失败 0 写入前后 SQL 快照、影响行数
异步传播MqSer/Provider/Consumercommit 后新业务事实MQ/外部/缓存派生状态逐步追平消息/外部 ID、ACK、回调
清理测试领域撤销/反向流程独立事务测试业务最终态反向单/关闭状态通过业务动作恢复,不直接删关键流水原单与反向单、库存资金平衡

子模块追踪:local-start 本地容器启动与健康检查

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
启动体检Docker/Colima 启动 DGJ2container/service、port、CI_ENVapplication/config/env.php、application/config/config.php容器、OpenResty/PHP-FPM、挂载、配置环境名环境检查事务外,业务 DB 不写container status + health URL + access/error log502 分层查代理、FPM、挂载;不通过改业务代码规避环境问题
最小验收首页/健康接口和 PHP 语法URI、request IDapplication/core/BaseController.php路由、session、日志目录和 DB 只读连接请求只读 不写HTTP code + request ID + PHP error log环境未通不执行有副作用联调;修复后重跑五层健康检查

子模块追踪:local-pc PC 请求联调

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
复现请求浏览器/curl 调 /scm/*method、URI、session、sid、billNoapplication/core/BaseController.php路由、登录、权限、query/form/JSON 和当前业务态校验外零写;目标 Service 本地事务 old -> newaccess request ID + URI + user/sid + billNo401/403/404/500 分层定位;超时按 billNo 查是否已提交
结果回查响应后核对业务事实request ID、返回单号application/Components/KzLogger.phpController/Service 日志、主明细和后置 MQ查询只读 不写request ID + billNo + affected rowsHTTP 200 仍判断业务码;用领域撤销清理测试数据

子模块追踪:local-app-pda App 与 PDA 请求联调

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
网关/直连tradeCode 或 PDA Controller 请求tradeCode/URI、token、sid、设备业务键application/config/appapis.php -> application/core/BaseAppController.phpcode 映射、登录上下文、载荷形态和目标类路由鉴权不写;领域本地事务 old -> newrequest ID + tradeCode/URI + sid + billNocode 未映射与直连协议分开查;禁止互换接口猜测
扫码重试PDA 出入库/盘点响应不确定device request、billNo、SKU/locationapplication/core/BaseAppController.php业务单、库存流水和当前状态回查只读;确认未执行才重试request ID + billNo + SKU + transType网络超时先查流水,避免重复库存;敏感 token 不写文档

子模块追踪:local-openapi 老 OpenAPI 联调

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
动态分发外部请求 transCodeappId、timestamp、requestId、来源单application/config/apis.php -> application/service/OpenService.php签名、时间窗、code 映射、幂等和载荷鉴权失败零写;目标 API 本地事务写业务事实request ID + transCode + external/local orderNo200 仍判断业务码;日志脱敏,不保存凭证
重复/超时相同来源请求重放requestId、sourceOrderNoapplication/service/OpenService.php既有映射、主单和副作用已完成 new -> new,新增单据/流水 0old/new request IDs + sourceOrderNo先按来源单回查;只补缺失回调或响应,不重复建单

子模块追踪:local-inner Inner API 联调

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
内部请求/inner/* 服务间调用URI、内部头、sid、JSON、业务 IDapplication/config/routes.php -> application/core/BaseService.php路由、内部身份、用户/站点上下文和参数校验外零写;Service 本地事务 old -> newrequest ID + URI + sid + business ID本地 mock 身份不等于预发合同;未授权零业务写入
响应验收success/code/data 返回request ID、业务 IDapplication/core/BaseService.phpService 返回、异常和持久化结果响应阶段 DB 不变;异步链另查request ID + business code + affected rows成功响应后回查主表;失败仅清理本次测试事实

子模块追踪:local-mq RabbitMQ 消费联调

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
启动消费CLI 启动目标 Notifydestination、routing key、eventapplication/config/mq.php -> application/KzData/Enums/MqEventEnums.phpBroker 配置名、binding、消费者进程和 handler启动本身不写业务 DBprocess PID + destination/routing + startup log队列/凭证只引用配置键;进程不工作先查 CLI 和 binding
消息验收发布脱敏测试消息message ID、稳定业务键application/Services/Mq/MqSer.php当前业务态、幂等行、ACK/NACK单消息本地事务 old -> new;ACK 不属于 DB 事务message ID + event + billNo + ACK重投前查业务事实;已完成重放副作用 0

子模块追踪:local-cli CLI 与定时任务联调

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
任务执行PHP CLI 调 tasks/methodtask、参数、time window、limitapplication/controllers/tasks/FlashSaleTask.phpis_cli、候选状态、时间和批量上限每记录本地事务 old -> new,或 dry/query 只读task + batch + scanned/success/fail IDs本地先小批且使用测试数据;禁止无范围跑环境全量
幂等重跑中断/补偿任务再次执行batch、business IDsapplication/controllers/tasks/GoodsEsCache.php已完成项、失败项、锁和水位已完成影响行 0;只补失败项task + batch + affected rows清锁前确认进程;水位不越过失败数据

子模块追踪:local-data MySQL、Redis、Mongo 与 ES 联调

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
连接定位本地四类数据组件检查environment、db/index/key/collectionapplication/config/database.php、application/config/redis.php、application/config/mongodb.php、application/config/elasticsearch.php实际连接目标、分片规则和只读样本健康检查只读 不写config name + ping/query result + target type不输出密码;环境目标不确定时停止写入测试
跨层核对页面数据不一致sid、SKU/billNo、cache/index keyapplication/config/tables.phpMySQL 主事实、Redis/Mongo/ES 派生值和时间查询只读;修复只更新明确失败派生层 old -> sourcebusiness key + each-layer timestamp主库为权威;禁止用缓存反写业务主表

子模块追踪:local-provider 外部 Provider 与 Mock 联调

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
请求构造本地业务调用外部系统provider/endpoint、request ID、业务单application/Providers/BaseProvider.php环境 base URL、超时、脱敏 payload 和响应合同外部调用事务外;mock 不写真实外部系统request ID + provider + latency + HTTP/business codeMock 固定成功/失败/超时样本;不伪造生产已受理证据
回调模拟模拟外部回调/乱序/重复event、message ID、business keyapplication/Services/Mq/MqSer.php本地当前态和幂等事实单回调本地事务;重复/乱序零非法副作用message IDs + business key + row count回归成功、重复、迟到、失败四条;凭证仅用本地配置

子模块追踪:preprod-log 预发日志、Kibana 与环境差异

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
日志串查预发接口/MQ/任务异常absolute time、request/message ID、billNo、sidapplication/Components/KzLogger.php访问、应用、Provider、Consumer 日志和时区日志查询只读 不写request ID + business key + host/index + timeline时间统一到绝对时区;无权限时记录缺失证据,不猜日志内容
环境对比本地正常预发失败config names、route、consumer/versionapplication/config/env.php、application/config/SaasApis.php代码版本、配置键、进程、数据和外部合同对比只读;修复按所属系统 old config/process -> intendedcommit/version + config key names + health result不记录配置值;业务补偿先证明代码/配置修复已生效