Per-task logging costs a third of worker throughput
維護者通常 1 天內回覆
還沒有人認領這個 Issue。
評估
- 難度
- 3/5
- 預估耗時
- 1-2 天
- 新手友好度
- 68/100
- Issue 類型
- 缺陷
- 描述清晰度
- 基本清楚
- 活躍度
- 活躍
- 領域
- backend, cli, observability, performance
研究方向
Start with threadmill/executor.py, especially configure_logging, the worker command options, and the per-task executor log calls. Trace how TaskExecutor receives logging configuration and how Django's task signal receivers inherit the root level. Done means the worker exposes a configurable level, avoids forcing INFO, and treats per-task executor messages as debug detail while preserving operator control of django.tasks.
由索引模型根據 Issue 內容生成。
描述
Profiling a drain (20,000 echo tasks, one process, one thread, prefetch 128) puts logging at roughly 70 µs of client CPU per task, against a recorded per-task wall of 184 µs. That is about 38% of the worker's throughput, and it is the single largest Python cost in the loop - larger than the Redis round trips it sits next to.
What emits four JSON records per task
threadmill/executor.pylogsExecuting task ...and thenTask ... succeeded(or failed) at INFO for every task.- Django's own
django.tasks.signalsreceivers (log_task_started,log_task_finished) log once more each. They are registered at import and sit at NOTSET, so they inherit the root logger's level. threadmill/executor.py'sconfigure_loggingsets the root logger toINFOunconditionally, so all four records are formatted and written.- The worker's default formatter is
JsonFormatter, which builds a payload dict andjson.dumpses it per record, then writes to stdout and flushes.
Measured inside that 70 µs: 51 µs in StreamHandler.emit and 36 µs in JsonFormatter.format/json.dumps - the formatting, not the log call itself. record_task's lock, by contrast, costs 0.35 µs, and normalize_json 0.5 µs.
Why this is a defect and not just a tuning knob
There is no way to quieten a production worker: configure_logging hardcodes root_logger.setLevel(logging.INFO), and the command exposes --log-format but no --log-level. A deployment that wants WARNING output cannot get it, and it pays a JSON encode and a stdout flush per task for the privilege.
Suggested fix
- Add a level option to the worker command (and to
TaskExecutor), defaulting to something quiet. - Demote the two per-task executor records to
DEBUG; "task started/succeeded" is trace-level detail, and the task itself is the interesting signal. - Leave the level of
django.tasksto the operator rather than forcing the root logger to INFO.
Benchmark fairness
The comparison harness runs celery and dramatiq with --loglevel=WARNING, while threadmill currently cannot run below INFO, so part of the chart gap is threadmill logging its own benchmark. Fixing this makes the comparison apples-to-apples as well as making production faster.
Discovered while validating per-task performance claims; the profiling numbers are from a loaded machine, so treat the shares as the durable result and the absolute microseconds as this box's.
- 主要語言
- Python
- 星號
- 21
- 分支
- 2
- 平均合併
- 12 小時 39 分鐘
- 30 天內合併 PR
- 27
環境準備
- 沒有 Dockerfile 或 Docker Compose 檔案
- 沒有 Pull Request 範本
- 閱讀貢獻指南
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
相似的 Issue
-
Use mhctools predictor_required=False for saved-result rescoring可能已有人在做 @iskandr 今天認領。 未關閉
難度 2/5 1-3 小時 新手友好度 72/100
維護者通常 1 天內回覆
-
難度 2/5 1-3 小時 新手友好度 79/100
-
難度 1/5 1 小時以內 新手友好度 85/100
521xueweihan/HelloGitHub#4051 · 1 則留言 ·
-
bug documentation
難度 2/5 1-3 小時 新手友好度 78/100
awslabs/visual-asset-management-system#514 ·
維護者通常 1 天內回覆
-
backend bug spec:REQ-053
難度 2/5 1-3 小時 新手友好度 66/100
nolte/kamerplanter#2547 ·
維護者通常 1 天內回覆