了解 TimescaleDB 背景工作者和作业

发布: (2026年3月1日 GMT+8 18:00)
7 分钟阅读
原文: Dev.to

Source: Dev.to

请提供您希望翻译的完整文本内容(除代码块和 URL 之外),我会将其翻译成简体中文并保持原有的格式、Markdown 语法和技术术语不变。谢谢!

Source:

背景工作者的工作机制

每次调用 add_compression_policy()add_retention_policy()add_continuous_aggregate_policy() 时,TimescaleDB 都会注册一个计划任务。每个任务都在 PostgreSQL 背景工作者中运行——这是一个独立的进程,运行在任何客户端连接之外。

可用背景工作者的数量受两个参数控制:

设置描述默认
timescaledb.max_background_workersTimescaleDB 自己调度器的上限8‑16
max_worker_processesPostgreSQL 的全局限制,供所有扩展、并行查询和逻辑复制共享

您可以使用以下查询检查当前配置:

SELECT name, setting, unit
FROM pg_settings
WHERE name IN (
    'timescaledb.max_background_workers',
    'max_worker_processes',
    'max_parallel_workers'
)
ORDER BY name;

并使用下面的查询列出所有活动任务:

SELECT
    job_id,
    proc_name,
    hypertable_name,
    schedule_interval,
    scheduled AS is_active
FROM timescaledb_information.jobs
WHERE scheduled = true
ORDER BY proc_name, hypertable_name;

Source:

疲劳是如何产生的

数学计算直接且毫不留情。

  • 每个带有压缩、保留 连续聚合的 hypertable 会产生 三个 作业。
  • 八个 hypertable → 24 个作业。
  • 再加上 TimescaleDB 的内部维护任务,总数很容易超过 100 个计划作业。

默认的 max_background_workers 为 16,根本不是为这种负载设计的。

当作业无法获取 worker 时,它 不会 抛出错误,只是停留在调度器的队列中。如果在调度间隔内没有空闲 worker,下一次调用就会排在当前作业后面。随着时间推移,积压会形成,并在每个周期中进一步叠加。

最坏情况: 作业的执行时间超过了它的调度间隔。
一个需要 15 分钟完成但每 10 分钟调度一次的压缩作业会永久占用一个 worker 插槽,永远追不上进度。每个周期都会再加入一个排队的调用,导致其他作业类型被饿死。

诊断问题

将作业计数与工作者限制进行比较

WITH worker_config AS (
    SELECT current_setting('timescaledb.max_background_workers')::int AS max_workers
),
active_jobs AS (
    SELECT count(*) AS total_scheduled_jobs
    FROM timescaledb_information.jobs
    WHERE scheduled = true
)
SELECT
    wc.max_workers,
    aj.total_scheduled_jobs,
    CASE
        WHEN aj.total_scheduled_jobs = 0 THEN 'FAILING'
        WHEN js.total_runs = 0 THEN 'NEVER RUN -- likely queued'
        ELSE 'OK'
    END AS health_status
FROM timescaledb_information.jobs j
JOIN timescaledb_information.job_stats js ON j.job_id = js.job_id
ORDER BY js.total_failures DESC, j.proc_name;

关键警告信号

  • total_runs = 0 – 作业已注册但从未获取到工作者(纯队列饥饿)。
  • consecutive_failures 上升 – 工作者已获取但作业失败(通常是锁争用或压缩期间的 OOM)。
  • last_run_duration > schedule_interval – 作业在下一次调用前永远无法完成,永久阻塞工作者槽位。

合理调配工作池规模

公式很简单:

total_policies + 2 (internal jobs) = minimum max_background_workers

使用以下查询计算精确的建议值:

WITH policy_count AS (
    SELECT count(*) AS total_jobs
    FROM timescaledb_information.jobs
    WHERE scheduled = true
)
SELECT
    total_jobs,
    total_jobs + 2 AS recommended_workers,
    'ALTER SYSTEM SET timescaledb.max_background_workers = '
        || (total_jobs + 2) AS sql_to_run
FROM policy_count;

应用更改:

ALTER SYSTEM SET timescaledb.max_background_workers = 28;
ALTER SYSTEM SET max_worker_processes = 32;
-- Requires a full PostgreSQL restart – pg_reload_conf() is NOT sufficient

过度配置成本低。每个空闲的后台工作进程大约消耗 5‑10 MB 内存且不占用 CPU。将 max_background_workers 设置为 32 或 64,即使服务器上运行 20 个作业,也不会产生可测量的性能损失。相反,配置不足会悄然破坏整个自动化流水线。

关于 PostgreSQL 18 + TimescaleDB 2.24 的说明

如果您在使用 PostgreSQL 18 与 TimescaleDB 2.24,需注意通过 add_job() 注册的自定义函数会出现 “cache lookup failed for function” 错误。该版本组合下的后台工作进程无法解析 public‑schema 中的函数。解决办法是将任何自定义的计划任务交给系统 cron 处理,而让 TimescaleDB 正常执行其内置策略(压缩、保留、聚合刷新)。

Source:

防护清单

  • 在每个新 hypertable 之后统计作业数量。
    每个带完整策略的 hypertable 会添加 3 个作业。请主动更新 worker 设置。

  • 定期监控 total_failuresconsecutive_failures
    每周查询 timescaledb_information.job_stats,或设置自动化监控。

  • 确保作业执行时长低于调度间隔。
    last_run_duration 接近 schedule_interval 时,考虑:

    • 增加间隔时间,
    • 减小块大小,或
    • 添加更多 worker。
  • max_worker_processes 设置为高于 max_background_workers
    为并行查询和逻辑复制留出余量。

  • 记住:这两个设置都需要完整的 PostgreSQL 重启。
    请在维护窗口期间进行更改。

  • 把 worker 大小视为 hypertable 设置的一部分。
    添加策略 → 添加 worker。切勿把它当作事后补救。

背景 worker 耗尽是完全可以预防的。修复只需一条 SQL 语句和一次重启。难点在于在自动化静默停止之前就能发现并处理它。

0 浏览
Back to Blog

相关文章

阅读更多 »

当工作成为心理健康风险时

markdown !Ravi Mishrahttps://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fu...