DescribeLogDirs icon
OutputValues icon
Loop icon
TopicDescribe icon
Log icon
If icon
SlackIncomingWebhook icon
TopicUpdate icon
Fail icon
LoopUntil icon
Schedule icon

Kafka Topic Disk Budget Guard

Measure Kafka topic disk usage with DescribeLogDirs, flag topics over budget, cap them with per-partition retention.bytes and verify the reclaim.

Categories
DataInfrastructure

Kafka brokers usually run out of disk because of one topic, not the total. Typical causes:

  • a clickstream topic created with retention.ms=-1 "for now";
  • a topic whose traffic grew tenfold;
  • a debugging topic nobody owns.

Time-based retention does not help when the volume per day changes, and nothing warns before the disk alarm.

This blueprint reads the on-disk size of every topic with the AdminClient and compares it with a budget. It alerts Slack, and can cap the topics over budget with retention.bytes, then describe them again to verify. Optionally it waits until the broker has deleted the old segments and the space is back.

This blueprint was created by zkasuran.

The budget

  • default_budget_mb applies to every topic, and budgets_mb overrides it per topic. Internal topics (__consumer_offsets...) are skipped.
  • A budget is the total on disk: all partitions, all replicas, all brokers, as returned by DescribeLogDirs.
  • retention.bytes is enforced per partition replica, so the value set is budget / (partitions × replication factor). A 20 MB budget on a 4-partition topic sets retention.bytes=5242880.
  • Compacted topics are reported but never capped: a size limit would delete live keys.
  • A topic already capped at its target is not reported again. Its overshoot is the active segments, which Kafka never deletes.

How it works

  1. log_dirs (io.kestra.plugin.kafka.DescribeLogDirs, read-only) returns the size of every topic. over keeps those above their budget.
  2. describe_over (io.kestra.plugin.core.flow.Loop over io.kestra.plugin.kafka.TopicDescribe) reads the partition count, replication factor and retention configs of each one.
  3. plan computes the per-partition retention.bytes, flags unbounded topics (retention.ms and retention.bytes both -1), and marks compacted ones as report only. summary logs it.
  4. route (io.kestra.plugin.core.flow.If):
    • within budget: logs it.
    • over budget: alert posts to Slack.
      • remediate_gate runs only when auto_remediate is true and dry_run is false.
      • remediate sets retention.bytes with TopicUpdate, then verify and verify_result describe the topics again and fail on any other value.
      • With wait_for_reclaim, wait_reclaim (io.kestra.plugin.core.flow.LoopUntil) polls DescribeLogDirs every 15 seconds until each topic is within 125% of its budget, then reclaimed logs the sizes before and after.
  5. errors alerts Slack when the flow fails, for example on an unreachable broker.

What you get

  • Disk usage per topic, measured by the brokers, against a budget you set.
  • The retention.bytes arithmetic done for you, per partition and replica.
  • Proof that the cap is set, and optionally that the space really came back.

Who it's for

  • Platform teams running Kafka for many producers on fixed-size disks.
  • SREs who get disk alarms on brokers and want to know which topic caused them.
  • Teams evaluating the Kafka plugin who want an example of DescribeLogDirs driving TopicUpdate.

Why orchestrate this with Kestra

kafka-log-dirs.sh prints raw JSON per partition. Kestra sums it per topic on a schedule and compares it with budgets kept next to the flow. It turns overruns into a Slack alert, applies the cap only behind auto_remediate and dry_run, waits for the broker with LoopUntil, and keeps an execution history of every topic's size over time.

Tested end to end

On Kestra 2.0.5 OSS against Apache Kafka 3.9.1 (KRaft, log.retention.check.interval.ms=10000, 1 MB segments), with a local HTTP sink standing in for Slack. Topics:

  • clickstream: 4 partitions, 58 MB, retention.ms=-1;
  • orders: 4 MB, with a 50 MB budget;
  • customers: compacted, 1.8 MB.
Run Inputs Result
1 defaults (20 MB) clickstream over budget with no limit, target retention.bytes=5242880. Alert sent
2 default_budget_mb: 1 Adds customers, reported as compacted, never capped. orders within its 50 MB override
3 auto_remediate: true, dry_run: true Same report. kafka-configs.sh shows no retention.bytes on clickstream
4 auto_remediate: true, dry_run: false, wait_for_reclaim: true retention.bytes=5242880 set and verified. kafka-configs.sh shows the same. clickstream went from 57 MB to 22.3 MB on disk
5 defaults again Nothing to do: clickstream is capped, the 2.3 MB above budget is the active segments
6 unreachable broker errors alert sent

Prerequisites

  • A Kafka cluster reachable from the Kestra worker, and a principal allowed to describe the cluster and topics and, for remediation, alter topic configs.
  • Local testing:
    • docker run -d --name kafka -p 9092:9092 apache/kafka:3.9.1;
    • create a topic with --config retention.ms=-1 --config segment.bytes=1048576;
    • fill it with kafka-producer-perf-test.sh.

Secrets

  • SLACK_WEBHOOK_URL: used by alert and the errors block. In Kestra OSS, provide it as the base64-encoded environment variable SECRET_SLACK_WEBHOOK_URL.

Inputs

Input Default Purpose
bootstrap_servers localhost:9092 Brokers
default_budget_mb 20 Budget per topic
budgets_mb {"orders": 50} Per-topic overrides
wait_for_reclaim false Wait for the space to come back
auto_remediate false Allow TopicUpdate
dry_run true Must be false for a change to apply

Quick start

  1. Add the SLACK_WEBHOOK_URL secret.
  2. Import the flow and set bootstrap_servers, default_budget_mb and budgets_mb for your largest topics.
  3. Run it once and read the topics over budget.
  4. Check with the owners that the data beyond the budget can go, then run with auto_remediate: true and dry_run: false.
  5. Enable the hourly trigger, which always runs in safe mode.

How to extend

  • Alert at 80% of the budget, before the topic is over.
  • Load budgets from a namespace file or Git, owned by the teams that produce to each topic.
  • Track the size per topic in a table to forecast when a broker disk will be full.
  • Ask for approval with a Pause before capping topics that hold more than a day of data.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.