Firehose: managed delivery and its limits

Lesson 3 of 5 in Streaming at Scale.

Firehose is the answer to a question people rarely ask plainly: how do I get records into the lake, continuously, with nobody on call? There is no shard count, no consumer to write, no checkpoint and no scaling policy. You configure a source, a destination, two buffering numbers and optionally a transform, and the service delivers.

The numbers are the lesson, because every one of them has a question built on it.

Buffering. For Amazon S3, buffer size is 1–128 MB and buffer interval 0–900 seconds, and Firehose flushes when either is reached. So the interval is a latency ceiling and the size is a file-size floor, and together they are the dial that decides whether you get the small-files problem downstream. A 60-second interval on a quiet stream produces 1,440 objects a day per prefix; 128 MB / 900 seconds produces a handful of well-sized ones at up to fifteen minutes of delay.

What turning on the good features costs you. Enabling Parquet or ORC conversion or dynamic partitioning raises the minimum buffer size to 64 MB, with 128 MB the default. Zero buffering is unavailable with dynamic partitioning. And with dynamic partitioning Firehose buffers in several internal stages, so end-to-end delay can be about 1.5 times the configured interval — a pipeline promised "60-second freshness" can legitimately deliver in 90.

The ceiling that produces a real incident. Each active partition holds its own buffer, and there are 500 active partitions per delivery stream. Past that, the overflow records go to the S3 error prefix with activePartitionExceeded — data in the wrong place rather than data lost, which is a distinction worth making in an answer.

And one behaviour that is easy to miss: when delivery falls behind ingestion, Firehose raises its own buffer size to catch up. So the file sizes you observe in production can exceed the ones you configured, and that is the service protecting durability rather than a misconfiguration.

Which streaming component a requirement admits. Read down the column for the requirement the stem states most precisely — the first "no" is the answer.
RequirementFirehose aloneData StreamsData Streams + Firehose

Land records in S3 with no code

yes — this is its purpose

no — you write a consumer

yes

Reprocess last week after a bug

no — nothing is retained

yes, within the retention window

yes, plus the raw S3 copy

Several independent consumers

no — one source, one destination

yes, with enhanced fan-out past two or three

yes

Sub-second end-to-end latency

no — the floor is the buffer interval

yes, especially with enhanced fan-out

yes, on the stream path

Per-key ordering

no — a buffer makes no ordering promise

yes, per partition key

yes, on the stream path

Convert to Parquet on the way in

yes, against a Catalog table

no — your consumer does it

yes

Nothing to size or scale

yes

only in on-demand mode

on-demand, yes

Key terms: Amazon Data Firehose, Firehose buffering hints, Dynamic partitioning, Record format conversion