[BUG] cwlogs: every PutLogEvents batch rewrites the entire events store — quadratic write amplification can saturate the host disk
What happens
CloudWatch Logs persistence serializes the entire events store to data/cwlogs-events.json (write to .tmp, rename) on every PutLogEvents batch. The write cost of one incoming log line is therefore proportional to all events ever stored, and total disk traffic grows quadratically with event count.
Why it matters
Any steady log producer eventually saturates the host's disk. Observed on a small real deployment (Floci 1.7.0, community edition, two ECS-emulated apps shipping container logs via the awslogs driver):
- ~62k events accumulated over ~20h from one chatty Celery worker (
-l info, ~1 line/s) - store grew to 41 MB, rewritten more than once per second
- the
applicationprocess wrote a sustained 54–74 MB/s (measured via/proc/<pid>/io), withcwlogs-events.json.tmpits only open data file - on an HDD-backed ZFS host this saturated the pool: 4–14 s transaction syncs, other containers' processes in D-state, docker builds 8× slower, and eventually the Floci data plane itself browned out
The producer writing ~2 KB/s of logs caused ~70 MB/s of disk writes — a ~35,000× amplification at this store size, and it only grows.
Reproduce (Floci 1.7.0)
aws --endpoint-url http://localhost:4566 logs create-log-group --log-group-name /t
aws --endpoint-url http://localhost:4566 logs create-log-stream --log-group-name /t --log-stream-name s
# feed it a modest stream and watch the process's write_bytes explode as the store grows
for i in $(seq 1 100000); do
aws --endpoint-url http://localhost:4566 logs put-log-events --log-group-name /t --log-stream-name s \
--log-events timestamp=$(date +%s%3N),message="line $i" >/dev/null
done
# watch: awk '/write_bytes/{print $2}' /proc/<floci-pid>/io (delta per second ≈ current store size × batch rate)Expected Ingesting one log batch should cost O(batch), not O(all events ever). Any of:
- append-only journal (JSONL) with periodic compaction,
- per-stream files so a batch touches only its stream,
- debounced/periodic persistence instead of per-batch,
- and/or honoring
PutRetentionPolicy+ a size cap so the store cannot grow unbounded.
Workaround we use meanwhile: run app loggers at warning, and periodically DeleteLogGroup (or stop Floci and remove data/cwlogs-events.json).
Source: floci-io/floci