feat(ingest)!: bound the decoded telemetry held in flight - #263
Merged
Merged
Conversation
Every other change in this series makes one commit cost less. None of them makes the process bounded. Ingest concurrency is HTTP/2 streams times connections -- net/http allows 250 streams per connection by default and nothing here lowers it -- and each handler holds its decoded batch and its proto until the commit is durably acknowledged. Nothing counted how much was in flight at once, so a large enough burst was still an out-of-memory kill however cheap an individual batch became. Submit now charges a request against a byte ceiling on entry and releases it on return. That is the right place: both transports funnel through it, and it already blocks until durable acknowledgement, so the ledger measures exactly what the process is holding rather than what arrived on the wire. A refusal returns RESOURCE_EXHAUSTED over gRPC and the existing 503 over HTTP. Both are what the OTLP specification tells an exporter to back off and retry on, so a shed request is delayed rather than lost. The fanout_ingest_shed_total counter makes that visible before it becomes a support question. An empty ledger admits any single request however large: one request is already one atomic batch, and refusing the only thing in flight would shed load the process is not short of. The ceiling exists to stop requests accumulating, not to reject a large one. Also bounds a group-commit batch by payload. maxGroupBatchRows caps rows, but a row is whatever the sender put in it: 50,000 bare log lines and 50,000 spans carrying kilobytes of attributes are the same count and differ by orders of magnitude in what the commit holds. Breaking: a deployment under sustained overload now receives retryable refusals where it previously received acceptance and, eventually, a killed process. ingest.max_in_flight_bytes defaults to 256 MiB; zero restores the old unbounded behaviour exactly.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Sixth item of #254, and the one that changes behaviour. Also carries the byte-weighted batch limit (fifth item).
Why this is the one that matters
Every other change in this series makes one commit cost less. None of them makes the process bounded.
Ingest concurrency is HTTP/2 streams times connections — net/http allows 250 streams per connection by default and nothing in this repo lowers it — and each handler holds its decoded batch and its proto until the commit is durably acknowledged. Nothing counted how much was in flight at once. A large enough burst was still an out-of-memory kill however cheap an individual batch became.
Change
Submitcharges a request against a byte ceiling on entry and releases it on return.That is the right seam: both transports funnel through it, and it already blocks until durable acknowledgement, so the ledger measures exactly what the process is holding rather than what arrived on the wire.
A refusal returns
RESOURCE_EXHAUSTEDover gRPC and the existing 503 over HTTP. Both are what the OTLP specification tells an exporter to back off and retry on, so a shed request is delayed, not lost.fanout_ingest_shed_totalmakes it visible before it becomes a support question.An empty ledger admits any single request however large. One request is already one atomic batch, and refusing the only thing in flight would shed load the process is not short of. The ceiling exists to stop requests accumulating, not to reject a large one.
Also: byte-weighted group batches
maxGroupBatchRowscaps rows, but a row is whatever the sender put in it. 50,000 bare log lines and 50,000 spans carrying kilobytes of attributes are the same count and differ by orders of magnitude in what the commit holds.batchBytescounts the JSON columns and free-form strings, which carry effectively all of the variable size.Breaking change — please read
A deployment under sustained overload now receives retryable refusals where it previously received acceptance and, eventually, a killed process.
ingest.max_in_flight_bytesdefaults to 256 MiB. Setting it to0restores the previous unbounded behaviour exactly.I want a second opinion on the default. 256 MiB is chosen to sit well above any plausible steady state while still being a small fraction of an 8 GiB host — but it is a judgement, not a measurement, and it is the number that decides when a healthy deployment starts shedding.
Tests
TestSubmitRefusesWorkBeyondTheInFlightBudget— charge, refuse, release, admit again, ledger returns to zero.TestSubmitBudgetOfZeroAdmitsEverything— the unconfigured path is unchanged.TestSubmitOverBudgetIsReportedToTheCaller— refusal reaches the caller asErrIngestOverBudget, not a hang.TestBatchBytesMeasuresThePayloadNotTheRowCount— equal row counts, wildly different payloads.TestGroupBatchBytesAdmitsALoneOversizedRequest— the lone-request exemption.All written first and verified failing.
just checkpasses, including the config-schema and generated-docs gates, which caught the new key being undocumented.