Files

57 lines
5.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 后端性能日志排查
此功能不需要安装 `py-spy`、`perf` 等工具。后台会为业务 `/api/` 请求打印一行简洁耗时(健康检查和 worker 池控制接口除外);超过 500 ms、返回 5xx 或抛出异常的请求会附带分阶段细节。每 5 秒最多报告一次超过 200 ms 的事件循环卡顿。日志不记录请求体、聊天内容、查询参数、SQL 原文、账号信息或密钥。
## 查看慢接口阶段耗时
更新并重启后台后,在宿主机执行:
```bash
docker logs --since 10m cmzs-deerflow-deerflow-backend-1 2>&1 | grep 'PERF'
```
慢请求会有一行 `PERF http_request` 日志,主要字段:
- `total_ms`:完整请求耗时。
- `headers_ms`:服务开始返回响应头前的耗时;大通常说明服务端处理或等待较慢。
- `endpoint_ms`:接口函数本身的耗时。
- `outside_handler_ms`:接口函数以外的耗时,包括鉴权、中间件、依赖解析和响应序列化。
- `stages`:接口内部分阶段的耗时,单位为毫秒。
- `event_loop_lag_ms`:最近测得的主事件循环延迟。
- `node`、`worker_access_ms`、`worker_upstream_headers_ms`、`worker_fallback`:请求是否走子 work、代理耗时,以及是否因容量不足回退主服务。
- `api_inflight_start` / `route_inflight_start`:请求刚进入时正在处理的 API 总数、同一路由请求数;`*_end` 是该请求结束记录时仍在处理的数量。
- `db_pool`:慢请求、异常请求和并发达到 8 个时,记录业务数据库连接池已借出数、池大小和溢出连接数。用于判断首屏并发/连续刷新是否挤满 MySQL 连接池。
- `exception_type`:只记录异常类型,不记录可能含敏感数据的异常消息。
- `status=499`:浏览器刷新、切页或取消请求导致服务端提前结束,不表示接口内部失败。
接口 INFO 日志依赖后台日志级别允许 INFO。若 `config.yaml` 中设置为 WARNING,请临时调到 INFO;慢请求和 5xx 仍会以 WARNING/ERROR 级别记录。
重点接口的 `stages` 含义:
- `auth_options`:`load_system_settings` 是系统设置读取;`count_admin_users` 是业务库查询。
- `agents_list`:`agents_*_query_db` 和 `*_db` 是数据库调用;`agent_response_models`、`agents_filter_and_sort` 是进程内转换/排序;`agents_*_assembly` 汇总列表组装耗时。
- `llmwiki_knowledge_bases`:`weknora_knowledge_base_list_wait` 是等待 WeKnora 列表结果;`local_knowledge_base_query_db` 是本地数据库查询;`conversation_deposit_mapping_sync` 是会话知识库映射同步。
- `llmwiki_agent_knowledge_bases`:`actor_and_agent_access` 是用户与智能体权限查询;`load_agent_binding_config` 是读取智能体配置文件;`local_knowledge_base_mapping_query` 是按智能体绑定 ID 读取本地映射;`weknora_knowledge_base_list_wait` 是等待远端列表。
知识库列表接口(`/api/llmwiki/knowledge-bases` 和智能体绑定列表 `/api/llmwiki/agents/{id}/knowledge-bases`)会等待 WeKnora 列表请求,进程内缓存有效期为 15 秒。若 `PERF http_request` 的 `stages.weknora_knowledge_base_list_wait` 接近 16 秒,同时出现相近耗时的 `PERF weknora_knowledge_base_list upstream_ms=...`,就能确认主要耗时在 WeKnora 请求。`PERF weknora_http_request` 会把远端目录请求拆成 `auth_ms`(获取/刷新 WeKnora 登录凭据)与 `network_ms`(HTTP 请求等待);这样能看出慢在登录还是远端 API 网络/处理。若远端耗时很快但接口仍慢,则看其他阶段。智能体绑定接口另记录 `actor_and_agent_access`(权限与智能体查询)、`load_agent_binding_config`(配置文件读取)和 `local_knowledge_base_mapping_query`(本地数据库映射查询)。
ORM 数据库执行时间超过 500 ms 会打印 `PERF db_query`,包含请求 ID、数据库类型、SQL 操作类型、耗时和 SQL 指纹,不包含 SQL 语句和参数。请求 ID 与 `http_request` 行相同,可据此判断慢 SQL 属于哪个接口。SQL 错误只记录错误类型。可用 `DEERFLOW_SLOW_SQL_LOG_MS` 单独调整数据库慢查询阈值。
首屏或反复刷新若引起请求洪峰,可看同一时间 `api_inflight_start`、`route_inflight_start` 是否升高,以及 `db_pool.checked_out` 是否逼近 `size + max_overflow`。如果接口等待明显但没有慢 SQL,重点看 `event_loop_lag_ms` 和 `outside_handler_ms`;这表示等待可能发生在连接获取、文件/磁盘、鉴权中间件或其它同步代码中。
如果 `total_ms` 很高、接口 `stages` 都很低,或同时出现 `PERF event_loop_stall`,问题更可能在接口函数之外的中间件/同步代码,或事件循环被其他任务占用。可以在卡顿发生时抓当下正在执行的 Python 函数。
## 抓当前 Python 函数堆栈
后台启动时会注册标准库 `faulthandler` 的 `SIGUSR1` 处理器。先在宿主机查容器里的 Python 主机 PID,再发信号:
```bash
docker top cmzs-deerflow-deerflow-backend-1 -eo pid,ppid,comm,args
sudo kill -USR1 <上一步查到的Python主机PID>
docker logs --since 2m cmzs-deerflow-deerflow-backend-1 2>&1 | less
```
在 `Current thread` 段查看最忙线程当时的 Python 文件和函数;其它线程也会一起输出。请在 CPU 正高时连续抓 2 到 3 次,每次间隔几秒:同一个函数反复出现通常是持续热点,不同调用栈则可能是瞬时任务。
若运行环境已有程序占用 `SIGUSR1`,可在后台容器环境设置 `DEERFLOW_ENABLE_STACK_DUMP=0` 关闭此处理器。额外详细输出可临时设置 `DEERFLOW_PERF_DIAGNOSTICS=1`,只会逐次记录 `options`、`agents`、知识库列表和智能体绑定知识库接口;HTTP 慢请求阈值可通过 `DEERFLOW_SLOW_REQUEST_LOG_MS` 调整,默认 500 ms。修改环境变量后需重启后台。